PR Body Implements Spec 065 “Tenant RBAC v1” with capabilities-first RBAC, tenant membership scoping (Option 3), and consistent Filament action semantics. Key decisions / rules Tenancy Option 3: tenant switching is tenantless (ChooseTenant), tenant-scoped routes stay scoped, non-members get 404 (not 403). RBAC model: canonical capability registry + role→capability map + Gates for each capability (no role-string checks in UI logic). UX policy: for tenant members lacking permission → actions are visible but disabled + tooltip (avoid click→403). Security still enforced server-side. What’s included Capabilities foundation: Central capability registry (Capabilities::*) Role→capability mapping (RoleCapabilityMap) Gate registration + resolver/manager updates to support tenant-scoped authorization Filament enforcement hardening across the app: Tenant registration & tenant CRUD properly gated Backup/restore/policy flows aligned to “visible-but-disabled” where applicable Provider operations (health check / inventory sync / compliance snapshot) guarded and normalized Directory groups + inventory sync start surfaces normalized Policy version maintenance actions (archive/restore/prune/force delete) gated SpecKit artifacts for 065: spec.md, plan/tasks updates, checklists, enforcement hitlist Security guarantees Non-member → 404 via tenant scoping/membership guards. Member without capability → 403 on execution, even if UI is disabled. No destructive actions execute without proper authorization checks. Tests Adds/updates Pest coverage for: Tenant scoping & membership denial behavior Role matrix expectations (owner/manager/operator/readonly) Filament surface checks (visible/disabled actions, no side effects) Provider/Inventory/Groups run-start authorization Verified locally with targeted vendor/bin/sail artisan test --compact … Deployment / ops notes No new services required. Safe change: behavior is authorization + UI semantics; no breaking route changes intended. Co-authored-by: Ahmed Darrazi <ahmeddarrazi@MacBookPro.fritz.box> Reviewed-on: #79
11 KiB
Tasks for Feature: Tenant RBAC v1
This document outlines the implementation tasks for the Tenant RBAC v1 feature, ordered by dependency.
Phase 1: Setup & Database
- T001 Verify
tenant_membershipsschema matches spec (uuid PK, role enum, minimal provenance fields) indatabase/migrations/2026_01_25_022729_create_tenant_memberships_table.php - T002 Verify
TenantMembershippivot model + relationships exist and are correct inapp/Models/TenantMembership.php,app/Models/User.php, andapp/Models/Tenant.php
Phase 2: Foundational RBAC Core
- T005 [P] Ensure canonical capability registry exists and matches v1 contract in
app/Support/Auth/Capabilities.php - T006 [P] Ensure role → capability mapping matches least-privilege semantics (Owner-only membership manage) and references only registry constants in
app/Services/Auth/RoleCapabilityMap.php - T007 Register tenant capability gates for the full registry using
Capabilities::all()(no hand-maintained lists) inapp/Providers/AuthServiceProvider.php - T008 Add/confirm request-scope cache for membership + capabilities and add a test asserting repeated capability checks do not execute additional membership queries (query count assertion) in
tests/Unit/Auth/CapabilityResolverQueryCountTest.php - T009 Create/update unit tests asserting least-privilege invariants (Owner can manage memberships, Manager cannot) in
tests/Unit/Auth/CapabilityResolverTest.php - T012 [P] Add contract test that fails fast on unknown/typo capability strings passed to the capability system in
tests/Unit/Auth/UnknownCapabilityGuardTest.php - T013 [P] (Optional, recommended) Add guard test forbidding role-string checks outside the mapper (e.g.
'owner','manager') intests/Unit/Auth/NoRoleStringChecksTest.php
Phase 3: User Story 1 - Membership Management UI
Goal: As a Tenant Owner, I want to manage members and their roles. Independent Test Criteria: An owner can add, edit, and remove members. Non-owners cannot. The last owner cannot be removed or demoted.
- T014 [US1] Create/update
TenantMembershipsRelationManagerforTenantResourceinapp/Filament/Resources/TenantResource/RelationManagers/TenantMembershipsRelationManager.php - T015 [US1] Implement table columns (user name, email, role) in
app/Filament/Resources/TenantResource/RelationManagers/TenantMembershipsRelationManager.php - T016 [US1] Ensure "Add Member" action is Owner-only and requires existing user (no placeholder user creation) in
app/Filament/Resources/TenantResource/RelationManagers/TenantMembershipsRelationManager.php - T017 [US1] Implement "Change Role" action (Owner-only, server-authorized, requires confirmation + clear validation/feedback) in
app/Filament/Resources/TenantResource/RelationManagers/TenantMembershipsRelationManager.php - T018 [US1] Implement "Remove Member" action (Owner-only, server-authorized, requires confirmation + clear validation/feedback) in
app/Filament/Resources/TenantResource/RelationManagers/TenantMembershipsRelationManager.php - T019 [US1] Add "last owner" protection logic to change/remove actions (and cover policy edge-cases) in
app/Filament/Resources/TenantResource/RelationManagers/TenantMembershipsRelationManager.php - T020 [US1] Add DB-only render guard test for Members UI: use
Http::preventStrayRequests()(and prevent queued work) while rendering/hydrating members relation manager; assert no outbound HTTP and no jobs dispatched intests/Feature/Filament/TenantMembersDbOnlyRenderTest.php - T021 [US1] Create feature test for membership management UI and authorization in
tests/Feature/Filament/TenantMembersTest.php
Phase 4: User Story 2 - Authorization Enforcement
Goal: As a user, my actions are authorized based on my role, and I cannot access unauthorized resources. Independent Test Criteria: Routes and actions are protected based on the defined capability matrix.
- T022 [US2] Harden tenant scoping to enforce FR-011 in the Filament tenant middleware chain (registered in
app/Providers/Filament/AdminPanelProvider.php) with 404 (not 403) semantics for all/admin/t/{tenant}/**routes; enforce global search scoping by overriding global search queries on each Resource (or a shared trait) to restrict results to the current tenant and deny non-members (tests assert non-member sees zero results and result URLs still 404) inapp/Filament/Resources/*Resource.php - T022 [US2] Harden tenant scoping to enforce FR-011 in the Filament tenant middleware chain (registered in
app/Providers/Filament/AdminPanelProvider.php) with 404 (not 403) semantics for all/admin/t/{tenant}/**routes; enforce global search scoping by overriding global search queries on each Resource (or a shared trait) to restrict results to the current tenant and deny non-members (tests assert non-member sees zero results and result URLs still 404) inapp/Filament/Resources/*Resource.php - T023 [US2] Add non-member 404 tests (direct URL, tenant switcher list, global search scoping) in
tests/Feature/Filament/TenantScopingTest.php - T024 [US2] Discovery sweep (required): produce a mutation/start-action hitlist across Filament (Resources/RelationManagers/Actions/BulkActions) in
specs/065-tenant-rbac-v1/enforcement-hitlist.md - T025 [US2] Enforcement pass (required): for each hitlist entry add server-side authorization + UI visibility/disabled rules + confirmations for destructive actions in
app/Filament/** - T026 [US2] Replace role-based authorization helpers (e.g.
TenantRole::can*()calls) with capability Gates across tenant-plane UI/actions (deny non-member as 404 per middleware; otherwise prefer authorization failures as 403) inapp/Filament/**andapp/Policies/** - T025 [US2] Enforcement pass (required): for each hitlist entry add server-side authorization + UI visibility/disabled rules + confirmations for destructive actions in
app/Filament/** - T026 [US2] Replace role-based authorization helpers (e.g.
TenantRole::can*()calls) with capability Gates across tenant-plane UI/actions (deny non-member as 404 per middleware; otherwise prefer authorization failures as 403) inapp/Filament/**andapp/Policies/** - T027 [P] [US2] Providers enforcement: gate + UI rules for provider CRUD / run ops / credential rotate in
app/Filament/Resources/ProviderConnectionResource.phpandapp/Filament/Resources/ProviderConnectionResource/Pages/*.php - T028 [P] [US2] Tenants + tenant settings enforcement: gate + UI rules for tenant pages/actions in
app/Filament/Resources/TenantResource.phpandapp/Filament/Resources/TenantResource/Pages/*.php - T029 [P] [US2] Policies enforcement: gate + UI rules (sync/delete/version views) in
app/Filament/Resources/PolicyResource.phpandapp/Filament/Resources/PolicyResource/Pages/*.php - T030 [P] [US2] Backups enforcement: gate + UI rules for backup sets/schedules in
app/Filament/Resources/BackupSetResource.phpandapp/Filament/Resources/BackupScheduleResource.php - T031 [P] [US2] Restore enforcement: gate + UI rules for restore creation/execution in
app/Filament/Resources/RestoreRunResource.phpandapp/Jobs/ExecuteRestoreRunJob.php - T032 [P] [US2] Drift/Findings enforcement: gate + UI rules for drift findings browsing/ack (if present) in
app/Filament/Resources/FindingResource.phpandapp/Filament/Resources/FindingResource/Pages/*.php - T033 [P] [US2] Inventory enforcement: gate + UI rules for inventory browsing/sync runs in
app/Filament/Resources/InventoryItemResource.phpandapp/Filament/Resources/InventorySyncRunResource.php - T034 [US2] Add canonical audit action_ids for membership changes (
tenant_membership.add|role_change|remove|last_owner_blocked) inapp/Support/Audit/AuditActionId.php - T035 [US2] Implement audit logging for membership changes (writes
audit_logs.action+ redacted metadata) inapp/Filament/Resources/TenantResource/RelationManagers/TenantMembershipsRelationManager.php - T036 [US2] Add audit logging tests (entry written, action_id stable, metadata minimal + redacted; includes explicit data-minimization assertions: no secrets/tokens, minimal identity fields) in
tests/Feature/Audit/TenantMembershipAuditLogTest.php - T037 [US2] Add denial diagnostics: log structured context for authorization denials (capability, tenant_id, actor_user_id) without secrets in
app/Services/Auth/CapabilityResolver.php(or a dedicated listener) and cover one representative denial path intests/Feature/Rbac/DenialDiagnosticsTest.php - T038 [P] [US2] Role matrix tests (Readonly: 5–10 golden checks) in
tests/Feature/Rbac/RoleMatrix/ReadonlyAccessTest.php - T039 [P] [US2] Role matrix tests (Operator: 5–10 golden checks) in
tests/Feature/Rbac/RoleMatrix/OperatorAccessTest.php - T040 [P] [US2] Role matrix tests (Manager: 5–10 golden checks) in
tests/Feature/Rbac/RoleMatrix/ManagerAccessTest.php - T041 [P] [US2] Role matrix tests (Owner: 5–10 golden checks) in
tests/Feature/Rbac/RoleMatrix/OwnerAccessTest.php
Late enforcement follow-ups (post-sweep)
- T046 Gate tenant registration + tenant create/edit/delete for non-managers (prevent cross-tenant privilege escalation via Register Tenant) in
app/Filament/Pages/Tenancy/RegisterTenant.php,app/Filament/Resources/TenantResource.php, andapp/Filament/Resources/TenantResource/Pages/*.php - T047 Gate policy version maintenance actions (archive/restore/prune/force delete) to
Capabilities::TENANT_MANAGEwith UI disable + server-side abort inapp/Filament/Resources/PolicyVersionResource.php - T048 Add regression tests for readonly tenant + policy version maintenance restrictions in
tests/Feature/Rbac/*.phpand update existing bootstrap test intests/Feature/TenantRBAC/TenantBootstrapAssignTest.php
Phase 5: Polish & Finalization
- T042 [P] Review all changed code for adherence to project conventions in
app/andtests/ - T043 [P] Ensure all new UI text is translatable in
resources/lang/*/*.php - T044 Run
./vendor/bin/sail bin pint --dirtyto format all changed files inapp/andtests/ - T045 Run the full test suite with
./vendor/bin/sail artisan test --compactto ensure no regressions
Dependencies
- US1 (Membership Management) depends on Phase 1 and Phase 2.
- US2 (Authorization Enforcement) depends on Phase 1 and Phase 2. US1 should be completed first to allow for testing with different roles.
Parallel Execution
- Within Phase 2, tasks T005, T006, T008, and T012 can be worked on in parallel.
- Within Phase 4, the domain enforcement tasks (T024–T030) can be split across agents once T022 (hitlist) is stable.
Implementation Strategy
The implementation will follow an MVP-first approach. The initial focus will be on completing Phase 1 and 2 to establish the core data model and RBAC logic. Then, Phase 3 will be implemented to provide the essential UI for managing memberships. Phase 4 will be a sweep to enforce the new authorization rules across the application.