Wire the role Resolver and feed granted permissions into policy evaluation

Related to gitlab-org/gitlab#600048

What

Two related steps toward role-based authorization in GLAZ:

  1. Wire the Resolver (glaz-roles) — turn the set of roles a subject holds into an effective permission set.
  2. Feed that set into policy evaluation (glaz-policy) — so the Cedar decision is driven by the permissions the subject actually holds, not a hardcoded value.

Changes

glaz-rolesResolver

  • Role-id-keyed in-memory index: load / get, plus permissions(role_ids) (the deduplicated union of those roles' permissions) and has_permission(role_ids, perm).
  • Removed the dead access-level level constants (the old access-level-keyed design they belonged to is gone) and tidied the Resolver docs/test names for the flat role model.

glaz-policy — granted-driven decision

  • PolicyEngine::check gains granted_permissions: &[Permission]. user_permissions is built from it and is authoritative over any value the caller puts in context.
  • Previously user_permissions was hardcoded to the single requested action, which made the shared permit_role_granted policy a tautology (every request "held" exactly the permission it asked about). Now the grant is actually consulted.
  • The engine stays a pure Cedar evaluator — it does not know which roles a subject holds. Callers resolve granted_permissions (e.g. via Resolver::permissions()).

glaz-module

  • Decodes the merged CheckRequest contract and passes a documented placeholder granted_permissions (the requested action) for now — it does not yet resolve the subject's roles from the request's relationships.

Tests

cargo test --workspace — all passing. Notably:

  • A request whose action is not in granted_permissions is denied (proves the grant is consulted, no longer a tautology).
  • A granted_permissions set resolved from a role via Resolver::permissions() drives the decision (allow for a granted action, deny for one outside the role's permissions).

Notes / follow-ups

  • Built on the merged AR ↔️ GLAZ contract (!28 (merged)). Rebased onto main; glaz-module decodes the Check/CheckRequest contract (Principal subject, object, relationships, context). The check signature also reconciles with the explicit schema/policy-initialization work on main (it carries both granted_permissions and the NotInitialized behavior).
  • glaz-module is a placeholder, not end-to-end yet. With the placeholder granted_permissions, the module-level check effectively always allows; the value here is the Resolver + glaz-policy plumbing.
  • Next (#600048): compute effective permissions from the request's relationships — resolve role grants → union via the Resolver → evaluate — plus an action-validity gate and the org-owner bypass. The schema-from-roles question is resolved there (Rust validity gate + schema-less Cedar), not here.

🤖 Generated with Claude Code

Edited by Diane Russel

Merge request reports

Loading