create(); createUserWithTenant(tenant: $tenant, user: $approver, role: 'owner', workspaceRole: 'manager'); $finding = Finding::factory()->for($tenant)->create([ 'status' => Finding::STATUS_RISK_ACCEPTED, ]); /** @var FindingExceptionService $service */ $service = app(FindingExceptionService::class); $requested = $service->request($finding, $tenant, $requester, [ 'owner_user_id' => (int) $requester->getKey(), 'request_reason' => 'Temporary exception while remediation is scheduled.', 'review_due_at' => now()->addDays(5)->toDateTimeString(), 'expires_at' => now()->addDays(30)->toDateTimeString(), 'evidence_references' => [ [ 'label' => 'Initial review note', 'source_type' => 'review_pack', 'source_id' => 'rp-initial', 'source_fingerprint' => 'fp-initial', 'measured_at' => now()->subDay()->toDateTimeString(), ], ], ]); $service->approve($requested, $approver, [ 'effective_from' => now()->subDay()->toDateTimeString(), 'expires_at' => now()->addDays(30)->toDateTimeString(), 'approval_reason' => 'Approved with compensating controls.', ]); $this->actingAs($requester); Filament::setTenant($tenant, true); Livewire::test(ViewFinding::class, ['record' => $finding->getKey()]) ->assertActionVisible('revoke_exception') ->callAction('revoke_exception', data: [ 'revocation_reason' => 'Compensating controls no longer exist in production.', ]) ->assertHasNoActionErrors() ->assertNotified('Exception revoked'); $revoked = FindingException::query() ->with(['currentDecision', 'decisions', 'evidenceReferences']) ->where('finding_id', (int) $finding->getKey()) ->firstOrFail(); expect($revoked->status)->toBe(FindingException::STATUS_REVOKED) ->and($revoked->current_validity_state)->toBe(FindingException::VALIDITY_REVOKED) ->and($revoked->currentDecision?->decision_type)->toBe(FindingExceptionDecision::TYPE_REVOKED) ->and($revoked->decisions->pluck('decision_type')->all())->toBe([ FindingExceptionDecision::TYPE_REQUESTED, FindingExceptionDecision::TYPE_APPROVED, FindingExceptionDecision::TYPE_REVOKED, ]) ->and($revoked->revocation_reason)->toBe('Compensating controls no longer exist in production.') ->and($revoked->revoked_at)->not->toBeNull() ->and($revoked->evidenceReferences)->toHaveCount(1) ->and($finding->fresh()?->status)->toBe(Finding::STATUS_RISK_ACCEPTED) ->and(AuditLog::query() ->where('action', AuditActionId::FindingExceptionRevoked->value) ->where('resource_type', 'finding_exception') ->where('resource_id', (string) $revoked->getKey()) ->exists())->toBeTrue(); Livewire::test(ViewFinding::class, ['record' => $finding->getKey()]) ->assertSee('Risk governance') ->assertSee('Revoked'); });