TenantAtlas/specs/154-finding-risk-acceptance/tasks.md
ahmido b1e1e06861 feat: implement finding risk acceptance lifecycle (#184)
## Summary
- add a first-class finding exception domain with request, approval, rejection, renewal, and revocation lifecycle support
- add tenant-scoped exception register, finding governance surfaces, and a canonical workspace approval queue in Filament
- add audit, badge, evidence, and review-pack integrations plus focused Pest coverage for workflow, authorization, and governance validity

## Validation
- vendor/bin/sail bin pint --dirty --format agent
- CI=1 vendor/bin/sail artisan test --compact
- manual integrated-browser smoke test for the request-exception happy path, tenant register visibility, and canonical queue visibility

## Notes
- Filament implementation remains on v5 with Livewire v4-compatible surfaces
- canonical queue lives in the admin panel; provider registration stays in bootstrap/providers.php
- finding exceptions stay out of global search in this rollout

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #184
2026-03-20 01:07:55 +00:00

206 lines
17 KiB
Markdown

# Tasks: Finding Risk Acceptance Lifecycle
**Input**: Design documents from `/specs/154-finding-risk-acceptance/`
**Prerequisites**: plan.md, spec.md, research.md, data-model.md, contracts/, quickstart.md
**Tests**: Tests are REQUIRED for this feature because it changes runtime behavior, authorization, auditability, and tenant-scoped governance workflows.
**Operations**: This feature intentionally keeps request, approval, rejection, renewal, and revocation as security-relevant DB-only actions without `OperationRun`; tasks therefore enforce `AuditLog` coverage instead of an operations progress workflow.
**RBAC**: This feature introduces authorization changes and MUST enforce canonical capability registry usage, 404 vs 403 semantics, cross-plane deny-as-not-found behavior, and positive/negative authorization tests.
**Filament UI**: This feature adds and modifies Filament Resource and Page surfaces, so tasks include Action Surface Contract, BADGE-001, and UX-001 enforcement work.
## Phase 1: Setup (Shared Infrastructure)
**Purpose**: Create the core schema and file scaffolding needed for all stories.
- [X] T001 Create exception schema migrations in `database/migrations/2026_03_19_000001_create_finding_exceptions_table.php`, `database/migrations/2026_03_19_000002_create_finding_exception_decisions_table.php`, and `database/migrations/2026_03_19_000003_create_finding_exception_evidence_references_table.php`
- [X] T002 [P] Create Eloquent model scaffolding for the new domain in `app/Models/FindingException.php`, `app/Models/FindingExceptionDecision.php`, and `app/Models/FindingExceptionEvidenceReference.php`
- [X] T003 [P] Create Filament surface scaffolding in `app/Filament/Resources/FindingExceptionResource.php`, `app/Filament/Resources/FindingExceptionResource/Pages/ListFindingExceptions.php`, `app/Filament/Resources/FindingExceptionResource/Pages/ViewFindingException.php`, and `app/Filament/Pages/Monitoring/FindingExceptionsQueue.php`
---
## Phase 2: Foundational (Blocking Prerequisites)
**Purpose**: Establish the shared domain, authorization, audit, and navigation infrastructure before any user-story slice is implemented.
**⚠️ CRITICAL**: No user story work should begin until this phase is complete.
- [X] T004 Register exception capabilities and role mappings in `app/Support/Auth/Capabilities.php`, `app/Services/Auth/RoleCapabilityMap.php`, and `app/Services/Auth/WorkspaceRoleCapabilityMap.php`
- [X] T005 Implement policy and entitlement enforcement for tenant and canonical exception access in `app/Policies/FindingExceptionPolicy.php`, `app/Providers/Filament/AdminPanelProvider.php`, and `app/Providers/Filament/TenantPanelProvider.php`
- [X] T006 [P] Add shared audit action IDs, summaries, and related-navigation hooks in `app/Support/Audit/AuditActionId.php`, `app/Support/Navigation/RelatedNavigationResolver.php`, and `app/Services/Intune/AuditLogger.php`
- [X] T007 Implement the shared exception lifecycle service and validity resolver skeleton in `app/Services/Findings/FindingExceptionService.php` and `app/Services/Findings/FindingRiskGovernanceResolver.php`
- [X] T008 Wire domain relationships and tenant-owned query behavior in `app/Models/Finding.php`, `app/Models/FindingException.php`, `app/Models/FindingExceptionDecision.php`, and `app/Models/FindingExceptionEvidenceReference.php`
- [X] T009 [P] Add foundational schema, policy, and model regression coverage in `tests/Unit/Findings/FindingExceptionModelTest.php` and `tests/Feature/Findings/FindingExceptionPolicyTest.php`
**Checkpoint**: Foundation ready. User story work can now proceed.
---
## Phase 3: User Story 1 - Propose And Approve A Time-Bounded Risk Acceptance (Priority: P1) 🎯 MVP
**Goal**: Allow tenant managers to request risk acceptance for a finding and route it through explicit approval or rejection.
**Independent Test**: Create a finding, submit an exception request with justification and review timing, approve or reject it as an authorized approver, and verify correct finding governance state plus 404/403 authorization behavior.
### Tests for User Story 1
- [X] T010 [P] [US1] Add request, approve, and reject feature coverage in `tests/Feature/Findings/FindingExceptionWorkflowTest.php`
- [X] T011 [P] [US1] Add positive and negative authorization coverage for request and approval flows in `tests/Feature/Findings/FindingExceptionAuthorizationTest.php`
- [X] T012 [P] [US1] Add lifecycle transition, blocked self-approval, and overlapping-request rejection unit coverage in `tests/Unit/Findings/FindingExceptionServiceTest.php`
### Implementation for User Story 1
- [X] T013 [US1] Implement request, approve, and reject lifecycle transitions, blocked self-approval, overlapping-request guards, and append-only decision persistence in `app/Services/Findings/FindingExceptionService.php` and `app/Models/FindingExceptionDecision.php`
- [X] T014 [US1] Integrate approved and rejected exception outcomes with finding status mutation rules in `app/Services/Findings/FindingWorkflowService.php` and `app/Models/Finding.php`
- [X] T015 [US1] Add request, approve, and reject forms and actions to the finding detail and canonical queue in `app/Filament/Resources/FindingResource.php`, `app/Filament/Resources/FindingResource/Pages/ViewFinding.php`, and `app/Filament/Pages/Monitoring/FindingExceptionsQueue.php`
- [X] T016 [US1] Persist request, approval, and rejection audit history with summary-first metadata in `app/Support/Audit/AuditActionId.php`, `app/Support/Audit/AuditContextSanitizer.php`, and `app/Services/Intune/AuditLogger.php`
**Checkpoint**: User Story 1 is independently functional and demonstrates the MVP governance workflow.
---
## Phase 4: User Story 2 - See Whether Accepted Risk Is Still Valid (Priority: P1)
**Goal**: Provide tenant and canonical views that show pending, active, expiring, expired, rejected, and revoked exceptions without leaking unauthorized tenant data.
**Independent Test**: Seed exception records in multiple lifecycle states and verify tenant and canonical views show correct state, timing, owners, and filters only for entitled tenants.
### Tests for User Story 2
- [X] T017 [P] [US2] Add tenant register and finding-detail coverage for lifecycle-state visibility, passive expiry reminders, actor-specific visibility, empty states, and filters in `tests/Feature/Findings/FindingExceptionRegisterTest.php` and `tests/Feature/Findings/FindingRiskGovernanceProjectionTest.php`
- [X] T018 [P] [US2] Add canonical queue and exception-detail coverage for tenant-safe filtering, passive expiry reminders, and entitled actor visibility in `tests/Feature/Monitoring/FindingExceptionsQueueTest.php` and `tests/Feature/Findings/FindingExceptionAuthorizationTest.php`
- [X] T019 [P] [US2] Add badge and validity-mapping unit coverage in `tests/Unit/Findings/FindingExceptionBadgeTest.php`
### Implementation for User Story 2
- [X] T020 [US2] Implement the tenant exception register, exception detail, and finding-detail reminder surfaces, including actor-specific passive reminder visibility, header actions, and the documented v1 bulk-action exemption, in `app/Filament/Resources/FindingExceptionResource.php`, `app/Filament/Resources/FindingExceptionResource/Pages/ListFindingExceptions.php`, `app/Filament/Resources/FindingExceptionResource/Pages/ViewFindingException.php`, `app/Filament/Resources/FindingResource.php`, and `app/Filament/Resources/FindingResource/Pages/ViewFinding.php`
- [X] T021 [US2] Implement canonical queue filters, passive expiry reminders, header actions, empty states, documented v1 bulk-action exemption, and entitled tenant prefilter behavior in `app/Filament/Pages/Monitoring/FindingExceptionsQueue.php`
- [X] T022 [US2] Add centralized exception-state and validity badges in `app/Support/Badges/BadgeDomain.php`, `app/Support/Badges/Domains/FindingExceptionStatusBadge.php`, and `app/Support/Badges/Domains/FindingRiskGovernanceValidityBadge.php`
- [X] T023 [US2] Add exception filter catalog entries and related navigation affordances in `app/Support/Filament/FilterOptionCatalog.php` and `app/Support/Navigation/RelatedNavigationResolver.php`
**Checkpoint**: User Story 2 is independently functional and can be demonstrated with seeded exception records even without renewal or downstream consumer work.
---
## Phase 5: User Story 3 - Renew Or Revoke An Accepted Risk With Audit Evidence (Priority: P2)
**Goal**: Support renewal and revocation with preserved decision history and structured evidence references.
**Independent Test**: Renew an active exception with updated evidence references, revoke another one, and verify history remains append-only and intelligible.
### Tests for User Story 3
- [X] T024 [P] [US3] Add renewal and revocation feature coverage in `tests/Feature/Findings/FindingExceptionRenewalTest.php` and `tests/Feature/Findings/FindingExceptionRevocationTest.php`
- [X] T025 [P] [US3] Add append-only decision and evidence-reference unit coverage in `tests/Unit/Findings/FindingExceptionDecisionTest.php` and `tests/Unit/Findings/FindingExceptionEvidenceReferenceTest.php`
### Implementation for User Story 3
- [X] T026 [US3] Implement renewal and revocation lifecycle behavior in `app/Services/Findings/FindingExceptionService.php`, `app/Models/FindingException.php`, and `app/Models/FindingExceptionDecision.php`
- [X] T027 [US3] Persist and render structured evidence references in `app/Models/FindingExceptionEvidenceReference.php`, `app/Filament/Resources/FindingExceptionResource.php`, and `app/Filament/Resources/FindingExceptionResource/Pages/ViewFindingException.php`
- [X] T028 [US3] Add renew and revoke actions to tenant and canonical surfaces in `app/Filament/Resources/FindingResource.php`, `app/Filament/Resources/FindingResource/Pages/ViewFinding.php`, and `app/Filament/Pages/Monitoring/FindingExceptionsQueue.php`
- [X] T029 [US3] Extend audit summaries and sanitization for renewal, revocation, and linked evidence metadata in `app/Support/Audit/AuditActionId.php`, `app/Support/Audit/AuditContextSanitizer.php`, and `app/Services/Intune/AuditLogger.php`
**Checkpoint**: User Story 3 is independently functional and preserves exception history without overwriting earlier decisions.
---
## Phase 6: User Story 4 - Detect Governance Drift In Accepted-Risk Findings (Priority: P2)
**Goal**: Surface findings that look risk-accepted but are not backed by a currently valid exception, and ensure downstream consumers count only valid governed exceptions.
**Independent Test**: Seed findings with valid, expired, revoked, rejected, and missing exception states and verify only valid ones count as active accepted risk in finding detail and downstream evidence/reporting summaries.
### Tests for User Story 4
- [X] T030 [P] [US4] Add governance-drift and finding-lifecycle-change coverage for finding detail and register warnings in `tests/Feature/Findings/FindingRiskGovernanceProjectionTest.php`
- [X] T031 [P] [US4] Add evidence and review-pack downstream validity coverage in `tests/Feature/Evidence/ExceptionValidityEvidenceIntegrationTest.php` and `tests/Feature/ReviewPack/ReviewPackValidRiskAcceptanceTest.php`
### Implementation for User Story 4
- [X] T032 [US4] Implement validity projection, warning-state resolution, and history-preserving behavior for resolved, closed, reopened, and severity-changed findings in `app/Services/Findings/FindingRiskGovernanceResolver.php`, `app/Models/FindingException.php`, and `app/Models/Finding.php`
- [X] T033 [US4] Surface missing, expired, and revoked governance warnings in `app/Filament/Resources/FindingResource.php`, `app/Filament/Resources/FindingResource/Pages/ViewFinding.php`, and `app/Filament/Resources/FindingExceptionResource.php`
- [X] T034 [US4] Update downstream evidence and review-pack consumers to count only valid governed exceptions in `app/Services/Evidence/EvidenceSnapshotService.php`, `app/Jobs/GenerateReviewPackJob.php`, and `app/Services/ReviewPackService.php`
**Checkpoint**: User Story 4 is independently functional and proves that accepted-risk reporting depends on valid exception governance rather than finding status alone.
---
## Phase 7: Polish & Cross-Cutting Concerns
**Purpose**: Finalize cross-story safeguards, UI contract enforcement, and quickstart validation.
- [X] T035 [P] Update Filament action-surface guard coverage for the new exception surfaces, including the documented v1 bulk-action exemptions, and refresh badge guard coverage in `tests/Feature/Guards/ActionSurfaceContractTest.php` and `tests/Feature/Guards/NoAdHocStatusBadgesTest.php`
- [X] T036 [P] Tighten tenant-owned query and cross-tenant leakage guards for the new domain in `tests/Feature/Guards/TenantOwnedQueryGuardTest.php` and `tests/Feature/Findings/FindingExceptionAuthorizationTest.php`
- [X] T037 Validate the quickstart scenarios, passive reminder visibility, actor-specific visibility matrix, and timed success-criteria walkthroughs against focused Pest packs in `specs/154-finding-risk-acceptance/quickstart.md`, `tests/Feature/Findings/FindingExceptionWorkflowTest.php`, `tests/Feature/Findings/FindingExceptionRegisterTest.php`, `tests/Feature/Findings/FindingRiskGovernanceProjectionTest.php`, `tests/Feature/Monitoring/FindingExceptionsQueueTest.php`, and `tests/Feature/ReviewPack/ReviewPackValidRiskAcceptanceTest.php`
---
## Dependencies & Execution Order
### Phase Dependencies
- **Setup (Phase 1)**: No dependencies; starts immediately.
- **Foundational (Phase 2)**: Depends on Setup completion; blocks all user stories.
- **User Story 1 (Phase 3)**: Depends on Foundational completion; recommended MVP slice.
- **User Story 2 (Phase 4)**: Depends on Foundational completion; integrates best after User Story 1 because canonical queue actions reuse approval handlers.
- **User Story 3 (Phase 5)**: Depends on Foundational completion and User Story 1 lifecycle foundations.
- **User Story 4 (Phase 6)**: Depends on Foundational completion and benefits from User Stories 1 and 3 because validity projection relies on complete exception lifecycle states.
- **Polish (Phase 7)**: Depends on all desired user stories being complete.
### User Story Dependencies
- **US1**: No dependency on other user stories after Foundational; this is the MVP.
- **US2**: Can be viewed with seeded data after Foundational, but approval queue actions are most complete after US1.
- **US3**: Depends on US1 because renewal and revocation extend the primary exception lifecycle.
- **US4**: Depends on US1 for valid governance semantics and on US3 for renewal/revocation edge states.
### Within Each User Story
- Write tests before the corresponding implementation tasks and confirm they fail first.
- Complete service and model behavior before Filament action wiring.
- Complete audit and authorization enforcement before closing the story.
### Parallel Opportunities
- `T002` and `T003` can run in parallel after `T001`.
- `T006` and `T009` can run in parallel once `T004` and `T005` establish the authorization baseline.
- In each story, the `[P]` test tasks can run in parallel.
- `T022` and `T023` can run in parallel during US2 after list/detail surfaces exist.
- `T035` and `T036` can run in parallel in the polish phase.
---
## Parallel Example: User Story 1
```bash
# Run the User Story 1 tests in parallel:
Task: "Add request, approve, and reject feature coverage in tests/Feature/Findings/FindingExceptionWorkflowTest.php"
Task: "Add positive and negative authorization coverage for request and approval flows in tests/Feature/Findings/FindingExceptionAuthorizationTest.php"
Task: "Add lifecycle transition, blocked self-approval, and overlapping-request rejection unit coverage in tests/Unit/Findings/FindingExceptionServiceTest.php"
# Then implement the shared lifecycle and UI wiring in sequence:
Task: "Implement request, approve, and reject lifecycle transitions plus append-only decision persistence in app/Services/Findings/FindingExceptionService.php and app/Models/FindingExceptionDecision.php"
Task: "Integrate approved and rejected exception outcomes with finding status mutation rules in app/Services/Findings/FindingWorkflowService.php and app/Models/Finding.php"
Task: "Add request, approve, and reject forms and actions to the finding detail and canonical queue in app/Filament/Resources/FindingResource.php, app/Filament/Resources/FindingResource/Pages/ViewFinding.php, and app/Filament/Pages/Monitoring/FindingExceptionsQueue.php"
```
---
## Implementation Strategy
### MVP First
1. Complete Phase 1 and Phase 2.
2. Deliver User Story 1 as the MVP: request, approve, reject, audit, and correct authorization semantics.
3. Validate that the core governance gap is closed before expanding read models and downstream consumers.
### Incremental Delivery
1. Add User Story 2 to make governance state visible and operable across tenant and canonical views.
2. Add User Story 3 for renewal and revocation once the core approval lifecycle is stable.
3. Add User Story 4 to tighten downstream validity semantics and governance-drift reporting.
### Suggested MVP Scope
- **Recommended MVP**: Phases 1-3 only.
- **Why**: This yields the minimum coherent business value by turning `risk_accepted` from a bare status into a governed, approved, auditable exception workflow.