ADR 0060 — Unified Audit RBAC: Role-Gated Dimensions vs Feature-Flag-Gated Dimensions
Status: Accepted (updated v2 — 2026-05-09 UTC)
Date: 2026-05-09 UTC
Deciders: software-architect, operator (Kristerpher)
Refs: customer-audit-unified/design.md §8, rbac-design.md, docs/architecture/rbac-v2/design.md (parallel), ADR-0020, ADR-0064, project_rbac_model.md
Context
The unified audit table has three dimensions. Access to each dimension varies by actor class. Two approaches govern who reads what:
- RBAC-gated: access to a dimension is determined by the caller's RBAC role.
- Feature-flag-gated: a flag gates each dimension.
The project_rbac_as_feature_dispatch.md philosophy directly applies here.
Decision
RBAC-gated dimensions. Feature flags gate UI surfaces; they do not gate which audit data a role can see. RBAC role grants determine dimension access.
v2 additions to this decision (operator + security feedback, 2026-05-09):
raptor-audit-compliance role (SOC-2, now in v1 scope)
The operator has confirmed SOC-2 as v1 scope. The raptor-audit-compliance role moves from "stubbed, implement when needed" (v1) to "implemented in RBAC V2 before Phase 3 reader cutover" (v2). A separate software-architect agent is designing RBAC V2 at docs/architecture/rbac-v2/. This ADR references that work; it does not design it.
Properties of raptor-audit-compliance:
- Read-only across all three dimensions, all customers.
- No customer notification: compliance auditor reads are logged at the pg_audit level but do not trigger the Path A or Path B notification pipeline. Auditor reads are logged in customer_audit_events with actor_type = 'system_actor' (auditor = internal process, not individual operator read) to prevent notification pipeline from firing.
- Time-bounded membership: auditor is provisioned into raxx-auditor-team group for the duration of the engagement (start date + end date). RBAC V2 supports time-bounded group memberships.
- Access provisioning requires superadmin action, which is itself logged as operator.rbac.grant.
This satisfies SOC-2 TSC CC6.1 (logical access controls) and enables a clean audit engagement path.
RBAC V2 dependency
SC-A8 (reader endpoint with RBAC + ticket gate) is explicitly gated on RBAC V2 landing (needs:RBAC-V2). The four RBAC roles defined in this ADR cannot be resolved at the application layer until RBAC V2 tables are live in production.
If RBAC V2 lands before Phase 3: the reader endpoint uses the concrete RBAC V2 role/permission resolution API. If Phase 3 is ready before RBAC V2: Phase 3 does not proceed. RBAC V2 is a hard prerequisite.
Updated role matrix
Five RBAC roles (four from v1, one expanded from "stub"):
| Role | Dimensions accessible | Notification path | RBAC V2 group | Notes |
|---|---|---|---|---|
antlers-audit-self |
Dim 1 + Dim 2 (own events only) | N/A | antlers-user (all authenticated users) |
|
raptor-audit-support |
Dim 1 + Dim 2 + Dim 3 (ticket required for Dim-3) | Path A or B per ticket state | raxx-support-team |
|
raptor-audit-admin |
All dimensions, all customers | Always Path B | raxx-platform-admins |
No ticket requirement; notification always fires |
raptor-audit-compliance |
All dimensions, all customers, read-only | None (auditor path) | raxx-auditor-team (new group in RBAC V2) |
SOC-2 auditor; time-bounded membership |
Consequences
Positive (from v1, unchanged)
- Granting a support agent Dim-3 access is a group membership change, not a code ship (RBAC-as-config).
- The compliance auditor role is now implemented (not stubbed). SOC-2 audit engagements can proceed without using the superadmin role, avoiding customer notification noise.
- Feature flags continue to gate UI surfaces. The API layer always enforces RBAC regardless of flag state.
- Separation of duties: flag changes (operator config) and RBAC changes (identity/access management) have distinct audit trails.
Positive (v2 additions)
- Auditor path is clean:
raptor-audit-compliancerole provides read access without triggering customer notifications. SOC-2 auditors can perform their work without creating inbox noise for every customer whose records they examine. - Time-bounded memberships allow audit engagements to be provisioned and deprovisioned without leaving stale credentials. The RBAC V2 group membership model (per
project_rbac_model.md) supports this.
Negative
- RBAC V2 is a hard dependency for Phase 3. Delay in RBAC V2 delays the reader cutover and all dependent sub-cards. There is no interim path.
raptor-audit-complianceadds a new actor type that the notification pipeline must explicitly exempt. Any future change to the notification pipeline must preserve this exemption or SOC-2 audits will generate customer notifications.raxx-auditor-teamis a new RBAC V2 group. The RBAC V2 architect must account for it in the group model.
Alternatives Considered
Feature-flag-gated dimensions (rejected, same reasoning as v1)
Flags are blunt instruments. Turning on Dim-3 for support opens it for all support agents simultaneously. RBAC allows per-group grants. Flags bypass the GDPR audit trail for access decisions.
Auditor uses raptor-audit-admin temporarily (no compliance role)
Simpler in the short term. Auditor uses the admin role during the SOC-2 audit period.
Rejected: superadmin reads trigger Path B security-incident notifications for every customer whose records the auditor examines. A SOC-2 audit typically covers all customers over the audit period — this would generate hundreds of security-incident notification emails. This is operationally unacceptable and would erode customer trust in the notification system.
Auditor gets a read-only DB credential (bypasses RBAC entirely)
Direct DB credential for the auditor.
Rejected: bypasses application-layer RBAC audit trail. Auditor access is not logged in customer_audit_events. Credential lifecycle (rotation, revocation at end of engagement) is a management burden. RBAC role + time-bounded membership is the correct access model.