Kurzbeschreibung Implementiert Tenant RBAC v1 (specs/062-tenant-rbac-v1): tenant_memberships, Capability registry/resolver, gates, Filament RelationManager für Tenant→Members, Last‑Owner‑Guard, bootstrap assign/recover (break‑glass), Audit-Logging. Wichtige Änderungen Migration: create_tenant_memberships_table (T004) — ausgeführt Models/Services: TenantMembership, Capabilities, RoleCapabilityMap, CapabilityResolver (T008–T013) Auth: Gates registriert in AuthServiceProvider.php (T011) Filament: RelationManager unter Settings → Tenants (Members CRUD + Last‑Owner‑Guard) (T017–T018) Break‑glass: lokale platform superadmin + persistent banner + bootstrap_recover action (T024–T026) Audit: Audit‑Einträge für membership actions mit canonical action_ids (T022) Tests: neue/aktualisierte Feature- und Unit‑Tests (siehe Test‑Abschnitt) Migrations / Deploy Run migrations: vendor/bin/sail artisan migrate Keine neuen Panel‑Assets registriert (kein php artisan filament:assets nötig) Wenn Frontend nicht sichtbar: vendor/bin/sail npm run dev oder vendor/bin/sail npm run build Tests (geprüft / neu) Fokus-Suite ausgeführt für Tenant RBAC (T031). Neu / aktualisiert: CapabilitiesRegistryTest CapabilityResolverTest TenantSwitcherScopeTest TenantRouteDenyAsNotFoundTest TenantMembershipCrudTest LastOwnerGuardTest TenantBootstrapAssignTest MembershipAuditLogTest BreakGlassRecoveryTest Befehl zum lokalen Ausführen (minimal): vendor/bin/sail artisan test tests/Feature/TenantRBAC --stop-on-failure Filament / Sicherheits‑Contract (erforderliche Punkte) Livewire v4.0+ compliance: bestätigt (Filament v5 target). Provider registration: keine neue Panel‑Provider-Änderung; falls nötig: providers.php (Laravel 11+). Globale Suche: keine neuen Ressourcen für Global Search hinzugefügt; vorhandene Ressourcen behalten Edit/View‑Pages unverändert. Destructive actions: tenant_membership.remove und role‑demote sind destruktive — implemented via Action::make(...)->action(...)->requiresConfirmation() + policy checks. Asset strategy: keine globalen Assets; on‑demand/load as before. Deployment: filament:assets nicht erforderlich für diese PR. Testing plan: Livewire/Filament Komponenten + actions abgedeckt — RelationManager CRUD, Last‑Owner‑Guard, BreakGlassRecovery, CapabilityResolver/Registry, Tenant switcher + deny‑as‑not‑found route tests. Offene/optionale Punkte T005/T028/T029 (tenant_role_mappings migration + UI + Tests) sind optional und noch nicht umgesetzt. Checklist (aus tasks.md) T001–T003 Discovery T004, T006–T007 Migrations (T005 optional) T008–T013 Models/Capabilities/Gates T014–T016 Tenant isolation & route enforcement T017–T021 Membership UI + bootstrap flows T022–T023 Audit logging + tests T024–T027 Break‑glass flows & tests T005, T028, T029 Optional mappings T030–T031 Formatting + focused tests Migration / Test commands to run locally vendor/bin/sail up -d vendor/bin/sail artisan migrate vendor/bin/sail artisan tinker (falls manuell Benutzer/Flags setzen) vendor/bin/sail artisan test tests/Feature/TenantRBAC --stop-on-failure Wenn du einen PR‑Titel und Labels willst, schlage ich vor: Title: feat(062): Tenant RBAC v1 — memberships, capability resolver, break‑glass recovery Labels: feature, tests, migration Co-authored-by: Ahmed Darrazi <ahmeddarrazi@MacBookPro.fritz.box> Reviewed-on: #74
6.0 KiB
6.0 KiB
Actionable Tasks for Tenant RBAC v1
Feature: Tenant RBAC v1
Branch: 062-tenant-rbac-v1
Plan: specs/062-tenant-rbac-v1/plan.md
This task list is dependency-ordered and test-driven. It implements:
- Entra (OIDC) identity (no Entra credentials stored)
- Suite-tenant authorization via
tenant_memberships(SoT) - Capabilities-first gates/policies (no role checks in feature code)
- Tenant switcher + direct route enforcement (non-members = 404)
- Audit logging with canonical action_ids
- Break-glass platform superadmin recovery
Phase 0 — Discovery / Fit Check
- T001 [P] Confirm existing auth entrypoints (where OIDC callback/upsert happens) and Filament tenancy resolver (where current tenant is set).
- T002 [P] Confirm existing
User/Tenantmodels and current schema (do NOT create duplicates). Identify required columns for Entra identity:entra_tenant_id (tid),entra_object_id (oid). - T003 [P] Identify existing AuditLog service/model and how to write audit entries (target format + redaction).
Phase 1 — Schema (RBAC source of truth)
- T004 Create migration
create_tenant_memberships_tablewith:tenant_id,user_id,role(owner|manager|operator|readonly)source(manual|entra_group|entra_app_role|break_glass)source_ref(nullable)created_by_user_id(nullable)- unique
(tenant_id, user_id)and index(tenant_id, role)
- T005 (Optional, but supported) Create migration
create_tenant_role_mappings_tablewith:tenant_id,mapping_type(entra_group|entra_app_role),external_id,role,is_enabled- unique
(tenant_id, mapping_type, external_id)
- T006 Add/adjust
userscolumns if missing:entra_tenant_id(tid),entra_object_id(oid) + unique index(entra_tenant_id, entra_object_id). - T007 Run migrations.
Phase 2 — Models + Capability Registry (capabilities-first)
- T008 Create
app/Support/Auth/Capabilities.phpas the canonical allowlist (constants/enum) of capability strings. - T009 Create
app/Services/Auth/RoleCapabilityMap.php(single source of truth) mapping roles → capabilities. - T010 Create
app/Services/Auth/CapabilityResolver.php:- resolves membership for (user, tenant) once per request (no N+1)
- answers
can($capability)using the registry + map
- T011 Register Gates in
app/Providers/AuthServiceProvider.phpusingCapabilityResolver(no direct role checks). - T012 Add model
TenantMembershipand (if used)TenantRoleMappingwith relationships:Tenant::memberships(),User::tenantMemberships()
- T013 Unit tests:
CapabilitiesRegistryTest: role map only references registry entriesCapabilityResolverTest: Owner/Manager/Operator/Readonly mapping works and is deterministic
Phase 3 — Tenant Isolation (switcher + deny-as-not-found)
- T014 Enforce tenant switcher scoping: only tenants with a membership are listable/selectable for a user.
- T015 Enforce route-level deny-as-not-found:
- direct access to
/t/{tenant}and tenant-scoped resources returns 404 when user is not a member. - member without capability returns 403.
- direct access to
- T016 Feature tests:
TenantSwitcherScopeTest: only membership tenants appearTenantRouteDenyAsNotFoundTest: non-member gets 404 for direct URL
Phase 4 — Suite Tenant Membership Management UI (Tenant → Members)
- T017 Add a Filament Relation Manager (or equivalent) under
Settings → Tenantsto manage memberships:- list members + role
- add member (select existing user) + role
- edit member role
- remove member
- T018 Implement Last Owner Guard:
- prevent removing/demoting last
ownermembership (clear UI message)
- prevent removing/demoting last
- T019 Implement Bootstrap assign:
- on tenant creation, creator becomes Owner (action_id
tenant_membership.bootstrap_assign)
- on tenant creation, creator becomes Owner (action_id
- T020 Implement Bootstrap recover (platform superadmin path):
- add/assign Owner when needed (action_id
tenant_membership.bootstrap_recover)
- add/assign Owner when needed (action_id
- T021 Feature tests:
TenantMembershipCrudTestLastOwnerGuardTestTenantBootstrapAssignTest
Phase 5 — Audit Logging (canonical action_ids)
-
T022 Add audit logging for membership and mapping changes with canonical action_ids:
tenant_membership.addtenant_membership.role_changetenant_membership.removetenant_membership.bootstrap_assigntenant_membership.bootstrap_recovertenant_role_mapping.create|update|delete(if mappings are enabled)
Audit entries must be redacted (no secrets; minimal identity data).
-
T023 Feature test
MembershipAuditLogTestensures audit entries are written on add/change/remove and contain no sensitive fields.
Phase 6 — Break-glass Platform Superadmin (recovery)
- T024 Implement (or confirm existing) local platform superadmin authentication separate from Entra users.
- T025 Add a persistent UI banner when authenticated as break-glass.
- T026 Ensure platform superadmin can manage memberships across all tenants for recovery (at least to add an Owner).
- T027 Feature test
BreakGlassRecoveryTest:- can assign owner to tenant
- actions are audited with bootstrap_recover
Phase 7 — Optional: Entra Mapping (deferred execution in v1)
- T028 (Optional) Add UI to manage
tenant_role_mappings(no Graph calls for resolution in v1). - T029 (Optional) Test that mapping records are tenant-scoped and audited on create/update/delete.
Phase 8 — Quality Gates
- T030 Run formatting:
./vendor/bin/sail php ./vendor/bin/pint --dirty - T031 Run focused tests:
./vendor/bin/sail artisan test tests/Feature/TenantRBAC --stop-on-failure
Notes / Guardrails
- Non-member access = 404 (deny-as-not-found). Member without capability = 403.
- No feature code may use
role == ...checks. Always gates/capabilities. - Do not add any render-time Graph calls (group/app-role resolution is deferred unless explicitly scheduled as a job in a later feature).