Context
An access check that runs in only one place can be bypassed, and a list that filters in code can leak rows. The owner’s enforcement answers A5, A6, A8 and A9 (mem L622–626, 2026-10-20) fix where the check runs and how lists are filtered.Decision
- Pipeline gate (A5). The IAM gate runs on every action (ADR 0138). Lists are filtered by compiling grants to an ltree SQL predicate, combined with row-level security. The interface receives a cosmetic permissions snapshot. No hand-rolled checks.
- Embedded policy decision point (A6).
@stackra/iamcontains an embedded decision point that evaluates a versioned policy snapshot pushed by events. A level L3 or above action can force a fresh read. The IAM service owns the writes and theexplaincall. - Service-to-service (A8). Each service has its own ZITADEL service account. A call carries the service token and
onBehalfOf. Both grants are checked. - Audit (A9). Every deny and every L3 or higher allow is audited. Routine allows are metrics only.
explainis itself a permission.
Consequences
- A list returned to a user contains only rows the user may see, enforced in the database as well as in code.
- A service call proves both the calling service and the user it acts for.
Enforcement
planned — a test checks that every list action carries the predicate, and the service-call test checks both grants.Supersedes and sources
Supersedes: none. Sources: owner IAM enforcement answers A5, A6, A8, A9 (stackra-decisions-2026-10-19.md L622–626, 2026-10-20).