Skip to content

OPA policies check credentials.system_scope but the Rust field is system — system-reader rule is dead #1045

Description

@gtema

Found while investigating tempest-identity-compatibility 403s (#997/#998), not the direct cause of any currently-tracked failure — a separate correctness bug surfaced as a byproduct.

Credentials (crates/core/src/policy.rs) serializes its system-scope field as system (pub system: Option<String>, no #[serde(rename)]), populated as "all" for system scope by Credentials::try_from. Several .rego policies instead check a field named system_scope, which is never present in the real OPA input — so their "reader role with system scope may read this" rule is silently dead (always evaluates to undefined/false), not just for these three, for every request that should qualify:

  • policy/auth/token/show.rego (lines ~40-41)
  • policy/auth/project/list.rego
  • policy/assignment/list.rego
  • policy/service/show.rego
  • policy/service/list.rego
  • policy/endpoint/show.rego
  • policy/endpoint/list.rego

(policy/auth/token/revoke.rego has the same wrong field name but in an already-commented-out block, so it's inert either way.)

Each of these files' own _test.rego mocks the same wrong system_scope key, so the existing unit tests pass while asserting a self-consistently wrong contract — they don't catch this because they never exercise the real Rust→JSON field name.

Impact: a caller with role:reader and system scope (GET a token, list domains-a-project-belongs-to/projects, list role assignments, show/list services, show/list endpoints) is denied even though the policy's own doc comments say they should be allowed. Fails closed (denies access that should be granted), not a privilege escalation, but a real functional/compatibility gap — likely part of why some tempest identity tests using system-scoped reader credentials fail.

Fix: rename system_scopesystem in each allow rule listed above and in the corresponding _test.rego mocks (matching the working reference implementation already used correctly elsewhere, e.g. policy/resource/domain/show.rego's input.credentials.system == "all").

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions