# Implementation Plan: RBAC Role Matrix & Access Boundary Audit

**Branch**: `309-rbac-role-matrix-access-boundary-audit` | **Date**: 2026-05-15 | **Spec**: [spec.md](spec.md)  
**Input**: Feature specification from `/specs/309-rbac-role-matrix-access-boundary-audit/spec.md`

## Summary

Audit and harden TenantPilot's RBAC and panel-access boundaries across workspace, managed-environment, provider connection, review, review pack, evidence, finding exception, OperationRun, Admin panel, and System panel surfaces.

The implementation is audit-first:

1. Inventory repo-real role/capability grants and direct access boundaries.
2. Classify Constitution/runtime contradictions.
3. Write focused tests for confirmed contradictions and boundary bugs.
4. Apply only minimal runtime fixes.
5. Re-run focused regression lanes and document remaining product decisions.

## Technical Context

**Language/Version**: PHP 8.4.15, Laravel 12.52.0  
**Primary Dependencies**: Filament 5.2.1, Livewire 4.1.4, Pest 4.3.1, Laravel Sail  
**Storage**: PostgreSQL; no schema change expected  
**Testing**: Pest 4 Unit and Feature tests; Browser only if Feature/Filament tests cannot prove a panel/action boundary  
**Validation Lanes**: confidence; optional browser; formatting/diff-check  
**Target Platform**: Laravel Sail locally; Dokploy container deployment for staging/production  
**Project Type**: Laravel/Filament app under `apps/platform`  
**Performance Goals**: No broad query redesign; authorization checks should reuse existing resolvers and avoid new global scans  
**Constraints**: no new RBAC architecture, no migrations by default, no new roles, no new assets, no UI redesign, no broad route cleanup  
**Scale/Scope**: focused security-boundary audit and minimal fixes over existing role maps/policies/panels/tests

## UI / Surface Guardrail Plan

- **Guardrail scope**: no new operator-facing surface; direct access/action authorization and possible minor visibility alignment only.
- **Native vs custom classification summary**: existing Filament v5 panels/resources/pages/actions.
- **Shared-family relevance**: panel access, workspace/environment context, resource authorization, direct action execution, global search safety.
- **State layers in scope**: panel guard, middleware, route model binding, policies, Filament page/action access, Livewire action execution.
- **Audience modes in scope**: workspace users, customer-safe readers, platform/system users.
- **Decision/diagnostic/raw hierarchy plan**: no presentation hierarchy change.
- **Raw/support gating plan**: verify raw/provider/support details remain gated by existing policies.
- **One-primary-action / duplicate-truth control**: no new actions.
- **Handling modes by drift class or surface**: security blocker and high-risk contradiction fix in 309; product-decision-needed stays deferred.
- **Repository-signal treatment**: review-mandatory for role-map, panel, policy, and sensitive action changes.
- **Special surface test profiles**: standard-native-filament plus direct Feature/Livewire action tests.
- **Required tests or manual smoke**: focused Unit/Feature tests; browser not required unless direct behavior cannot be proven otherwise.
- **Exception path and spread control**: no exceptions planned.
- **Active feature PR close-out entry**: RBAC Inventory / Boundary Proof / Remaining Decisions.

## Shared Pattern & System Fit

- **Cross-cutting feature marker**: yes.
- **Systems touched**: role maps, capability resolvers, policies, gates, panels, workspace context, Filament resources/pages/actions, existing RBAC tests.
- **Shared abstractions reused**: `Capabilities`, `PlatformCapabilities`, `WorkspaceRoleCapabilityMap`, `RoleCapabilityMap`, `WorkspaceCapabilityResolver`, `CapabilityResolver`, `ManagedEnvironmentAccessScopeResolver`, model policies, Gate definitions, Filament access methods.
- **New abstraction introduced? why?**: none planned.
- **Why the existing abstraction was sufficient or insufficient**: the repo already has canonical maps and resolvers; the issue is suspected incorrect grants or missing enforcement, not absent infrastructure.
- **Bounded deviation / spread control**: any fix must remain local to existing maps/policies/panel checks and must not add a public permission framework.

## OperationRun UX Impact

- **Touches OperationRun start/completion/link UX?**: authorization only.
- **Central contract reused**: `OperationRunPolicy`, `OperationRunCapabilityResolver`, `OperationRunLinks`.
- **Delegated UX behaviors**: all existing start/completion/link feedback remains unchanged.
- **Surface-owned behavior kept local**: no new operation UI or notifications.
- **Queued DB-notification policy**: N/A.
- **Terminal notification path**: existing central lifecycle.
- **Exception path**: none.

## Provider Boundary & Portability Fit

- **Shared provider/platform boundary touched?**: provider credential authorization is audited.
- **Provider-owned seams**: credential rotation/delete/dedicated credential management.
- **Platform-core seams**: ProviderConnection resource/policy and workspace/environment access boundaries.
- **Neutral platform terms / contracts preserved**: provider connection, provider credential, workspace, managed environment, operation.
- **Retained provider-specific semantics and why**: existing Microsoft/Intune details stay in provider-owned logic.
- **Bounded extraction or follow-up path**: no provider registry redesign; provider-specific follow-up only if audit finds structural drift.

## Constitution Check

- Inventory-first: PASS. No inventory or Graph sync behavior changes are planned.
- Read/write separation: PASS. Mutations remain behind existing action flows; this spec audits and fixes authorization.
- Graph contract path: PASS. No Graph endpoint or contract change.
- Deterministic capabilities: NEEDS IMPLEMENTATION PROOF. Role/capability grants must become deterministic and tested.
- RBAC-UX: NEEDS IMPLEMENTATION PROOF. Constitution says Manager must not manage tenant memberships; current maps appear to grant Manager membership-management authority.
- Workspace isolation: NEEDS IMPLEMENTATION PROOF. Cross-workspace direct URLs must be tested for representative sensitive resources.
- Tenant/managed-environment isolation: NEEDS IMPLEMENTATION PROOF. Same-workspace wrong-environment direct URLs must be tested.
- Cross-plane access: PARTIAL PASS. Existing `/system` tests prove several tenant-session denials; Spec 309 should keep/extend focused proof.
- Run observability: PASS. No new run behavior; OperationRun access must remain policy-gated.
- TEST-GOV-001: PASS if tests stay focused and no broad helper defaults are introduced.
- PROP-001 / BLOAT-001: PASS. No new tables, roles, capability framework, enum, or UI taxonomy planned.
- PERSIST-001: PASS. No new persisted truth.
- STATE-001: PASS. No new lifecycle/status family.
- UI-SEM-001: PASS. No presentation framework.
- XCUT-001: PASS if implementation reuses existing auth/policy/gate paths.
- PROV-001: PASS. Provider credential authorization is audited without expanding provider semantics.
- UI-FIL-001: PASS if any visibility alignment stays Filament-native and avoids assets/ad-hoc styling.

## Initial Read-Only Repo Findings

### RBAC Inventory

| Role | Current inspected sensitive capabilities | Initial match assessment | Action |
|---|---|---|---|
| Workspace Owner | `workspace_membership.manage`, `tenant_membership.manage`, provider manage/dedicated, review/evidence manage, finding exception approve | Mostly expected | Keep unless tests reveal bypass |
| Workspace Manager | `workspace_membership.manage`, appended `tenant_membership.manage`, provider manage, review/evidence manage, finding exception approve | High-risk contradiction for membership; other manage grants need classification | Add tests, fix membership if Owner-only confirmed |
| Workspace Operator | membership view, provider view/run, review/evidence view, findings triage, audit view | Mostly expected | Prove no owner-only mutation |
| Workspace Readonly | workspace/settings/alerts/baselines/audit view plus tenant/review/evidence/provider view via merged tenant role | Mostly expected but verify customer-safe download/mutation boundaries | Prove read-only cannot mutate |
| Platform/System | `PlatformUser` + `PlatformCapabilities`, separate `platform` guard | Expected separate plane | Prove no ordinary workspace access to `/system` and no implicit customer data access |

### Constitution vs Runtime

- `apps/platform/app/Services/Auth/WorkspaceRoleCapabilityMap.php` currently grants Manager `Capabilities::WORKSPACE_MEMBERSHIP_MANAGE`.
- `WorkspaceRoleCapabilityMap::getCapabilities()` appends `Capabilities::TENANT_MEMBERSHIP_MANAGE` for Manager.
- `apps/platform/app/Services/Auth/RoleCapabilityMap.php` does not grant tenant Manager `TENANT_MEMBERSHIP_MANAGE`, which makes the WorkspaceRoleCapabilityMap append the direct source of the tenant-membership Manager grant.
- `.specify/memory/constitution.md` states: "Manager ... MUST NOT manage tenant memberships (Owner-only)."
- Existing tests currently assert Manager can manage tenant membership:
  - `apps/platform/tests/Unit/Auth/CapabilityResolverTest.php`
  - `apps/platform/tests/Feature/Rbac/RoleMatrix/ManagerAccessTest.php`

### Panel Boundary Findings

- `apps/platform/app/Models/User.php::canAccessPanel()` currently returns `true`.
- Admin panel uses `web` guard plus `ensure-correct-guard:web`, `ensure-workspace-selected`, and `ensure-filament-tenant-selected`.
- System panel uses `authGuard('platform')`, `ensure-correct-guard:platform`, and `ensure-platform-capability:platform.access_system_panel`.
- Existing tests already cover several system-panel cross-plane denials:
  - `apps/platform/tests/Feature/Auth/CrossScopeAccessTest.php`
  - `apps/platform/tests/Feature/System/Spec113/AuthorizationSemanticsTest.php`
  - `apps/platform/tests/Feature/System/Spec114/SystemConsoleAccessSemanticsTest.php`
- Spec 309 still needs a dedicated boundary test family tying those semantics to the RBAC matrix and current `canAccessPanel()` posture.

## Proposed Minimal Fix Strategy

1. Start with static tests for `WorkspaceRoleCapabilityMap` and `RoleCapabilityMap`.
2. If Constitution Owner-only semantics are confirmed, remove Manager's `WORKSPACE_MEMBERSHIP_MANAGE` grant and the Manager-specific appended `TENANT_MEMBERSHIP_MANAGE`.
3. Update existing tests that assert Manager membership management so they become denial tests.
4. Verify whether `User::canAccessPanel()` can be tightened without breaking admin login/workspace chooser flow. If not, document the middleware/policy proof and add direct route tests.
5. Add or adjust policy/action tests for confirmed direct-access bypasses only.
6. Align Filament visibility only after server-side policy behavior is correct.
7. Do not change provider/review/evidence/finding-operation grants unless the audit classifies them as confirmed security bugs rather than product decisions.

## Project Structure

### Documentation (this feature)

```text
specs/309-rbac-role-matrix-access-boundary-audit/
|-- spec.md
|-- plan.md
|-- tasks.md
`-- checklists/
    `-- requirements.md
```

### Likely Source Code Surfaces For Later Implementation

```text
apps/platform/app/Support/Auth/
|-- Capabilities.php
|-- PlatformCapabilities.php
`-- WorkspaceRole.php

apps/platform/app/Support/
`-- TenantRole.php

apps/platform/app/Services/Auth/
|-- WorkspaceRoleCapabilityMap.php
`-- RoleCapabilityMap.php

apps/platform/app/Models/
|-- User.php
`-- PlatformUser.php

apps/platform/app/Providers/
|-- AuthServiceProvider.php
`-- Filament/
    |-- AdminPanelProvider.php
    `-- SystemPanelProvider.php

apps/platform/app/Policies/
|-- OperationRunPolicy.php
|-- ProviderConnectionPolicy.php
|-- EnvironmentReviewPolicy.php
|-- ReviewPackPolicy.php
|-- EvidenceSnapshotPolicy.php
`-- FindingExceptionPolicy.php

apps/platform/tests/Unit/Auth/
apps/platform/tests/Feature/Rbac/
apps/platform/tests/Feature/Auth/
apps/platform/tests/Feature/System/
apps/platform/tests/Feature/ProviderConnections/
apps/platform/tests/Feature/ReviewPack/
apps/platform/tests/Feature/Reviews/
apps/platform/tests/Feature/Findings/
apps/platform/tests/Feature/Operations/
```

**Structure Decision**: Use existing Laravel/Filament/Pest test families where equivalent coverage exists. Create new `tests/Feature/Rbac/*BoundaryTest.php` files only when no repo-real focused equivalent exists.

## Technical Approach

1. Inventory capabilities from `Capabilities::all()` and `PlatformCapabilities::all()`.
2. Inventory role grants from `WorkspaceRoleCapabilityMap::getCapabilities()` and `RoleCapabilityMap::getCapabilities()`.
3. Categorize capabilities into workspace administration, managed-environment administration, provider connections, findings/exceptions, reviews, review packs, evidence, OperationRuns, reports, support requests, and system panel.
4. Compare membership, credential, lifecycle, review/export, and operation actions against Constitution RBAC-UX statements.
5. Add focused tests for confirmed mismatches and direct route/action boundaries.
6. Apply only the smallest map/policy/panel/resource changes needed for confirmed bugs.
7. Run focused regressions for affected review, review-pack, provider, finding, and operation lanes.
8. Close out with role inventory, fixed contradictions, deferred product decisions, and validation results.

## Data / Model Implications

- No migration expected.
- No new model expected.
- No new capability persistence expected.
- Static role-to-capability maps may change.
- Existing `workspace_memberships` and `managed_environment_memberships` data is not migrated by default.

## Policy / Authorization Implications

- `WorkspaceMembershipPolicy` and `WorkspaceRoleCapabilityMap` are the primary owner-only membership-management proof targets.
- Provider credential actions should continue to rely on `ProviderConnectionPolicy`.
- Review and Review Pack actions should continue to rely on `EnvironmentReviewPolicy` and `ReviewPackPolicy`.
- FindingException lifecycle actions should continue to rely on `FindingExceptionPolicy`.
- OperationRun visibility/action access should continue to rely on `OperationRunPolicy` and `OperationRunCapabilityResolver`.
- Service-level mutations must call Gate/Policy where UI actions execute state changes.

## Filament v5 / Livewire v4 Compliance Notes

- Filament is v5.2.1 and Livewire is v4.1.4.
- Panel providers are registered in `apps/platform/bootstrap/providers.php`, not `bootstrap/app.php`.
- This spec does not add a new panel provider.
- Any changed globally searchable resource must either keep an Edit/View page or disable global search.
- Destructive actions must execute via `Action::make(...)->action(...)`, include `->requiresConfirmation()`, and still authorize server-side.
- No new assets are planned. Existing panel theme assets remain resolved through `PanelThemeAsset`; deployment should keep the existing `cd apps/platform && php artisan filament:assets` step where registered Filament assets are published.

## Test Strategy

### New Or Updated Focused Tests

- `apps/platform/tests/Unit/Auth/WorkspaceRoleCapabilityMapTest.php`
- `apps/platform/tests/Feature/Rbac/WorkspaceRoleCapabilityBoundaryTest.php`
- `apps/platform/tests/Feature/Rbac/AdminPanelAccessBoundaryTest.php`
- `apps/platform/tests/Feature/Rbac/SystemPanelAccessBoundaryTest.php`
- `apps/platform/tests/Feature/Rbac/ManagedEnvironmentAccessBoundaryTest.php`
- `apps/platform/tests/Feature/Rbac/ProviderConnectionAccessBoundaryTest.php`
- `apps/platform/tests/Feature/Rbac/ReviewPackAccessBoundaryTest.php`
- `apps/platform/tests/Feature/Rbac/OperationRunAccessBoundaryTest.php`
- `apps/platform/tests/Feature/Rbac/FindingExceptionLifecycleAccessBoundaryTest.php`

Use existing tests instead when they already provide the exact proof and update names only if a new focused file improves reviewability.

### Regression Lanes

- Review/customer workspace:
  - `apps/platform/tests/Feature/Reviews/CustomerReviewWorkspaceAuthorizationTest.php`
  - `apps/platform/tests/Feature/Reviews/CustomerReviewWorkspacePackAccessTest.php`
- ReviewPack:
  - `apps/platform/tests/Feature/ReviewPack/ReviewPackRbacTest.php`
  - `apps/platform/tests/Feature/ReviewPack/ReviewPackDownloadTest.php`
- ProviderConnection:
  - existing `apps/platform/tests/Feature/ProviderConnections/*Authorization*` and credential security tests if provider boundaries change.
- OperationRun:
  - `apps/platform/tests/Feature/Rbac/OperationRunWorkspaceFirstAuthorizationTest.php`
  - `apps/platform/tests/Feature/Operations/TenantlessOperationRunViewerTest.php`
  - existing operation link/legacy route guard tests if policy or links change.

### Validation Commands

```bash
cd apps/platform && ./vendor/bin/sail artisan test --compact \
  tests/Unit/Auth/WorkspaceRoleCapabilityMapTest.php \
  tests/Feature/Rbac/WorkspaceRoleCapabilityBoundaryTest.php \
  tests/Feature/Rbac/AdminPanelAccessBoundaryTest.php \
  tests/Feature/Rbac/SystemPanelAccessBoundaryTest.php \
  tests/Feature/Rbac/ManagedEnvironmentAccessBoundaryTest.php \
  tests/Feature/Rbac/ProviderConnectionAccessBoundaryTest.php \
  tests/Feature/Rbac/ReviewPackAccessBoundaryTest.php \
  tests/Feature/Rbac/OperationRunAccessBoundaryTest.php \
  tests/Feature/Rbac/FindingExceptionLifecycleAccessBoundaryTest.php
```

```bash
cd apps/platform && ./vendor/bin/sail artisan test --compact \
  tests/Feature/Reviews/CustomerReviewWorkspaceAuthorizationTest.php \
  tests/Feature/Reviews/CustomerReviewWorkspacePackAccessTest.php \
  tests/Feature/ReviewPack/ReviewPackRbacTest.php \
  tests/Feature/ReviewPack/ReviewPackDownloadTest.php
```

If OperationRun policy or links are touched:

```bash
cd apps/platform && ./vendor/bin/sail artisan test --compact \
  tests/Feature/Rbac/OperationRunWorkspaceFirstAuthorizationTest.php \
  tests/Feature/Operations/TenantlessOperationRunViewerTest.php \
  tests/Feature/Guards/OperationRunLinkContractGuardTest.php
```

Final:

```bash
cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent
git diff --check
```

## Implementation Phases

1. **Read-only inventory**: confirm role maps, panel guards, policies, routes, resources, and existing tests.
2. **Classification**: distinguish confirmed security bugs, product decisions, docs drift, UI-only mismatches, and out-of-scope findings.
3. **Tests first**: add failing tests for confirmed contradictions.
4. **Minimal fixes**: adjust maps/policies/panel/resource access only where confirmed.
5. **Regression validation**: run focused affected lanes.
6. **Close-out**: record inventory, fixed contradictions, deferred decisions, tests, and remaining risks.

## Risk Controls

- Do not remove Manager capabilities unrelated to membership unless classified as confirmed bugs.
- Do not tighten `canAccessPanel()` until direct route/middleware behavior and workspace chooser flow are understood.
- Do not implement support impersonation, break-glass redesign, or system-to-workspace implicit access.
- Do not add new capability aliases.
- Do not create migrations unless the existing model cannot represent the confirmed fix.
- Do not broaden test helpers or factories globally.

## Rollout / Deployment Considerations

- No migration expected.
- No env vars expected.
- No queue/cron changes expected.
- No storage volume changes expected.
- No frontend build expected.
- Any changed authorization behavior must be validated in Staging before Production promotion.
- Existing Dokploy deployment should keep current asset publication and cache-clearing steps; no new asset step is introduced by this spec.

## Complexity Tracking

| Violation | Why Needed | Simpler Alternative Rejected Because |
|---|---|---|
| None planned | N/A | N/A |

## Open Product Decisions To Preserve If Unclear

- Manager membership-management authority.
- Manager managed-environment access-scope authority.
- Manager provider credential rotation/delete authority.
- Manager accepted-risk approval authority.
- Readonly Review Pack download authority.
- System/platform support access to customer workspaces.

Unclear items must be recorded as product-decision-needed rather than fixed blindly.
