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

17 KiB

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.

  • 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
  • T002 [P] Create Eloquent model scaffolding for the new domain in app/Models/FindingException.php, app/Models/FindingExceptionDecision.php, and app/Models/FindingExceptionEvidenceReference.php
  • 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.

  • T004 Register exception capabilities and role mappings in app/Support/Auth/Capabilities.php, app/Services/Auth/RoleCapabilityMap.php, and app/Services/Auth/WorkspaceRoleCapabilityMap.php
  • 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
  • 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
  • T007 Implement the shared exception lifecycle service and validity resolver skeleton in app/Services/Findings/FindingExceptionService.php and app/Services/Findings/FindingRiskGovernanceResolver.php
  • 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
  • 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

  • T010 [P] [US1] Add request, approve, and reject feature coverage in tests/Feature/Findings/FindingExceptionWorkflowTest.php
  • T011 [P] [US1] Add positive and negative authorization coverage for request and approval flows in tests/Feature/Findings/FindingExceptionAuthorizationTest.php
  • 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

  • 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
  • T014 [US1] Integrate approved and rejected exception outcomes with finding status mutation rules in app/Services/Findings/FindingWorkflowService.php and app/Models/Finding.php
  • 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
  • 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

  • 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
  • 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
  • T019 [P] [US2] Add badge and validity-mapping unit coverage in tests/Unit/Findings/FindingExceptionBadgeTest.php

Implementation for User Story 2

  • 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
  • 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
  • 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
  • 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

  • T024 [P] [US3] Add renewal and revocation feature coverage in tests/Feature/Findings/FindingExceptionRenewalTest.php and tests/Feature/Findings/FindingExceptionRevocationTest.php
  • 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

  • T026 [US3] Implement renewal and revocation lifecycle behavior in app/Services/Findings/FindingExceptionService.php, app/Models/FindingException.php, and app/Models/FindingExceptionDecision.php
  • 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
  • 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
  • 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

  • T030 [P] [US4] Add governance-drift and finding-lifecycle-change coverage for finding detail and register warnings in tests/Feature/Findings/FindingRiskGovernanceProjectionTest.php
  • 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

  • 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
  • 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
  • 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.

  • 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
  • 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
  • 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

# 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.