Skip to content

core: fail a check whose value has an object key that isn't a string #108

Open

Description

@jbpros

Low priority. It only affects policies written in Rego, because JSON and YAML can't express these keys.

Rego lets an object key be any value. When ergo writes such a value into an expression, two cases come out badly. Seen on main (19c9395), with OPA 1.19.0:

A key that is itself an object or a list is written in a different order under Wasm, because sorting inside a key would need the JSON writer to call itself, which Rego doesn't allow:

"value": {{"b": 1, "a": 2}: "x"}

opa eval:                x == {"{\"a\":2,\"b\":1}": "x"}
opa test --target wasm:  x == {"{\"b\":1,\"a\":2}": "x"}

Two keys that are written the same way both appear, where json.marshal silently keeps one:

"value": {10: "a", "10": "b"}

json.marshal:  {"10": "b"}
ergo:          {"10": "a", "10": "b"}

Number, boolean and null keys are fine otherwise: they're written as JSON strings, the same in every runtime.

Proposal

Treat an object key that isn't a string, anywhere in a value written in the policy, as a badly written value: the check fails with cause absent, and the expression says so, for example <invalid key>. That's easy to state in a spec and matches failing closed elsewhere.

Open question

Should number keys stay allowed? They work in every runtime today, and a Rego policy might use them on purpose. Failing only on composite keys and on keys that collide once written would close both gaps with less impact.

Activity

  1. added
    enhancementNew feature or request
    coreRelates to the ergo library or format themselves.
    impacts-ergo-reportsImpacts ergo report schema. Careful design attention needed.
    on Oct 3, 2026
  2. jbpros commented on Oct 7, 2026

    @jbpros
    ContributorAuthor

    #155 fixed the failing-closed half of this. A set, or an object key that isn't a string, anywhere in a check now makes it written wrong. Both examples above now fail $well_formed with holds a key that isn't a string, and the check fails as ill_formed:

    "value": {{"b": 1, "a": 2}: "x"}   →  c: passed false, cause ill_formed
    "value": {10: "a", "10": "b"}      →  c: passed false, cause ill_formed
    

    The expression part is still open. On main (b4eb645), the first one still renders as x == {"{\"a\":2,\"b\":1}": "x"} with opa eval, and a test pinning that string fails under opa test --target wasm. So the report's bytes can still differ between runtimes. Writing <invalid key> in the expression, as proposed above, would close it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    coreRelates to the ergo library or format themselves.enhancementNew feature or requestimpacts-ergo-reportsImpacts ergo report schema. Careful design attention needed.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions