TenantAtlas/specs/402-resource-policy-authorization-proof-matrix/plan.md
Ahmed Darrazi eaf28229e0
Some checks failed
PR Fast Feedback / fast-feedback (pull_request) Failing after 1m7s
feat: add resource policy authorization proof matrix
2026-06-23 09:44:21 +02:00

285 lines
22 KiB
Markdown

# Implementation Plan: Spec 402 - Resource Policy & Authorization Proof Matrix
**Branch**: `402-resource-policy-authorization-proof-matrix` | **Date**: 2026-06-23 | **Spec**: `specs/402-resource-policy-authorization-proof-matrix/spec.md`
**Input**: Feature specification from `specs/402-resource-policy-authorization-proof-matrix/spec.md`
## Summary
Spec 402 converts TenantPilot resource authorization from implicit/scattered proof into an auditable matrix and targeted hardening package. The implementation must inventory existing admin and system resource-backed surfaces, classify each policy/gate/capability/scoped-query decision, add focused negative tests for high-risk authorization paths, and apply only minimal hardening for confirmed gaps.
Do not start by adding policies. Build the matrix first, classify gaps, then fix only the smallest confirmed in-scope authorization defects.
## Technical Context
**Language/Version**: PHP 8.4.15, Laravel 12.52.0
**Primary Dependencies**: Filament 5.2.1, Livewire 4.1.4, Laravel Sail, Pest 4.3.1, PHPUnit 12.5.4
**Storage**: PostgreSQL; no schema changes allowed
**Testing**: Pest Feature/Filament/Policy tests, focused Pest Browser smoke where available
**Validation Lanes**: confidence for Feature/Filament authorization tests; browser for representative UI proof; heavy-governance only if a matrix/discovery guard is implemented
**Target Platform**: TenantPilot Laravel monolith under `apps/platform`
**Project Type**: Laravel + Filament application
**Performance Goals**: No material runtime or suite-cost increase; avoid broad browser/full-suite expansion
**Constraints**: No new roles, permission product model, persisted truth, migrations, product surfaces, navigation, or broad refactor
**Scale/Scope**: Existing `/admin` resources/pages/actions and `/system` pages/actions with resource-backed authorization impact
## Preparation Context
- Dirty state before preparation: clean on `platform-dev` at `e1a7752f chore: finalize high risk admin action proof pack (#472)`.
- Spec Kit script used: `.specify/scripts/bash/create-new-feature.sh --json --number 402 --short-name resource-policy-authorization-proof-matrix "Resource Policy & Authorization Proof Matrix"`.
- Generated branch/path: `402-resource-policy-authorization-proof-matrix`, `specs/402-resource-policy-authorization-proof-matrix/`.
- Existing conflict note: local and remote branch `402-screwfast-website-rebuild` existed before preparation, but no `specs/402-*` package existed.
- Candidate source: direct user-provided Spec 402 draft, promoted from Spec 400 P1 resource-policy matrix condition.
- Completed-spec guardrail: Specs 400 and 401 are read-only context. Do not rewrite their close-out, validation, completed tasks, implementation reports, or browser evidence.
## Existing Repository Surfaces
### Panels and routes
- Admin panel provider: `apps/platform/app/Providers/Filament/AdminPanelProvider.php`, registered in `apps/platform/bootstrap/providers.php`, path `/admin`, discovers `App\Filament\Resources`.
- System panel provider: `apps/platform/app/Providers/Filament/SystemPanelProvider.php`, registered in `apps/platform/bootstrap/providers.php`, path `/system`, discovers `App\Filament\System\Pages`.
- Admin route families include workspace/environment resource routes under `/admin/workspaces/{workspace}/environments/{environment}/...`.
- System route families include `/system/directory/...`, `/system/ops/...`, `/system/security/access-logs`, and `/system/repair-workspace-owners`.
### Authorization foundations
- Tenant/admin capabilities are registered in `apps/platform/app/Providers/AuthServiceProvider.php` from `App\Support\Auth\Capabilities`.
- Platform/system capabilities are registered in `AuthServiceProvider` from `App\Support\Auth\PlatformCapabilities`.
- Some policies are registered via `$policies` in `AuthServiceProvider`.
- Additional policies are manually bound in `apps/platform/app/Providers/AppServiceProvider.php` for `BackupSchedule`, `Finding`, `EntraGroup`, and `OperationRun`.
- Existing central paths include `App\Services\Auth\CapabilityResolver`, `App\Services\Auth\WorkspaceCapabilityResolver`, `App\Support\Rbac\UiEnforcement`, and `App\Support\Rbac\WorkspaceUiEnforcement`.
### Resource inventory seed
The implementation must verify this list rather than treating it as complete:
- Admin resources: `AlertDeliveryResource`, `AlertDestinationResource`, `AlertRuleResource`, `BackupScheduleResource`, `BackupSetResource`, `BaselineProfileResource`, `BaselineSnapshotResource`, `EntraGroupResource`, `EnvironmentReviewResource`, `EvidenceSnapshotResource`, `FindingExceptionResource`, `FindingResource`, `InventoryItemResource`, `ManagedEnvironmentResource`, `OperationRunResource`, `PolicyResource`, `PolicyVersionResource`, `ProviderConnectionResource`, `RestoreRunResource`, `ReviewPackResource`, `StoredReportResource`, `Workspaces\WorkspaceResource`.
- Admin model-backed pages/custom flows: `BaselineSubjectResolution`, `EnvironmentDashboard`, `EnvironmentDiagnostics`, `EnvironmentRequiredPermissions`, `FindingsIntakeQueue`, `MyFindingsInbox`, `DecisionRegister`, `GovernanceInbox`, `AuditLog`, `EvidenceOverview`, `Operations`, `TenantlessOperationRunViewer`, `CustomerReviewWorkspace`, `ReviewRegister`, `WorkspaceSettings`, `ManagedEnvironmentOnboardingWizard`.
- Relation managers: backup schedule operation runs, backup items, baseline tenant assignments, managed environment memberships, policy versions, workspace memberships, and any relation managers discovered during implementation.
- System pages: dashboard, directory tenants/workspaces/detail pages, ops controls/failures/runbooks/runs/stuck/view run, repair workspace owners, security access logs.
- Controller-backed routes: review-pack downloads/rendered reports, management-report PDF downloads, provider consent/RBAC callbacks, finding exception queue deep links, workspace/environment context switching.
## UI / Surface Guardrail Plan
- **Guardrail scope**: existing operator/admin/system surfaces may be authorization-hardened; no new surfaces.
- **Affected routes/pages/actions/states/navigation/panel/provider surfaces**: exact touched surfaces named in implementation report after matrix inventory.
- **No-impact class, if applicable**: N/A because rendered authorization behavior may change.
- **Native vs custom classification summary**: native Filament resources/pages plus existing Laravel controllers and shared authorization helpers.
- **Shared-family relevance**: authorization, global search, high-impact actions, relation managers, downloads/exports, system panel access.
- **State layers in scope**: page, table/action, relation manager, route/query, global search, controller route.
- **Audience modes in scope**: operator-MSP, readonly/customer where existing tests/surfaces represent it, support-platform/system.
- **Decision/diagnostic/raw hierarchy plan**: unchanged; do not expose new raw technical evidence.
- **Raw/support gating plan**: preserve or tighten existing capability gating.
- **One-primary-action / duplicate-truth control**: unchanged; do not add UI layers.
- **Handling modes by drift class or surface**: review-mandatory for high-risk authorization paths; exception-required for any policy/gate exception; hard-stop for P0 unsafe access.
- **Repository-signal treatment**: review-mandatory for missing policy proof, direct invocation gaps, relation/bulk/search uncertainty, and system/admin boundary gaps.
- **Special surface test profiles**: standard-native-filament, global-context-shell, system-admin, browser representative proof.
- **Required tests or manual smoke**: Feature/Filament/policy tests plus focused browser smoke.
- **Exception path and spread control**: documented exception in matrix and implementation report only; no runtime exception framework.
- **Active feature PR close-out entry**: `Guardrail / Exception / Smoke Coverage`.
- **UI/Productization coverage decision**: existing-surface authorization hardening only; no route-inventory/design matrix update unless implementation materially changes a reachable surface beyond authorization.
- **Coverage artifacts to update**: none planned.
- **No-impact rationale**: N/A.
- **Navigation / Filament provider-panel handling**: no provider registration changes; system/admin provider locations must be stated in close-out.
- **Screenshot or page-report need**: no page-report set; focused browser proof is sufficient.
## Product Surface Contract Plan
- **Product Surface Contract reference**: `docs/product/standards/product-surface-contract.md`
- **No-legacy posture**: canonical current authorization, no compatibility exception.
- **Page archetype and surface budget plan**: existing archetypes only; neutral budget impact expected.
- **Technical Annex and deep-link demotion plan**: unchanged; do not promote OperationRun/evidence/raw IDs/source keys/payloads.
- **Canonical status vocabulary plan**: unchanged.
- **Product Surface exceptions**: none planned.
- **Browser verification plan**: focused representative authorization paths.
- **Human Product Sanity plan**: focused authorization sanity over changed rendered behavior.
- **Visible complexity outcome target**: neutral or decreased.
- **Implementation report target**: `specs/402-resource-policy-authorization-proof-matrix/implementation-report.md`.
## Filament / Livewire / Deployment Posture
- **Livewire v4 compliance**: Livewire 4.1.4 confirmed by Laravel Boost; no Livewire v3 APIs allowed.
- **Panel provider registration location**: unchanged; Laravel 12 providers are registered in `apps/platform/bootstrap/providers.php`.
- **Global search posture**: every resource must be classified; do not enable global search merely for completeness. Globally searchable resources need View/Edit pages, `$recordTitleAttribute`, scoped queries, and tests.
- **Destructive/high-impact action posture**: all touched destructive/high-impact actions must be action-backed, `->requiresConfirmation()` where destructive/high-impact, server-authorized, audited when mutating, and tested.
- **Asset strategy**: no new assets. `filament:assets` is not newly required unless implementation unexpectedly registers assets, which is out of scope by default.
- **Testing plan**: policy/gate tests, Filament page/action tests, relation manager tests, direct route access tests, global search posture tests, system/admin separation tests, focused browser smoke.
- **Deployment impact**: no env vars, migrations, queues, scheduler, storage, assets, routes, panels, or navigation changes expected. If authorization hardening changes runtime behavior, deployment notes must call out safer access enforcement only.
## Shared Pattern & System Fit
- **Cross-cutting feature marker**: yes.
- **Systems touched**: policies, gates, capability resolvers, UI enforcement helpers, scoped Filament resource queries, relation managers, system capability middleware, controller authorization.
- **Shared abstractions reused**: `CapabilityResolver`, `WorkspaceCapabilityResolver`, policy classes, `UiEnforcement`, `WorkspaceUiEnforcement`, platform capability middleware, existing scoped query helpers.
- **New abstraction introduced? why?**: none planned.
- **Why the existing abstraction was sufficient or insufficient**: existing abstractions are the correct sources of product authorization semantics; the gap is proof consistency and any missing direct/access tests.
- **Bounded deviation / spread control**: gate/capability exception acceptable only when matrix documents why adding a policy would duplicate existing tested contract without increasing safety.
## OperationRun UX Impact
- **Touches OperationRun start/completion/link UX?**: proof only, possible if OperationRun-linked actions/resources are hardened.
- **Central contract reused**: existing OperationRun policies and links.
- **Delegated UX behaviors**: unchanged.
- **Surface-owned behavior kept local**: existing initiation inputs only.
- **Queued DB-notification policy**: unchanged.
- **Terminal notification path**: unchanged.
- **Exception path**: none planned.
## Provider Boundary & Portability Fit
- **Shared provider/platform boundary touched?**: yes, for provider connection/resource/readiness authorization proof.
- **Provider-owned seams**: provider connection credentials/readiness/permissions details.
- **Platform-core seams**: workspace/environment authorization, operations, evidence, audit, capabilities, system/admin planes.
- **Neutral platform terms / contracts preserved**: workspace, managed environment, provider connection, operation, evidence, audit, capability.
- **Retained provider-specific semantics and why**: Microsoft/Graph/Entra terms remain only where existing provider-owned implementation uses them.
- **Bounded extraction or follow-up path**: none; provider productization is a later candidate if proof reveals UX friction rather than auth defect.
## Constitution Check
- Inventory-first: PASS planned. Authorization proof inspects existing inventory/resource truth and does not alter external truth.
- Read/write separation: PASS planned. Any touched mutating action keeps server authorization, confirmation where high-impact/destructive, audit, and tests.
- Graph contract path: PASS planned. No new Graph calls.
- Deterministic capabilities: PASS planned. Use existing capability resolvers and registries.
- RBAC-UX: PASS planned. Admin `/admin` and system `/system` planes remain separate; non-member/wrong-scope access deny-as-not-found; missing capability forbidden at execution level.
- Workspace isolation: PASS planned. Cross-workspace direct access tests are required.
- Tenant isolation: PASS planned. ManagedEnvironment-scoped resources must remain workspace/environment safe.
- Run observability: PASS planned. Existing OperationRun behavior only.
- OperationRun start UX: PASS planned. No new local start UX.
- Data minimization: PASS planned. No secrets/raw provider payloads in reports/tests.
- Test governance: PASS planned. Confidence/browser lanes are explicit; heavy-governance cost remains visible if used.
- Proportionality: PASS planned. Matrix/report is review evidence, not runtime framework.
- No premature abstraction: PASS planned. No new helper unless spec/plan is updated.
- Persisted truth: PASS. No new persistence.
- Behavioral state: PASS. No new states.
- UI semantics: PASS. No new presentation taxonomy.
- Shared pattern first: PASS. Existing authorization helpers preferred.
- Provider boundary: PASS. Provider-specific semantics stay bounded.
- V1 explicitness / few layers: PASS. Direct tests and targeted hardening only.
- Spec discipline / bloat check: PASS. One coherent authorization proof spec rather than many micro-specs.
- Filament-native UI: PASS planned. Existing Filament authorization/action patterns preserved.
- UI/Productization coverage: PASS planned. Existing-surface authorization hardening only.
- Product Surface Contract Gate: PASS planned. Spec/plan/tasks name no-legacy, UI impact, browser proof, human sanity, global search, destructive/high-impact actions, and close-out fields.
## Test Governance Check
- **Test purpose / classification by changed surface**: Policy/Gate for authorization decisions; Feature/Filament for resources/actions/relation managers; Browser for representative rendered proof; Heavy-Governance only for broad matrix/discovery guard.
- **Affected validation lanes**: confidence, browser, optional heavy-governance.
- **Why this lane mix is the narrowest sufficient proof**: resource authorization cannot be proven by unit tests only; browser proof is limited to representative high-risk paths.
- **Narrowest proving command(s)**:
- `cd apps/platform && ./vendor/bin/sail artisan test --filter=Policy`
- `cd apps/platform && ./vendor/bin/sail artisan test --filter=Authorization`
- `cd apps/platform && ./vendor/bin/sail artisan test --filter=Capability`
- `cd apps/platform && ./vendor/bin/sail artisan test --filter=Filament`
- `cd apps/platform && ./vendor/bin/sail artisan test --filter=Resource`
- `cd apps/platform && ./vendor/bin/sail artisan test --filter=System`
- targeted Spec 402 test files
- focused Spec 402 browser smoke if browser test support is available
- `git diff --check`
- conditional project formatter check for changed PHP runtime/test files
- report/test/log redaction check for secrets, tokens, raw credential payloads, and sensitive raw provider payloads
- **Fixture / helper / factory / seed / context cost risks**: workspace/environment/user/platform-user setup; keep helpers existing or opt-in.
- **Expensive defaults or shared helper growth introduced?**: no by default.
- **Heavy-family additions, promotions, or visibility changes**: none planned except explicit matrix/discovery guard if implementation chooses it.
- **Surface-class relief / special coverage rule**: standard-native-filament for ordinary resource pages; special coverage for global-context-shell and system-admin boundary.
- **Closing validation and reviewer handoff**: implementation report records command results, lane fit, browser proof, and residual findings.
- **Budget / baseline / trend follow-up**: none expected; document any material test runtime growth.
- **Review-stop questions**: Does every fixed gap have a negative test? Did any policy duplicate capability logic? Did relation/search/bulk proof cover direct access? Did `/system` remain platform-only?
- **Escalation path**: document-in-feature by default; follow-up-spec for structural unresolved authorization decisions; reject-or-split for scope creep.
- **Active feature PR close-out entry**: `Guardrail / Exception / Smoke Coverage`.
- **Why no dedicated follow-up spec is needed**: this spec itself is the bounded authorization proof package; only remaining P0/P1 blockers require a remediation spec.
## Project Structure
### Documentation (this feature)
```text
specs/402-resource-policy-authorization-proof-matrix/
├── spec.md
├── plan.md
├── tasks.md
├── checklists/
│ └── requirements.md
└── implementation-report.md # created during implementation
```
### Source Code (repository root)
Implementation may inspect and, if required by confirmed gaps, minimally edit:
```text
apps/platform/app/Filament/Resources/
apps/platform/app/Filament/Pages/
apps/platform/app/Filament/System/Pages/
apps/platform/app/Http/Controllers/
apps/platform/app/Http/Middleware/
apps/platform/app/Policies/
apps/platform/app/Providers/AuthServiceProvider.php
apps/platform/app/Providers/AppServiceProvider.php
apps/platform/app/Services/Auth/
apps/platform/app/Support/Auth/
apps/platform/app/Support/Rbac/
apps/platform/routes/web.php
apps/platform/tests/
```
**Structure Decision**: Use the existing Laravel monolith structure. Do not create new base folders or new runtime packages. Add tests under existing domain folders or focused `Spec402...` files.
## Complexity Tracking
| Violation | Why Needed | Simpler Alternative Rejected Because |
|---|---|---|
| Spec-local authorization matrix/report | Required to prove fragmented resource authorization across admin/system panels | Blind policy generation or local fixes would not prove relation/search/bulk/direct/system boundaries |
| Focused browser proof | Required because UI-hidden/disabled state and panel separation are rendered behavior | Feature tests alone cannot prove representative browser/Filament runtime behavior |
No runtime abstraction, persisted truth, enum/status family, or UI framework is planned.
## Implementation Phases
### Phase 1 - Baseline and inventory
Run required dirty-state commands, inspect panels/resources/routes/policies/gates/tests, and build the internal inventory. No edits before this phase is complete.
### Phase 2 - Resource authorization matrix
Create the implementation-report matrix before adding policies or hardening code. Include all columns required by the spec.
### Phase 3 - Gap classification
Classify each gap as missing proof only, sufficient gate/capability without policy, missing policy and insufficient path, UI/execution inconsistency, scope risk, system/admin boundary risk, global-search risk, relation/bulk risk, or product-decision required.
### Phase 4 - Tests first for high-risk gaps
Add or update negative tests for direct access, action execution, cross-workspace denial, system/admin separation, global search, relation managers, and bulk actions before runtime hardening when feasible.
### Phase 5 - Minimal hardening
Only after matrix and tests, apply the smallest safe fix: policy class, policy registration, action-level authorization, search disable/restrict, bulk/relation scoping, controller authorization, or documented exception.
### Phase 6 - Focused browser proof
Run a representative browser smoke for allowed admin access, cross-workspace denial, system-only denial to workspace admin, and unauthorized high-impact action visibility/execution. Global-search posture may remain feature-level proof when exercising the search UI would turn the focused smoke into a broader browser audit.
### Phase 7 - Implementation report and validation
Complete `implementation-report.md`, classify remaining findings, run targeted validation, record dirty state, and recommend PASS/PASS WITH CONDITIONS/FAIL.
## Risk Controls
- Stop and update spec/plan before introducing new roles, capabilities, product surfaces, database changes, or a shared authorization framework.
- Treat missing product semantics as `DEFERRED: product decision required`.
- Preserve completed specs and historical close-out evidence.
- Do not conflate UI visibility with execution authorization.
- Do not treat global search as safe unless scoped and tested.
- Do not count route middleware alone as record-level authorization proof.
## Rollout Considerations
- Staging: run targeted authorization tests and browser proof before merge.
- Production: no migrations or env changes expected. If authorization hardening changes access outcomes, release notes should mention stricter authorization enforcement.
- Queues/scheduler/storage/assets: no expected impact.
- `filament:assets`: no new requirement unless unexpected asset registration occurs, which is out of scope.
## Candidate Readiness
- Candidate Selection Gate: planned PASS because the operator explicitly promoted Spec 402, no existing spec package existed, and the scope is bounded to authorization proof/hardening.
- Spec Readiness Gate: should pass when `spec.md`, `plan.md`, `tasks.md`, and `checklists/requirements.md` are complete, placeholders are removed, and preparation analysis finds no blocking artifact drift.