- Fix namespace conflicts (Subgraph → PoESubgraph) - Add hash sanitization for Windows filesystem (colon → underscore) - Update all test mocks to use It.IsAny<>() - Add direct orchestrator unit tests - All 8 PoE tests now passing (100% success rate) - Complete SPRINT_3500_0001_0001 documentation Fixes compilation errors and Windows filesystem compatibility issues. Tests: 8/8 passing Files: 8 modified, 1 new test, 1 completion report 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
14 KiB
Console Admin RBAC Architecture
1. Purpose
- Provide a unified, Authority-backed admin surface for tenants, users, roles, clients, tokens, and audit.
- Expose the same capabilities to UI and CLI while preserving offline-first operation.
- Normalize scope and role bundles, including missing Scanner roles, for consistent RBAC across modules.
2. Scope
- Authority admin APIs and data model used by the Console Admin workspace.
- Role and scope taxonomy, including scanner roles.
- Audit, fresh-auth, and offline export/import workflow.
- UI integration contract (routes, scopes, and API paths).
Non-goals:
- Replacing external IdP user lifecycle workflows (SAML/OIDC remains primary for enterprise identity).
- Exposing privileged mTLS-only admin endpoints directly to the browser.
3. Core Architecture
3.1 Authority admin tiers
- /admin: mTLS + authority.admin scope for automation and ops tooling.
- /console/admin: DPoP + UI scopes for browser and CLI admin flows.
Both tiers share the same data model and audit log but enforce different auth policies.
3.2 Entities and ownership
Authority remains the source of truth for:
- Tenant: id, display name, status, isolation mode, default roles.
- Installation: installation id, tenant binding, bootstrap metadata.
- Role: id, display name, scopes[], audiences[], flags (interactive-only, requires fresh-auth).
- User: subject, status, display name, tenant assignments, roles per tenant.
- Client: client id, grant types, auth method, allowed scopes, audiences, tenant hint.
- Token record: access/refresh/device metadata, revocation status.
- Audit events: immutable admin and auth events.
3.3 Fresh-auth
High-risk operations require a fresh-auth window:
- Tenant suspend/resume
- Token revocation (bulk or admin)
- Role bundle edits
- Client secret or key rotation
- Branding apply
Authority uses auth_time + fresh-auth TTL to gate these operations.
4. Scope and Role Taxonomy
4.1 Console admin scopes
New admin scopes (Authority-managed):
authority:tenants.read,authority:tenants.writeauthority:users.read,authority:users.writeauthority:roles.read,authority:roles.writeauthority:clients.read,authority:clients.writeauthority:tokens.read,authority:tokens.revokeauthority:audit.readauthority:branding.read,authority:branding.writeui.admin(console access for admin views)
4.2 Scanner scope and role bundles (missing today)
Define scanner scopes and role bundles to align UI, CLI, and API:
- Scopes:
scanner:read,scanner:scan,scanner:export,scanner:write - Role bundles:
role/scanner-viewer->scanner:readrole/scanner-operator->scanner:read,scanner:scan,scanner:exportrole/scanner-admin->scanner:read,scanner:scan,scanner:export,scanner:write
Compatibility:
- Gateway maps
scanner:read|scan|export|writeto any legacy scanner scope strings until full cutover.
4.3 Module role bundle catalog
Role bundles are grouped by module and map to existing Authority scopes unless noted.
| Module | Role bundle | Scopes |
|---|---|---|
| Console | role/console-viewer |
ui.read |
| Console | role/console-admin |
ui.read, ui.admin, authority:tenants.read, authority:users.read, authority:roles.read, authority:clients.read, authority:tokens.read, authority:audit.read, authority:branding.read |
| Console | role/console-superadmin |
ui.read, ui.admin, authority:tenants.*, authority:users.*, authority:roles.*, authority:clients.*, authority:tokens.*, authority:audit.read, authority:branding.* |
| Scanner | role/scanner-viewer |
scanner:read, findings:read, aoc:verify |
| Scanner | role/scanner-operator |
scanner:read, scanner:scan, scanner:export, findings:read, aoc:verify |
| Scanner | role/scanner-admin |
scanner:read, scanner:scan, scanner:export, scanner:write, findings:read, aoc:verify |
| Policy | role/policy-author |
policy:read, policy:author, policy:simulate, findings:read |
| Policy | role/policy-reviewer |
policy:read, policy:review, policy:simulate, findings:read |
| Policy | role/policy-approver |
policy:read, policy:review, policy:approve, policy:simulate, findings:read |
| Policy | role/policy-operator |
policy:read, policy:operate, policy:run, policy:activate, policy:publish, policy:promote, policy:simulate, findings:read |
| Policy | role/policy-auditor |
policy:read, policy:audit, findings:read |
| Concelier | role/concelier-reader |
advisory:read, aoc:verify |
| Concelier | role/concelier-ingest |
advisory:ingest, advisory:read, aoc:verify |
| Concelier | role/concelier-operator |
concelier.jobs.trigger, advisory:read, aoc:verify |
| Concelier | role/concelier-admin |
concelier.jobs.trigger, concelier.merge, advisory:read, aoc:verify |
| Excititor | role/excititor-reader |
vex:read, aoc:verify |
| Excititor | role/excititor-ingest |
vex:ingest, vex:read |
| Notify | role/notify-viewer |
notify.viewer |
| Notify | role/notify-operator |
notify.viewer, notify.operator |
| Notify | role/notify-admin |
notify.viewer, notify.operator, notify.admin |
| Scheduler | role/scheduler-viewer |
scheduler:read (new) |
| Scheduler | role/scheduler-operator |
scheduler:read, scheduler:operate (new) |
| Scheduler | role/scheduler-admin |
scheduler:read, scheduler:operate, scheduler:admin (new) |
| Orchestrator | role/orch-viewer |
orch:read, findings:read |
| Orchestrator | role/orch-operator |
orch:read, orch:operate, findings:read |
| Orchestrator | role/orch-admin |
orch:read, orch:operate, orch:quota, orch:backfill, findings:read |
| Graph | role/graph-viewer |
graph:read, graph:export |
| Graph | role/graph-operator |
graph:read, graph:export, graph:simulate |
| Graph | role/graph-admin |
graph:read, graph:export, graph:simulate, graph:write, graph:admin |
| Vuln Explorer | role/vuln-viewer |
vuln:view, findings:read |
| Vuln Explorer | role/vuln-investigator |
vuln:view, vuln:investigate, findings:read |
| Vuln Explorer | role/vuln-operator |
vuln:view, vuln:investigate, vuln:operate, findings:read |
| Vuln Explorer | role/vuln-auditor |
vuln:view, vuln:audit, findings:read |
| Export Center | role/export-viewer |
export.viewer |
| Export Center | role/export-operator |
export.viewer, export.operator |
| Export Center | role/export-admin |
export.viewer, export.operator, export.admin |
| Advisory AI | role/advisory-ai-viewer |
advisory-ai:view, aoc:verify |
| Advisory AI | role/advisory-ai-operator |
advisory-ai:view, advisory-ai:operate, aoc:verify |
| Advisory AI | role/advisory-ai-admin |
advisory-ai:view, advisory-ai:operate, advisory-ai:admin, aoc:verify |
| Signals | role/signals-viewer |
signals:read, aoc:verify |
| Signals | role/signals-uploader |
signals:read, signals:write, aoc:verify |
| Signals | role/signals-admin |
signals:read, signals:write, signals:admin, aoc:verify |
| Evidence Locker | role/evidence-reader |
evidence:read |
| Evidence Locker | role/evidence-creator |
evidence:read, evidence:create |
| Evidence Locker | role/evidence-legal |
evidence:read, evidence:hold |
| Observability | role/observability-viewer |
obs:read, timeline:read, attest:read |
| Observability | role/observability-investigator |
obs:read, timeline:read, timeline:write, evidence:read, evidence:create, attest:read |
| Observability | role/observability-incident-commander |
obs:read, obs:incident, timeline:read, timeline:write, evidence:read, evidence:create, attest:read |
| Issuer Directory | role/issuer-directory-viewer |
issuer-directory:read |
| Issuer Directory | role/issuer-directory-operator |
issuer-directory:read, issuer-directory:write |
| Issuer Directory | role/issuer-directory-admin |
issuer-directory:read, issuer-directory:write, issuer-directory:admin |
| Task Packs | role/packs-viewer |
packs.read |
| Task Packs | role/packs-operator |
packs.read, packs.run |
| Task Packs | role/packs-publisher |
packs.read, packs.write |
| Task Packs | role/packs-approver |
packs.read, packs.approve |
| Airgap | role/airgap-viewer |
airgap:status:read |
| Airgap | role/airgap-operator |
airgap:status:read, airgap:import |
| Airgap | role/airgap-admin |
airgap:status:read, airgap:import, airgap:seal |
| Exceptions | role/exceptions-viewer |
exceptions:read |
| Exceptions | role/exceptions-approver |
exceptions:read, exceptions:approve |
| Exceptions | role/exceptions-editor |
exceptions:read, exceptions:write |
| Attestor | role/attestor-viewer |
attest:read, aoc:verify |
| Attestor | role/attestor-operator |
attest:read, attest:create, aoc:verify |
| Attestor | role/attestor-admin |
attest:read, attest:create, attest:admin, aoc:verify |
| Signer | role/signer-viewer |
signer:read, aoc:verify |
| Signer | role/signer-operator |
signer:read, signer:sign, aoc:verify |
| Signer | role/signer-admin |
signer:read, signer:sign, signer:rotate, signer:admin, aoc:verify |
| SBOM | role/sbom-viewer |
sbom:read, aoc:verify |
| SBOM | role/sbom-creator |
sbom:read, sbom:write, aoc:verify |
| SBOM | role/sbom-attestor |
sbom:read, sbom:write, sbom:attest, attest:create, aoc:verify |
| Release | role/release-viewer |
release:read, policy:read, findings:read |
| Release | role/release-manager |
release:read, release:write, policy:read, findings:read |
| Release | role/release-publisher |
release:read, release:write, release:publish, policy:read, findings:read |
| Release | role/release-admin |
release:read, release:write, release:publish, release:bypass, policy:read, findings:read |
| Zastava | role/zastava-viewer |
zastava:read |
| Zastava | role/zastava-operator |
zastava:read, zastava:trigger |
| Zastava | role/zastava-admin |
zastava:read, zastava:trigger, zastava:admin |
Missing scopes (must be added to Authority):
Scanner scopes are not yet defined in Authority. They are proposed as scanner:read, scanner:scan, scanner:export, and scanner:write and must be added to Authority constants, discovery metadata, and gateway enforcement.
Scheduler scopes are not yet defined in Authority. They are proposed as scheduler:read, scheduler:operate, and scheduler:admin and must be added to Authority constants, discovery metadata, and gateway enforcement.
Authority admin scopes (partial): authority:tenants.read exists. Must add: authority:tenants.write, authority:users.read, authority:users.write, authority:roles.read, authority:roles.write, authority:clients.read, authority:clients.write, authority:tokens.read, authority:tokens.revoke, authority:branding.read, authority:branding.write.
UI admin scope: ui.admin must be added to Authority constants.
Attestor scopes: attest:read exists. Must add: attest:create, attest:admin.
Signer scopes (all new): signer:read, signer:sign, signer:rotate, signer:admin.
SBOM scopes (all new): sbom:read, sbom:write, sbom:attest.
Release scopes (all new): release:read, release:write, release:publish, release:bypass.
Zastava scopes (all new): zastava:read, zastava:trigger, zastava:admin.
Graph admin scope: graph:admin must be added to Authority constants.
Exception write scope: exceptions:write must be added to Authority constants (exceptions:read and exceptions:approve exist).
5. Console Admin API Surface
5.1 Tenants
GET /console/admin/tenantsPOST /console/admin/tenantsPATCH /console/admin/tenants/{tenantId}POST /console/admin/tenants/{tenantId}/suspendPOST /console/admin/tenants/{tenantId}/resume
Scopes: authority:tenants.read|write
5.2 Users
GET /console/admin/users?tenantId=...POST /console/admin/users(local users only)PATCH /console/admin/users/{userId}POST /console/admin/users/{userId}/disablePOST /console/admin/users/{userId}/enable
Scopes: authority:users.read|write
5.3 Roles and scopes
GET /console/admin/rolesPOST /console/admin/rolesPATCH /console/admin/roles/{roleId}POST /console/admin/roles/{roleId}/preview-impact
Scopes: authority:roles.read|write
5.4 Clients
GET /console/admin/clientsPOST /console/admin/clientsPATCH /console/admin/clients/{clientId}POST /console/admin/clients/{clientId}/rotate
Scopes: authority:clients.read|write
5.5 Tokens and audit
GET /console/admin/tokens?tenantId=...POST /console/admin/tokens/revokeGET /console/admin/audit?tenantId=...
Scopes: authority:tokens.read|revoke, authority:audit.read
6. Audit and Observability
- Every admin mutation emits
authority.admin.*events with tenant, actor, and trace id. - Audit export provides deterministic ordering and ISO-8601 timestamps.
- Token revocations emit revocation bundle update markers for downstream caches.
7. Offline-first Administration
- Admin changes can be exported as signed bundles for air-gapped import.
- The Console produces a change manifest; Authority applies it via
/admin/bundles/apply(mTLS). - UI labels changes as pending when Authority is offline.
8. UI Integration Contract
- Admin workspace routes live under
/console/admin/*. - Admin UI uses
/console/adminAPIs with DPoP; no mTLS endpoints are called by the browser. ui.adminplus specificauthority:*scopes are required to render and mutate data.
9. References
docs/modules/authority/architecture.mddocs/modules/ui/architecture.mddocs/ui/admin.mddocs/contracts/web-gateway-tenant-rbac.md