Feature Specification: Fine-Grained RBAC for withAuth Routes
Feature Branch: prebuild/collapse-rbac-kb-prs
Created: 2026-05-28
Status: Draft
Input: User description: "Split the coarse supervisor#invoke OpenFGA gate into explicit capabilities for basic user functions, including credentials and Slack/Webex access-check routes, without creating a new branch."
User Scenarios & Testing (mandatory)
User Story 1 - Preserve Access While Splitting Capabilities (Priority: P1)
As an existing signed-in CAIPE user, I want profile, settings, chat, feedback, file, credential, and integration routes to keep working after the RBAC split, so the migration does not interrupt normal usage.
Why this priority: The current supervisor#invoke gate covers many unrelated signed-in user functions. The first migration slice must preserve behavior while replacing the misleading shared capability with explicit names.
Independent Test: Can be tested by signing in as a user who currently satisfies supervisor#invoke and exercising representative routes from each new capability bucket.
Acceptance Scenarios:
- Given a user currently has the organization-level access required for
supervisor#invoke, When the new capability model is active, Then profile, settings, chat, feedback, credential, file, AI assist, Slack access-check, and Webex access-check routes remain reachable where their existing deeper resource checks allow access. - Given a route is protected only by the legacy
withAuthumbrella today, When the route is migrated, Then its audit record uses a capability that describes the actual route purpose rather thansupervisor#invoke. - Given a new BFF route is added later, When no explicit capability mapping exists, Then the route does not silently inherit
supervisor#invoke.
User Story 2 - Revoke Chat Without Breaking Basic Account Functions (Priority: P1)
As an administrator, I want chat access to be independently revocable from profile, settings, feedback, and directory access, so I can disable the assistant surface without locking a user out of account functions.
Why this priority: The main security issue with the current gate is that revoking one broad tuple removes unrelated functions at the same time.
Independent Test: Can be tested by revoking the chat capability for one user and confirming chat routes deny while self-profile and settings routes still allow.
Acceptance Scenarios:
- Given a user has access to self-service account routes but lacks the chat capability, When the user calls chat or A2A routes, Then the request is denied with a chat-specific capability code.
- Given the same user calls self-profile, settings, feedback, or NPS routes, When the route is not chat-related, Then the request is evaluated against the matching non-chat capability.
- Given an audit reviewer inspects denied chat events, When the event is recorded, Then the capability name clearly identifies chat access rather than generic supervisor invocation.
User Story 3 - Protect Credential APIs With Credential-Specific FGA (Priority: P1)
As a user or service retrieving stored credentials, I want every credential operation to require an appropriate credential or secret relationship, so credential APIs cannot be accessed only because the caller can use the assistant.
Why this priority: Credential APIs are sensitive and already have resource-level secret_ref concepts. The BFF-level gate must stop reporting them as supervisor#invoke.
Independent Test: Can be tested by calling credential list, retrieve, create, update, share, health, audit, connection, and exchange flows with callers that have only broad signed-in access versus callers with the correct credential relationships.
Acceptance Scenarios:
- Given a caller has basic CAIPE access but no credential-vault capability, When the caller reaches a credential user API, Then the route denies before exposing credential metadata or payloads.
- Given a caller has credential-vault access but lacks access to a specific
secret_ref, When the caller tries to retrieve or use that secret, Then the per-secret check denies the request. - Given a caller has the required
secret_refrelationship, When the caller performs the matching read, use, share, manage, or delete operation, Then the operation is allowed and audited with credential-specific capability context.
User Story 4 - Prevent Slack/Webex Access-Check Oracles (Priority: P2)
As an administrator or integration service, I want Slack and Webex access-check routes to require visibility on the channel or space being inspected, so callers cannot probe relationships for messaging resources they should not see.
Why this priority: The access-check helpers already evaluate channel/space grants and user grants, but the route itself should first verify that the caller may inspect the channel or space.
Independent Test: Can be tested by calling each Slack/Webex access-check route as a caller with and without read access to the target channel or space.
Acceptance Scenarios:
- Given a caller lacks read access to
slack_channel:<workspace>--<channel>, When the caller invokes the Slack access-check route for that channel, Then the route denies before returning relationship details. - Given a caller has read access to the Slack channel, When the caller invokes the access-check route, Then the route evaluates the requested channel grant and user grant as it does today.
- Given a caller lacks read access to
webex_space:<workspace>--<space>, When the caller invokes the Webex access-check route for that space, Then the route denies before returning relationship details. - Given a caller has read access to the Webex space, When the caller invokes the access-check route, Then the route evaluates the requested space grant and user grant as it does today.
User Story 5 - Improve Audit and Support Triage (Priority: P3)
As an operator investigating access failures, I want audit events to name the actual denied function, so I can tell whether a failure involved chat, profile, credentials, files, Slack, Webex, or another surface.
Why this priority: The current shared capability hides the route purpose and makes support, revocation validation, and policy debugging harder.
Independent Test: Can be tested by forcing one allow and one deny event in each new capability bucket and reviewing the resulting audit records.
Acceptance Scenarios:
- Given a denied credential retrieval, When the audit event is written, Then the capability identifies credential or
secret_refaccess rather than supervisor invocation. - Given a denied Slack or Webex access-check, When the audit event is written, Then the capability identifies the messaging resource inspection.
- Given a denied self-profile, settings, feedback, or AI assist request, When the audit event is written, Then the capability identifies that user-facing surface.
Edge Cases
- Existing users and service accounts must keep working after the new capabilities are introduced unless an existing resource-level check already denies them.
- Routes that already perform deeper resource checks must keep those checks; the new route capability is not a substitute for
secret_ref, conversation, channel, space, or target resource authorization. - Token-only callers must have a stable subject or equivalent service-account subject before OpenFGA can evaluate resource-specific checks.
- Unsupported resource types in Slack/Webex access-check requests must still return a denial without leaking whether the caller could inspect another resource.
- Bootstrap or break-glass admin behavior must remain explicit and auditable; it must not silently reintroduce a broad
supervisor#invokebypass. - Missing route mappings must fail loudly during development or produce an explicit warning during a transition period.
Requirements (mandatory)
Functional Requirements
- FR-001: The system MUST replace the legacy
supervisor#invokefallback forwithAuth-only routes with explicit route capabilities that match the route purpose. - FR-002: The system MUST preserve existing access automatically for users who currently satisfy the broad signed-in-user gate, unless a deeper resource-level check denies access.
- FR-003: The system MUST define separate capabilities for self-profile read/write, user-directory read, chat supervisor invocation, feedback submission, user-settings read/write, user-file read/write, AI assist invocation, credential-vault use, Slack channel access-check, and Webex space access-check.
- FR-004: The system MUST map chat and A2A routes to a chat-specific capability so chat access can be revoked without disabling self-profile, settings, feedback, or other basic account functions.
- FR-005: The system MUST map
/api/users/searchto a directory-read capability rather than any chat or supervisor capability. - FR-006: The system MUST map self-profile and account-link routes to self-service capabilities and continue to ensure the request operates only on the caller's own account.
- FR-007: The system MUST protect credential user APIs with a credential-vault route capability before route-specific logic runs.
- FR-008: The system MUST require per-credential OpenFGA relationships for operations on a specific
secret_ref, including use/retrieve, read, manage, share, and delete as applicable to each route. - FR-009: The system MUST not treat credential-vault access as sufficient to retrieve a specific credential payload without the matching
secret_refrelationship. - FR-010: The system MUST protect Slack access-check routes by requiring the caller to have read access to the target Slack channel before evaluating requested channel and user grants.
- FR-011: The system MUST protect Webex access-check routes by requiring the caller to have read access to the target Webex space before evaluating requested space and user grants.
- FR-012: The system MUST keep existing Slack/Webex access-check semantics after the route-level read gate passes: both the channel or space grant and the target subject grant must be evaluated.
- FR-013: The system MUST emit audit capability names that describe the evaluated surface, not the legacy
supervisor#invokeumbrella. - FR-014: The system MUST provide tests showing that each new capability has at least one allowed and one denied case.
- FR-015: The system MUST document where each new capability is granted, how existing access is preserved, and how administrators can revoke each capability.
- FR-016: The system MUST update the RBAC route coverage inventory so future routes cannot silently inherit the legacy supervisor gate.
Key Entities
- Route Capability: A named permission used by the BFF to describe the high-level surface a caller is trying to access, such as
chat_supervisor#invokeorcredential_vault#use. - Organization Capability: A capability that applies at the CAIPE organization level and can preserve current signed-in-user behavior by deriving from existing membership or admin relationships.
- Secret Reference: A resource representing a stored credential. Access to it must be evaluated separately from broad credential-vault access.
- Slack Channel Resource: A messaging resource that can be read, managed, or used through OpenFGA relationships. Access-check routes must require read access to the channel being inspected.
- Webex Space Resource: A messaging resource that can be read, managed, or used through OpenFGA relationships. Access-check routes must require read access to the space being inspected.
- Audit Event: A record of an authorization decision that must carry the route capability or resource relationship that was actually evaluated.
Success Criteria (mandatory)
Measurable Outcomes
- SC-001: 100% of routes currently falling through to
supervisor#invokeare mapped to an explicit capability or have a documented resource-specific authorization helper. - SC-002: Existing users with current signed-in access can complete representative profile, settings, chat, feedback, credential, Slack access-check, and Webex access-check flows after migration without manual tuple backfill.
- SC-003: Revoking the chat capability blocks chat and A2A routes while leaving self-profile, settings, and feedback routes accessible for the same user.
- SC-004: A caller with credential-vault access but without a required
secret_refrelationship cannot retrieve or use that credential. - SC-005: A caller without read access to a Slack channel or Webex space receives a denial from the corresponding access-check route before any requested relationship result is returned.
- SC-006: Authorization tests cover at least one allow and one deny case for every newly introduced route capability.
- SC-007: Audit records for migrated routes no longer report
supervisor#invokeexcept for any deliberately retained deprecated fallback during the transition period. - SC-008: RBAC documentation lists every new capability and the associated route families, grant source, and revocation behavior.