TenantAtlas/specs/067-rbac-troubleshooting/spec.md
ahmido 3490fb9e2c feat: RBAC troubleshooting & tenant UI bugfix pack (spec 067) (#84)
Summary
Implements Spec 067 “RBAC Troubleshooting & Tenant UI Bugfix Pack v1” for the tenant admin plane (/admin) with strict RBAC UX semantics:

Non-member tenant scope ⇒ 404 (deny-as-not-found)
Member lacking capability ⇒ 403 server-side, while the UI stays visible-but-disabled with standardized tooltips
What changed
Tenant view header actions now use centralized UI enforcement (no “normal click → error page” for readonly members).
Archived tenants remain resolvable in tenant-scoped routes for entitled members; an “Archived” banner is shown.
Adds tenant-scoped diagnostics page (/admin/t/{tenant}/diagnostics) with safe repair actions (confirmation + authorization + audit log).
Adds/updates targeted Pest tests to lock the 404 vs 403 semantics and action UX.
Implementation notes
Livewire v4.0+ compliance: Uses Filament v5 + Livewire v4 conventions; widget Blade views render a single root element.
Provider registration: Laravel 11+ providers stay in providers.php (no changes required).
Global search: No global search behavior/resources changed in this PR.
Destructive actions:
Tenant archive/restore/force delete and diagnostics repairs execute via ->action(...) and include ->requiresConfirmation().
Server-side authorization is enforced (non-members 404, insufficient capability 403).
Assets: No new assets. No change to php artisan filament:assets expectations.
Tests
Ran:

vendor/bin/sail bin pint --dirty
vendor/bin/sail artisan test --compact (focused files for Spec 067)

Co-authored-by: Ahmed Darrazi <ahmeddarrazi@MacBookPro.fritz.box>
Reviewed-on: #84
2026-01-31 20:09:25 +00:00

131 lines
9.0 KiB
Markdown

# Feature Specification: RBAC Troubleshooting & Tenant UI Bugfix Pack v1
**Feature Branch**: `067-rbac-troubleshooting`
**Created**: 2026-01-31
**Status**: Draft
**Input**: RBAC troubleshooting + tenant admin UI bugfix pack focused on the tenant-plane admin experience (`/admin`).
## User Scenarios & Testing *(mandatory)*
### User Story 1 - Permission-safe tenant UI interactions (Priority: P1)
A tenant member with read-only permissions can browse tenant pages and menus without being sent to error pages for normal UI clicks.
**Why this priority**: Eliminates confusing UX and reduces support load; also prevents “permission leak” regressions in high-risk actions.
**Independent Test**: As a read-only member, verify restricted actions are visible-but-disabled with an explanatory tooltip and cannot be executed.
**Acceptance Scenarios**:
1. **Given** a user is a member of a tenant but lacks tenant management capability, **When** they view tenant lists and pages, **Then** management actions (e.g. Edit, Deactivate) are disabled and show an explanatory tooltip.
2. **Given** a user is a member but lacks tenant management capability, **When** they attempt to execute a blocked mutation (direct request / forced execution), **Then** the server denies it.
---
### User Story 2 - Archived tenant remains viewable for entitled members (Priority: P1)
A tenant member who is entitled to view a tenant can still access the tenant view even if the tenant is archived, and the UI clearly indicates status.
**Why this priority**: Prevents accidental “false 404” for legitimate members; enables safe lifecycle operations like restore.
**Independent Test**: Mark a tenant archived, ensure a viewing member can load it and sees an “Archived” banner; ensure non-members still receive 404.
**Acceptance Scenarios**:
1. **Given** a tenant is archived and a user is a member with tenant view capability, **When** they navigate to the tenant view, **Then** the page loads and shows an “Archived” status banner.
2. **Given** a tenant is archived and a user is not a member, **When** they navigate to the tenant scope URL, **Then** they receive a 404 (deny-as-not-found).
---
### User Story 3 - Diagnose & repair tenant membership invariants (Priority: P2)
An authorized tenant owner/manager can identify and fix membership integrity issues (missing owner, duplicates) via a dedicated troubleshooting screen.
**Why this priority**: Provides a recovery path for real-world “sharp edges” without requiring direct database intervention.
**Independent Test**: Seed broken states (0 owners, duplicate memberships), confirm diagnostics flag them and repair actions resolve them.
**Acceptance Scenarios**:
1. **Given** a tenant has no owners, **When** an authorized user opens diagnostics, **Then** the issue is surfaced and a repair action can promote a member to owner.
2. **Given** a tenant has duplicate memberships for the same user, **When** an authorized user runs “merge duplicates”, **Then** duplicates are removed and exactly one membership remains.
### Edge Cases
- A tenant member without management capability attempts to execute a blocked action via a forged request.
- A non-member attempts to access a tenant-scoped page (must be deny-as-not-found).
- Tenant is archived: view allowed for entitled members; lifecycle actions are status-appropriate.
- Tenant has 0 owners; tenant has 1 owner and an action would demote/remove the last owner.
- Membership duplicates exist and are resolved; ensure resulting owner count remains valid.
- A tenant has an external GUID identifier; ensure no internal lookups treat that GUID as the internal tenant primary key.
## Requirements *(mandatory)*
**Constitution alignment (required):** If this feature introduces any Microsoft Graph calls, any write/change behavior,
or any long-running/queued/scheduled work, the spec MUST describe contract registry updates, safety gates
(preview/confirmation/audit), tenant isolation, run observability (operation run record: type/identity/visibility), and tests.
If security-relevant DB-only actions intentionally skip an operation run record, the spec MUST describe audit log entries.
**Constitution alignment (RBAC-UX):** If this feature introduces or changes authorization behavior, the spec MUST:
- state which authorization plane(s) are involved (tenant `/admin/t/{tenant}` vs platform `/system`),
- ensure any cross-plane access is deny-as-not-found (404),
- explicitly define 404 vs 403 semantics:
- non-member / not entitled to tenant scope → 404 (deny-as-not-found)
- member but missing capability → 403
- describe how authorization is enforced server-side (Gates/Policies) for every mutation/operation-start/credential change,
- reference the canonical capability registry (no raw capability strings; no role-string checks in feature code),
- ensure global search is tenant-scoped and non-member-safe (no hints; inaccessible results treated as 404 semantics),
- ensure destructive-like actions require an explicit confirmation step,
- include at least one positive and one negative authorization test, and note any RBAC regression tests added/updated.
**Constitution alignment (OPS-EX-AUTH-001):** OIDC/SAML login handshakes may perform synchronous outbound HTTP (e.g., token exchange)
on `/auth/*` endpoints without an operation run record. This MUST NOT be used for Monitoring/Operations pages.
**Constitution alignment (BADGE-001):** If this feature changes status-like badges (status/outcome/severity/risk/availability/boolean),
the spec MUST describe how badge semantics stay centralized (no ad-hoc mappings) and which tests cover any new/changed values.
### Functional Requirements
- **FR-001 (Restore action icon)**: The tenant list row menu MUST display a consistent icon for the Restore action.
- **FR-002 (Readonly edit UX)**: For a tenant member lacking tenant management capability, the UI MUST present Edit as disabled with an explanatory tooltip and MUST avoid normal-click navigation leading to an error page.
- **FR-003 (Readonly cannot deactivate)**: Deactivate MUST be treated as a protected mutation and MUST NOT be executable by a tenant member lacking tenant management capability.
- **FR-004 (Archived tenant access)**: An entitled tenant member (tenant view capability) MUST be able to open archived tenants. A non-member MUST receive a 404 for tenant scope URLs.
- **FR-005 (Owner invariant)**: The system MUST prevent removing/demoting the last remaining tenant owner and MUST surface “missing owner” situations in diagnostics.
- **FR-006 (Membership integrity)**: The system MUST prevent duplicate memberships per (tenant, user). Diagnostics MUST identify duplicates and provide a safe repair flow for authorized users.
- **FR-007 (GUID vs internal ID)**: The system MUST treat external tenant identifiers (GUIDs) as external-only identifiers and MUST NOT use them where an internal tenant primary key is required.
- **FR-008 (Diagnostics access + safety)**: Diagnostics MUST not expose cross-tenant data to non-members. Repair actions MUST be permission-gated and MUST record an auditable trail.
#### Authorization & Error Semantics (explicit)
- Tenant-scope URLs: non-member / not entitled MUST be deny-as-not-found (404).
- Member but missing capability: server-side MUST deny execution (403).
- UI behavior: member-without-capability SHOULD see actions visible-but-disabled with tooltip to prevent normal-click 403 pages.
#### Out of Scope
- No new “Workspace” model in this spec.
- No platform-plane (`/system`) expansion.
- No outbound integration calls are introduced as part of diagnostics/repairs.
#### Assumptions
- “Archived” is treated as an archived/lifecycle state that remains viewable to entitled members.
- Deactivate (archive) uses the existing tenant lifecycle capability `Capabilities::TENANT_DELETE`.
### Key Entities *(include if feature involves data)*
- **Tenant**: The internal customer/workspace entity users are members of; has an internal primary key and an external identifier.
- **Tenant Membership**: Links a user to a tenant with one or more capability grants or derived entitlements.
- **Capability / Entitlement**: A named permission used to determine visibility/execution of actions within a tenant scope.
- **Diagnostics Finding**: A detected issue such as “missing owner”, “duplicate membership”, or “identifier misuse risk”.
- **Repair Action**: A controlled, permission-gated remediation step that fixes a finding and records an audit entry.
## Success Criteria *(mandatory)*
### Measurable Outcomes
- **SC-001**: Read-only members can navigate all tenant UI flows covered by automated tests without encountering an error page during normal click paths.
- **SC-002**: Protected tenant mutations (e.g., deactivate) have 0 successful executions by users lacking the required capability across automated tests.
- **SC-003**: Archived tenant access works as defined: entitled members can view; non-members get 404, verified by automated tests.
- **SC-004**: Membership integrity can be restored via UI-only repair actions for seeded broken states, verified by automated tests.