Authorization model
IMPLEMENTED in 0.4.0 (context-registry.v2). Workstation product concepts, not SEIF Protocol authority.
Principal classes
| Class | Who | How it authenticates | Can ever hold |
|---|---|---|---|
| Human | People: Viewer, Developer, Reviewer, Admin | Bearer credential resolved from an operator-configured reference (env:/keychain:) | Capabilities granted by the role |
| Automation | CI and release tooling | Registry-issued scw_ci_… credential, digest-only at rest | Build, regression, promotion/deploy within scope, trace ingestion — never approval, break-glass, access, policy or binding management |
| Application | Runtime consumers (a support backend, a mobile app) | Registry-issued scw_app_… credential, digest-only at rest | context.resolve, context.expand, context.report_consumption, context.report_outcome, runtime.inspect — nothing that changes releases |
| Runner | The Registry's own deployment runner | No credential (in-process) | trace.ingest, scoped to one deployment's Project and environment |
APPLICATION IDENTITY ≠ HUMAN IDENTITY. CONSUMER CAPABILITY ≠ RELEASE AUTHORITY. An application credential can never be configured to deploy: the class bound is checked when the identity is created and on every request.
Scope
Every principal belongs to one organization. Service identities are scoped to exactly one Project; application identities must also name the environments they may resolve in. Humans may optionally be scoped to Projects. Authorization checks, in order: the route's capability (router-level, before any handler work), then the Project and environment of the addressed object. Authorization precedes routing, so an out-of-scope caller cannot learn whether an environment has an active deployment. Cross-organization reads return 404 (the object does not exist for that tenant).
Lifecycle
POST /v1/service-identities creates an identity (no secret). POST …/credentials issues a credential: the bearer secret appears once in that response; the Registry stores its SHA-256 digest, a 4-character hint, creator, expiry and last use. At most two credentials are active per identity, so rotation is replace-in-one-step ({"replaces": "<credential id>"}) or overlap-then-revoke. …/revoke and …/disable take effect on the next request. Every step is audited. Credentials carry recognizable prefixes so the secret scanners in Builds, traces, provider responses and delivery audits refuse them.
Security invariants
- No route reachable by an application credential belongs to the access, development or delivery planes (tested over the route table).
- Approval (
environment.approve) and break-glass are human-only. A human Admin cannot inject traces (trace.ingestis automation/runner only). - Separation of duties (
requireDistinctApprover) refuses an approval by the principal who registered the candidate, re-checked at promotion; break-glass under that policy needs a second administrator. - Denied mutations by machine credentials are audited (
access.denied, bounded per principal). - Bearer secrets are never stored, logged, returned after issuance or written to traces.
<!-- BEGIN GENERATED: node scripts/authz-matrix.mjs -->
Capabilities by principal class and role
| Capability | Human | Automation | Application | Runner | Viewer | Developer | Reviewer | Admin |
|---|---|---|---|---|---|---|---|---|
context.resolve | ✓ | — | ✓ | — | — | ✓ | — | ✓ |
context.expand | ✓ | — | ✓ | — | — | ✓ | — | ✓ |
context.report_consumption | ✓ | — | ✓ | — | — | ✓ | — | ✓ |
context.report_outcome | ✓ | — | ✓ | — | — | ✓ | — | ✓ |
tools.execute | ✓ | — | ✓ | — | — | ✓ | — | ✓ |
tools.approve | ✓ | — | — | — | — | — | ✓ | ✓ |
runtime.inspect | ✓ | ✓ | ✓ | — | — | ✓ | ✓ | ✓ |
build.view | ✓ | ✓ | — | — | ✓ | ✓ | ✓ | ✓ |
build.register | ✓ | ✓ | — | — | — | ✓ | — | ✓ |
build.tag | ✓ | ✓ | — | — | — | ✓ | — | ✓ |
regression.run | ✓ | ✓ | — | — | — | ✓ | ✓ | ✓ |
environment.view | ✓ | ✓ | — | — | ✓ | ✓ | ✓ | ✓ |
environment.promote | ✓ | ✓ | — | — | — | ✓ | ✓ | ✓ |
environment.approve | ✓ | — | — | — | — | — | ✓ | ✓ |
environment.deploy | ✓ | ✓ | — | — | — | ✓ | ✓ | ✓ |
environment.rollback | ✓ | ✓ | — | — | — | ✓ | ✓ | ✓ |
environment.emergency_rollback | ✓ | — | — | — | — | — | — | ✓ |
environment.configure | ✓ | — | — | — | — | — | — | ✓ |
binding.view | ✓ | ✓ | — | — | ✓ | ✓ | ✓ | ✓ |
binding.manage | ✓ | — | — | — | — | — | — | ✓ |
trace.view | ✓ | ✓ | — | — | ✓ | ✓ | ✓ | ✓ |
trace.content | ✓ | ✓ | — | — | — | ✓ | ✓ | ✓ |
trace.reproduce | ✓ | ✓ | — | — | — | ✓ | ✓ | ✓ |
trace.ingest | — | ✓ | — | ✓ | — | — | — | — |
reliability.events | ✓ | ✓ | — | — | ✓ | ✓ | ✓ | ✓ |
access.view | ✓ | — | — | — | ✓ | ✓ | ✓ | ✓ |
member.manage | ✓ | — | — | — | — | — | — | ✓ |
service.manage | ✓ | — | — | — | — | — | — | ✓ |
audit.view | ✓ | — | — | — | ✓ | ✓ | ✓ | ✓ |
Service identity defaults
- application default:
context.resolve,context.expand,context.report_consumption,context.report_outcome - automation default:
build.view,build.register,regression.run,environment.view,binding.view
Endpoint matrix
| Method | Path | Capability | Classes that can ever hold it | Plane | Note |
|---|---|---|---|---|---|
| POST | /v1/projects/:project/environments/:environment/context/tools/execute | tools.execute | human, application | operations | |
| POST | /v1/projects/:project/environments/:environment/context/tools/approve | tools.approve | human | operations | Human only; exact call binding, five-minute expiry |
| GET | /v1/reliability | environment.view | human, automation | operations | |
| GET | /v1/reliability/impact | environment.view | human, automation | operations | Also requires build.view and trace.view; content diagnostics require trace.content |
| POST | /v1/reliability/impact-policy | environment.configure | human | operations | |
| POST | /v1/traces/:id/investigation-measurements | trace.view | human, automation | operations | Human only; explicit environment consent; elapsed time is not labor |
| GET | /v1/reliability/events | reliability.events | human, automation | operations | Also requires environment.view and trace.view; durable cursor feed without content |
| GET | /v1/reliability/history | environment.view | human, automation | operations | |
| POST | /v1/reliability/monitor | environment.configure | human | operations | |
| POST | /v1/reliability/checkpoint | regression.run | human, automation | operations | |
| POST | /v1/reliability/alerts/:id/acknowledge | regression.run | human, automation | operations | |
| GET | /v1/health | — | any authenticated principal | system | any authenticated principal; metrics for humans only |
| GET | /v1/capabilities | — | any authenticated principal | system | |
| GET | /v1/me | — | any authenticated principal | system | |
| GET | /v1/members | access.view | human | access | |
| POST | /v1/members | member.manage | human | access | |
| GET | /v1/service-identities | access.view | human | access | |
| POST | /v1/service-identities | service.manage | human | access | |
| GET | /v1/service-identities/:id | access.view | human | access | |
| POST | /v1/service-identities/:id/credentials | service.manage | human | access | |
| POST | /v1/service-identities/:id/credentials/:credential/revoke | service.manage | human | access | |
| POST | /v1/service-identities/:id/disable | service.manage | human | access | |
| GET | /v1/projects | build.view | human, automation | delivery | |
| POST | /v1/builds | build.register | human, automation | delivery | |
| GET | /v1/builds | build.view | human, automation | delivery | |
| GET | /v1/builds/:id | build.view | human, automation | delivery | |
| GET | /v1/builds/:id/artifact | build.view | human, automation | delivery | |
| GET | /v1/builds/:id/lineage | build.view | human, automation | delivery | |
| POST | /v1/builds/:id/tags | build.tag | human, automation | delivery | |
| POST | /v1/compare | build.view | human, automation | development | |
| POST | /v1/regressions | regression.run | human, automation | development | |
| GET | /v1/environments | environment.view | human, automation | delivery | |
| POST | /v1/environments | environment.configure | human | delivery | |
| POST | /v1/approvals | environment.approve | human | delivery | |
| POST | /v1/promotions | environment.promote or environment.rollback | human, automation | delivery | rollback=true requires environment.rollback |
| POST | /v1/emergency-rollbacks | environment.emergency_rollback | human | delivery | |
| POST | /v1/emergency-rollbacks/:id/confirm | environment.emergency_rollback | human | delivery | |
| GET | /v1/emergency-candidates | environment.view | human, automation | delivery | |
| GET | /v1/bindings | binding.view | human, automation | delivery | |
| GET | /v1/bindings/:project/:environment | binding.view | human, automation | delivery | |
| GET | /v1/bindings/:project/:environment/revisions | binding.view | human, automation | delivery | |
| POST | /v1/bindings | binding.manage | human | delivery | |
| POST | /v1/bindings/validate | binding.view | human, automation | delivery | |
| POST | /v1/deployments | environment.deploy | human, automation | delivery | |
| POST | /v1/deployments/:id/stop | environment.deploy | human, automation | delivery | |
| POST | /v1/deployments/:id/collect | trace.view | human, automation | operations | |
| POST | /v1/deployments/:id/:operation | context.resolve or context.expand or context.report_consumption or context.report_outcome or tools.execute or tools.approve | human, application | operations | operation is resolve, expand, consumption or outcome; each requires its own context.* capability |
| GET | /v1/deployments/:id/runtime/* | runtime.inspect or trace.view | human, automation, application | operations | health/build: runtime.inspect; traces/:id: trace.view |
| POST | /v1/deployments/:id/runtime/* | context.resolve or context.expand or context.report_consumption or context.report_outcome or tools.execute or tools.approve | human, application | operations | |
| GET | /v1/projects/:project/environments/:environment | environment.view or runtime.inspect | human, automation, application | operations | stable environment route status |
| POST | /v1/projects/:project/environments/:environment/context/:operation | context.resolve or context.expand or context.report_consumption or context.report_outcome or tools.execute or tools.approve | human, application | operations | stable application endpoint; routes only to the active HEALTHY/DEGRADED deployment |
| GET | /v1/projects/:project/environments/:environment/runtime/* | runtime.inspect | human, automation, application | operations | |
| POST | /v1/projects/:project/environments/:environment/runtime/* | context.resolve or context.expand or context.report_consumption or context.report_outcome or tools.execute or tools.approve | human, application | operations | |
| GET | /v1/promotions | environment.view | human, automation | delivery | |
| GET | /v1/deployments | environment.view | human, automation | delivery | |
| GET | /v1/regressions | build.view | human, automation | development | |
| GET | /v1/approvals | environment.view | human, automation | delivery | |
| GET | /v1/tags | build.view | human, automation | delivery | |
| GET | /v1/emergency-rollbacks | environment.view | human, automation | delivery | |
| GET | /v1/promotions/:id | environment.view | human, automation | delivery | |
| GET | /v1/deployments/:id | environment.view | human, automation | delivery | |
| GET | /v1/regressions/:id | build.view | human, automation | development | |
| GET | /v1/approvals/:id | environment.view | human, automation | delivery | |
| GET | /v1/tags/:id | build.view | human, automation | delivery | |
| GET | /v1/emergency-rollbacks/:id | environment.view | human, automation | delivery | |
| GET | /v1/audit | audit.view | human | access | |
| POST | /v1/traces | trace.ingest | automation, runner | operations | |
| GET | /v1/traces | trace.view | human, automation | operations | |
| GET | /v1/traces/:id | trace.view | human, automation | operations | |
| GET | /v1/traces/:id/investigation | trace.view | human, automation | operations | |
| POST | /v1/traces/:id/material | trace.content | human, automation | operations | Also requires trace.view and build.view |
| POST | /v1/traces/:id/test | trace.content | human, automation | operations | Also requires regression.run, trace.view and build.view; returns a draft only |
| POST | /v1/traces/:id/compare | trace.content | human, automation | operations | |
| POST | /v1/traces/:id/reproduce | trace.reproduce | human, automation | operations | |
| GET | /v1/analytics | trace.view | human, automation | operations |
<!-- END GENERATED -->