Skip to content

Keep resolve() returning the target logical ID for custom Rego rules while built-in policies see the __ref marker - #429

Merged
satyakigh merged 1 commit into
mainfrom
ref-backwards-compat
Sep 22, 2026
Merged

satyakigh merged 1 commit into
mainfrom
ref-backwards-compat

Conversation

@satyakigh

@satyakigh satyakigh commented Sep 22, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

#425 changed how the Rego resolve() builtin renders a Ref/Fn::GetAtt to a template resource: the target's
logical ID string became the {"__ref": target} marker object. The built-in policies needed that so a format or
enum check never judges a logical ID as if it were the literal (six false positives fixed there). It was also a
breaking change for every custom Rego rule written against the documented contract "references become target IDs",
and it broke silently: input.resources[resolve(...)], resolve(...) == "LogicalId", and string operations on the
result all stop matching, so the rule stops firing rather than erroring.

This change keeps both contracts by selecting the rendering per evaluating package:

How:

  • rego-engine/src/eval_context.rs: ReferenceRendering { Marker, TargetId } in a thread-local Cell, with an
    RAII ReferenceRenderingScope that restores the previous rendering on drop, and current_reference_rendering().
  • rego-engine/src/engine.rs: PolicyPackageKind { BuiltIn, Custom } replaces the loose source_label/origin
    parameters of eval_package_into and installs the scope around each package's eval_rule query. This is safe
    because Regorus clears rule_values and builtins_cache between eval_rule calls, so a value rendered for one
    package never reaches the next.
  • rego-engine/src/builtins.rs: resolved_to_rego/resolved_all_to_rego take the rendering. This covers exactly
    the two shapes Fix false positives where unresolved or referenced values were treated as missing or literal #425 changed - a reference that is the resolved value, and a reference inside a resolved list
    (resolve and resolve_all). Map values were already rendered as markers before Fix false positives where unresolved or referenced values were treated as missing or literal #425 and stay that way. A bare
    reference still contributes no value to resolve_all.
  • follow_ref, authored_form, flatten_list, has_property are unchanged; the input document is unchanged.
  • Docs: CUSTOM_RULES.md restores the resolve/resolve_all contract for custom-rule authors (with
    not input.resources[value], follow_ref, or authored_form as the ways to exclude or read a reference);
    the rego-engine README gains a "Reference rendering" section explaining the two audiences.

Consumers that already migrated to follow_ref need no change: resolve and follow_ref return the same logical
ID for a Ref or GetAtt target, and follow_ref stays undefined for literals.


By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license.

…while built-in policies see the __ref marker
@satyakigh satyakigh changed the title Keep resolve() returning the target logical ID for custom Rego rules … Keep resolve() returning the target logical ID for custom Rego rules while built-in policies see the __ref marker Sep 22, 2026
@satyakigh
satyakigh merged commit ab4a20b into main Sep 22, 2026
19 checks passed
@satyakigh
satyakigh deleted the ref-backwards-compat branch September 22, 2026 16:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant