TenantAtlas/specs/090-action-surface-contract-compliance/plan.md
2026-02-13 02:29:38 +01:00

196 lines
7.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Implementation Plan: Action Surface Contract Compliance & RBAC Hardening (Spec 090)
**Branch**: `090-action-surface-contract-compliance` | **Date**: 2026-02-12 | **Spec**: `specs/090-action-surface-contract-compliance/spec.md`
**Input**: Feature specification from `specs/090-action-surface-contract-compliance/spec.md`
## Summary
Bring a focused set of Filament v5 action surfaces into compliance with the repos **Filament UI Action Surface Contract**, and harden RBAC semantics using the existing enforcement helpers.
This work primarily:
- Shrinks `ActionSurfaceExemptions::baseline()` for the in-scope components.
- Adds `actionSurfaceDeclaration()` to those components (or explicit exemptions with reasons).
- Standardizes action ordering/grouping (“View → Edit → More → Destructive last”; max 2 visible row actions).
- Ensures **successful** side-effect actions create `AuditLog` entries.
## Technical Context
**Language/Version**: PHP 8.4.15
**Framework**: Laravel 12
**Admin UI**: Filament v5 + Livewire v4.0+
**Storage**: PostgreSQL (Sail)
**Testing**: Pest v4 (`vendor/bin/sail artisan test`)
**Target Platform**: Docker/Sail local; Dokploy staging/prod
**Project Type**: Laravel monolith
**Performance Goals**: Keep “start” surfaces enqueue-only; preserve guard test runtime
**Constraints**:
- No new dependencies
- BackupSchedule retention is explicitly deferred
- Use existing RBAC + audit primitives; no new tables
**Scale/Scope**: Multi-tenant admin UI; targeted subset of Resources/Pages
## Constitution Check
*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*
- ✅ Filament v5 targets Livewire v4.0+ (no Livewire v3)
- ✅ Authorization is enforced server-side (UI visibility is not security)
- ✅ RBAC-UX semantics: non-member → 404; member missing capability → 403 (and disabled + tooltip in UI)
- ✅ Destructive actions execute via `->action(...)` and include `->requiresConfirmation()`
- ✅ Action Surface Contract enforced via guard tests; exemptions must be explicit and minimized
- ✅ Audit logs for successful side-effect actions (per spec clarification)
## Project Structure
### Documentation (this feature)
```text
specs/090-action-surface-contract-compliance/
├── spec.md
├── plan.md
├── research.md
├── data-model.md
├── quickstart.md
└── contracts/
└── action-surface-contract-v1.openapi.yaml
```
### Source Code (relevant to this spec)
```text
app/
├── Filament/Resources/
│ ├── ProviderConnectionResource.php
│ ├── BackupScheduleResource.php
│ ├── FindingResource.php
│ ├── TenantResource.php
│ ├── PolicyResource/Pages/ListPolicies.php
│ └── PolicyResource/Pages/ViewPolicy.php
├── Filament/Resources/Workspaces/WorkspaceResource.php
├── Support/Rbac/UiEnforcement.php
├── Support/Rbac/WorkspaceUiEnforcement.php
└── Support/Ui/ActionSurface/
├── ActionSurfaceDeclaration.php
└── ActionSurfaceExemptions.php
tests/Feature/Guards/
├── ActionSurfaceContractTest.php
└── ActionSurfaceValidatorTest.php
```
**Structure Decision**: Laravel monolith; modifications are limited to existing Filament resources/pages + guard tests.
## Phase 0 — Outline & Research (DOCS COMPLETE)
Completed in `specs/090-action-surface-contract-compliance/research.md`.
Key findings:
- Action Surface Contract enforcement already exists via guard tests and `ActionSurfaceDeclaration`.
- Many in-scope resources are currently excluded by `ActionSurfaceExemptions::baseline()`.
- RBAC enforcement helpers exist and already implement 404/403 semantics: `UiEnforcement`, `WorkspaceUiEnforcement`.
- Audit logging services exist and sanitize metadata.
## Phase 1 — Design & Contracts (DOCS COMPLETE)
Outputs:
- `data-model.md`: No schema changes required.
- `contracts/action-surface-contract-v1.openapi.yaml`: Internal contract artifact (no new HTTP endpoints).
- `quickstart.md`: Local verification commands and checklist.
Design choices:
- “View” requirement is interpreted as an **inspection affordance** (clickable row, primary linked column, or explicit View action) consistent with the constitution.
- Audit logs are required for successful dispatch/execution surfaces only.
- Directory groups (Entra groups) and inventory items already follow the inspection-affordance pattern (clickable rows) and have explicit declarations; they are verification-only in this spec to avoid expanding scope.
Note: Phases 01 are complete for documentation and design artifacts. Implementation and verification work begins in Phase 2 and is tracked in `specs/090-action-surface-contract-compliance/tasks.md`.
## Phase 2 — Implementation Plan
### Step 1 — Make contract guard the primary gate
Target guard tests:
- `tests/Feature/Guards/ActionSurfaceContractTest.php`
- `tests/Feature/Guards/ActionSurfaceValidatorTest.php`
Workflow:
1) Add `actionSurfaceDeclaration()` to one component.
2) Remove its baseline exemption.
3) Run guard tests.
4) Repeat.
### Step 2 — Shrink baseline exemptions
File: `app/Support/Ui/ActionSurface/ActionSurfaceExemptions.php`
Remove baseline exemptions for components once they have declarations:
- `ProviderConnectionResource`
- `BackupScheduleResource`
- `FindingResource`
- `TenantResource`
- `Workspaces/WorkspaceResource`
### Step 3 — Add action surface declarations (per component)
Add `actionSurfaceDeclaration()` and ensure required slots are satisfied.
Expected profile direction (final selection should match existing profiles in the repo):
- CRUD list + inspect + edit: use a CRUD-capable profile; keep row actions to 2 max.
- List-only read-only resources should use a read-only profile (already in repo patterns).
### Step 4 — Fix known hotspots
#### (P1) Policy: Capture snapshot dispatch
File: `app/Filament/Resources/PolicyResource/Pages/ViewPolicy.php`
- Wrap action with `UiEnforcement::forAction(...)` using the canonical capability.
- Ensure the server-side `before(...)` aborts with 404/403 appropriately.
- Add audit logging on successful dispatch via `App\Services\Intune\AuditLogger`.
#### (P1) Policy: Sync action confirmation semantics
File: `app/Filament/Resources/PolicyResource/Pages/ListPolicies.php`
- Remove misuse of `destructive()` for non-destructive sync/run actions.
- Keep confirmation if required, but with non-destructive semantics.
#### (P2) Findings: action ordering + grouping
File: `app/Filament/Resources/FindingResource.php`
- Ensure `View` is first.
- Move secondary actions (like acknowledge) into `More`.
- Ensure bulk actions are grouped and capability gated via `UiEnforcement`.
#### (P2/P3) Backup schedules: empty-state CTA + grouping
File: `app/Filament/Resources/BackupScheduleResource.php`
- Ensure empty-state action exists (create) and is capability gated.
- Ensure “run now / retry” actions are gated and audited (audit already exists for manual dispatch; verify consistency).
#### (P1/P2) Tenant + Workspaces: RBAC semantics + bulk grouping
Files:
- `app/Filament/Resources/TenantResource.php`
- `app/Filament/Resources/Workspaces/WorkspaceResource.php`
Ensure:
- Destructive actions are last and confirmed.
- Bulk actions are grouped under a consistent `More` group.
- Workspaces use `WorkspaceUiEnforcement` + `WorkspaceAuditLogger` for workspace-scoped side effects.
### Step 5 — Testing plan
Minimum programmatic verification:
- Guard tests stay green as exemptions shrink.
- Add or extend focused Pest feature tests for:
- 404 vs 403 RBAC semantics for at least one representative mutation action.
- Successful audit log creation for at least one enqueue/dispatch surface.
### Step 6 — Formatting
Run formatter before final handoff:
- `vendor/bin/sail bin pint --dirty`
## Deploy / Ops Notes
- No migrations expected.
- No new Filament assets expected; if any assets are registered, ensure deploy runs `php artisan filament:assets`.