This page records how IAM policies work today and what the policy builder,
simulator and analyzer layer on top. The evaluator itself is unchanged.
What exists
- A policy is a JSON document of statements:
Effect (Allow or Deny),
Action (ability strings or *), Resource (identifiers or *).
Policies live in iam_policies; attachments link a policy to a user or
token principal in iam_policy_attachments.
- Abilities are a flat list on every user and token:
read, read:sensitive,
write, write:sensitive, deploy, root. root implies all of them.
- Resources are
app:NAME, database:NAME, environment:ID and
environment-kind:KIND. A trailing * is a prefix match. An app or
database also carries the environment resources of the environment it is
tagged with.
- Evaluation (
authorizeResource in internal/api/iam.go): an explicit Deny
in any attached policy always wins; otherwise the principal’s flat
abilities decide; otherwise an explicit Allow can grant the ability on that
resource. A malformed stored document is inert. A principal with no
policies behaves exactly like its flat abilities.
- Route gates that name a resource (
requireAbilityForResource) call the
evaluator. Routes gated by requireAbility consult flat abilities only.
- Every route above
read is audit logged by the shared gate, which covers
policy create, update, delete, attach and detach.
- Statements carry no conditions today. Environment kind is the one
condition-like check, and it is expressed as a resource.
- A catalog of abilities (group, plain description, risk) and a resource
picker with live match counts, both read only.
- A simulator that runs the real
authorizeResource path (including
environment visibility) and lists every statement that matched, plus a
grouped effective permissions view.
- An analyzer: static checks over stored documents, attachments and
principals, each with a severity and a one line fix.
- Preview before change (attach, detach, update) as a before and after
effective permission diff, a version history for policy documents, and a
guard that refuses a change that would leave no operational root
principal.
- Parameterized templates and field level validation errors.
Guarantees and limits
- No evaluation result changes.
internal/api/iam_evaluator_pin_test.go
pins the existing behavior; the simulator is tested to agree with
authorizeResource on every case.
- Source IP, time window and MFA conditions are not supported by the
evaluator, so the builder does not offer them. A
Condition key written by
hand is ignored by the evaluator and the analyzer flags it.
- There is no project or tag resource in the evaluator. The builder expands a
project into its environments when a policy is saved.
- Usage data is per token (
last_used_at), not per policy, so previews state
that and do not claim a policy was used.
Last modified on October 12, 2026