Implements Spec 090 (Action Surface Contract Compliance & RBAC Hardening). Highlights: - Adds/updates action surface declarations and shrinks baseline exemptions. - Standardizes Filament action grouping/order and empty-state CTAs. - Enforces RBAC UX semantics (non-member -> 404, member w/o capability -> disabled + tooltip, server-side 403). - Adds audit logging for successful side-effect actions. - Fixes Provider Connections list context so header create + row actions resolve tenant correctly. Tests (focused): - vendor/bin/sail artisan test --compact tests/Feature/090/ - vendor/bin/sail artisan test --compact tests/Feature/Guards/ActionSurfaceContractTest.php - vendor/bin/sail bin pint --dirty Livewire/Filament: - Filament v5 + Livewire v4 compliant. - No panel provider registration changes (Laravel 11+ registration remains in bootstrap/providers.php). Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #108
196 lines
7.8 KiB
Markdown
196 lines
7.8 KiB
Markdown
# 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 repo’s **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 0–1 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`.
|