TenantAtlas/apps/platform/tests/Browser/Spec354AcceptedRiskGuidanceSmokeTest.php
ahmido a9c54205bf feat: finding exceptions accepted risk resolution guidance v1 (spec 354) (#425)
Implemented the accepted risk resolution guidance, including the AcceptedRiskResolutionAdapter, guidance cards, and updated related Filament views. Added unit, feature, and browser tests.

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #425
2026-06-05 02:20:46 +00:00

308 lines
13 KiB
PHP

<?php
declare(strict_types=1);
use App\Filament\Pages\Monitoring\FindingExceptionsQueue;
use App\Filament\Resources\FindingExceptionResource;
use App\Models\Finding;
use App\Models\FindingException;
use App\Models\FindingExceptionDecision;
use App\Models\ManagedEnvironment;
use App\Models\User;
use App\Support\Workspaces\WorkspaceContext;
use Illuminate\Foundation\Testing\RefreshDatabase;
pest()->browser()->timeout(30_000);
uses(RefreshDatabase::class);
function spec354BrowserScreenshot(string $name): string
{
return 'spec354-'.$name;
}
function spec354CopyBrowserScreenshot(string $name): void
{
$filename = spec354BrowserScreenshot($name).'.png';
$source = base_path('tests/Browser/Screenshots/'.$filename);
$targetDirectory = repo_path('specs/354-finding-exceptions-accepted-risk-resolution-guidance-v1/artifacts/screenshots');
if (! is_dir($targetDirectory)) {
@mkdir($targetDirectory, 0755, true);
}
if (! is_file($source)) {
$source = \Pest\Browser\Support\Screenshot::path($filename);
}
for ($attempt = 0; $attempt < 10 && ! is_file($source); $attempt++) {
usleep(100_000);
clearstatcache(true, $source);
}
if (is_file($source) && is_dir($targetDirectory) && is_writable($targetDirectory)) {
@copy($source, $targetDirectory.DIRECTORY_SEPARATOR.$filename);
}
}
function spec354AuthenticateBrowser(mixed $test, User $user, ManagedEnvironment $tenant): void
{
$workspaceId = (int) $tenant->workspace_id;
$test->actingAs($user)->withSession([
WorkspaceContext::SESSION_KEY => $workspaceId,
WorkspaceContext::LAST_ENVIRONMENT_IDS_SESSION_KEY => [
(string) $workspaceId => (int) $tenant->getKey(),
],
]);
session()->put(WorkspaceContext::SESSION_KEY, $workspaceId);
session()->put(WorkspaceContext::LAST_ENVIRONMENT_IDS_SESSION_KEY, [
(string) $workspaceId => (int) $tenant->getKey(),
]);
setAdminPanelContext($tenant);
}
function spec354BrowserException(
ManagedEnvironment $tenant,
User $user,
array $findingAttributes = [],
array $exceptionAttributes = [],
?string $decisionType = FindingExceptionDecision::TYPE_APPROVED,
): FindingException {
$decisionMetadata = is_array($exceptionAttributes['decision_metadata'] ?? null)
? $exceptionAttributes['decision_metadata']
: [];
unset($exceptionAttributes['decision_metadata']);
$finding = Finding::factory()
->for($tenant)
->riskAccepted()
->create(array_merge([
'workspace_id' => (int) $tenant->workspace_id,
], $findingAttributes));
$exception = FindingException::query()->create(array_merge([
'workspace_id' => (int) $tenant->workspace_id,
'managed_environment_id' => (int) $tenant->getKey(),
'finding_id' => (int) $finding->getKey(),
'requested_by_user_id' => (int) $user->getKey(),
'owner_user_id' => (int) $user->getKey(),
'approved_by_user_id' => (int) $user->getKey(),
'status' => FindingException::STATUS_ACTIVE,
'current_validity_state' => FindingException::VALIDITY_VALID,
'request_reason' => 'Spec354 browser accepted-risk guidance',
'approval_reason' => 'Spec354 browser approval',
'requested_at' => now()->subDays(5),
'approved_at' => now()->subDays(4),
'effective_from' => now()->subDays(4),
'review_due_at' => now()->addDays(10),
'expires_at' => now()->addDays(30),
'evidence_summary' => ['reference_count' => 0],
], $exceptionAttributes));
if ($decisionType !== null) {
$decision = $exception->decisions()->create([
'workspace_id' => (int) $tenant->workspace_id,
'managed_environment_id' => (int) $tenant->getKey(),
'actor_user_id' => (int) $user->getKey(),
'decision_type' => $decisionType,
'reason' => 'Spec354 browser decision',
'metadata' => $decisionMetadata,
'decided_at' => now()->subDays(4),
]);
$exception->forceFill(['current_decision_id' => (int) $decision->getKey()])->save();
}
return $exception->fresh(['finding', 'tenant', 'owner', 'currentDecision', 'decisions.actor', 'evidenceReferences']);
}
it('smokes expiring queue guidance', function (): void {
[$user, $tenant] = createUserWithTenant(role: 'owner');
$expiring = spec354BrowserException($tenant, $user, exceptionAttributes: [
'review_due_at' => now()->addDay(),
'expires_at' => now()->addDays(2),
]);
spec354AuthenticateBrowser($this, $user, $tenant);
visit(FindingExceptionsQueue::getUrl(panel: 'admin', parameters: [
'exception' => (int) $expiring->getKey(),
]))
->resize(1440, 1100)
->waitForText(__('localization.accepted_risk_guidance.title_expiring'))
->assertNoJavaScriptErrors()
->assertNoConsoleLogs()
->assertSee(__('localization.accepted_risk_guidance.review_focus_label'))
->assertSee(__('localization.accepted_risk_guidance.next_step_expiring'))
->assertSee(__('localization.accepted_risk_guidance.action_open_exception'))
->screenshot(true, spec354BrowserScreenshot('ui-026-finding-exceptions-queue-guidance'));
spec354CopyBrowserScreenshot('ui-026-finding-exceptions-queue-guidance');
});
it('smokes expired queue guidance', function (): void {
[$user, $tenant] = createUserWithTenant(role: 'owner');
$expired = spec354BrowserException($tenant, $user, exceptionAttributes: [
'review_due_at' => now()->subDays(2),
'expires_at' => now()->subDay(),
]);
spec354AuthenticateBrowser($this, $user, $tenant);
visit(FindingExceptionsQueue::getUrl(panel: 'admin', parameters: [
'exception' => (int) $expired->getKey(),
]))
->waitForText(__('localization.accepted_risk_guidance.title_expired'))
->assertNoJavaScriptErrors()
->assertNoConsoleLogs()
->assertSee(__('localization.accepted_risk_guidance.impact_expired'));
});
it('smokes pending-renewal queue guidance while governance remains non-lapsed', function (): void {
[$user, $tenant] = createUserWithTenant(role: 'owner');
$pendingRenewalValid = spec354BrowserException($tenant, $user, exceptionAttributes: [
'status' => FindingException::STATUS_PENDING,
'current_validity_state' => FindingException::VALIDITY_VALID,
'decision_metadata' => [
'previous_review_due_at' => now()->addDays(10)->toIso8601String(),
'previous_expires_at' => now()->addDays(30)->toIso8601String(),
],
], decisionType: FindingExceptionDecision::TYPE_RENEWAL_REQUESTED);
spec354AuthenticateBrowser($this, $user, $tenant);
visit(FindingExceptionsQueue::getUrl(panel: 'admin', parameters: [
'exception' => (int) $pendingRenewalValid->getKey(),
]))
->waitForText(__('localization.accepted_risk_guidance.title_pending_renewal'))
->assertNoJavaScriptErrors()
->assertNoConsoleLogs()
->assertSee(__('localization.accepted_risk_guidance.next_step_pending_renewal'));
});
it('smokes pending-renewal queue guidance when expired governance stays dominant', function (): void {
[$user, $tenant] = createUserWithTenant(role: 'owner');
$pendingRenewalExpired = spec354BrowserException($tenant, $user, exceptionAttributes: [
'status' => FindingException::STATUS_PENDING,
'current_validity_state' => FindingException::VALIDITY_VALID,
'decision_metadata' => [
'previous_review_due_at' => now()->subDays(2)->toIso8601String(),
'previous_expires_at' => now()->subDay()->toIso8601String(),
],
], decisionType: FindingExceptionDecision::TYPE_RENEWAL_REQUESTED);
spec354AuthenticateBrowser($this, $user, $tenant);
visit(FindingExceptionsQueue::getUrl(panel: 'admin', parameters: [
'exception' => (int) $pendingRenewalExpired->getKey(),
]))
->waitForText(__('localization.accepted_risk_guidance.title_expired'))
->assertNoJavaScriptErrors()
->assertNoConsoleLogs()
->assertDontSee(__('localization.accepted_risk_guidance.title_pending_renewal'));
});
it('smokes german queue localization without fake remediation copy', function (): void {
[$user, $tenant] = createUserWithTenant(role: 'owner');
$expiring = spec354BrowserException($tenant, $user, exceptionAttributes: [
'review_due_at' => now()->addDay(),
'expires_at' => now()->addDays(2),
]);
spec354AuthenticateBrowser($this, $user, $tenant);
visit(FindingExceptionsQueue::getUrl(panel: 'admin', parameters: [
'exception' => (int) $expiring->getKey(),
'locale' => 'de',
]))
->waitForText('Was zu prüfen ist')
->assertNoJavaScriptErrors()
->assertNoConsoleLogs()
->assertSee('Das aktuelle Accepted-Risk-Governance-Fenster ist noch aktiv, läuft aber bald ab und muss geprüft werden.')
->assertDontSee('The current accepted-risk governance window is still active, but it is nearing expiry and needs review.')
->assertDontSee('Fix accepted risk');
});
it('smokes detail guidance hierarchy and pending-renewal queue continuity', function (): void {
[$user, $tenant] = createUserWithTenant(role: 'owner');
$incomplete = spec354BrowserException($tenant, $user, exceptionAttributes: [
'owner_user_id' => null,
'request_reason' => '',
'review_due_at' => null,
]);
$pendingRenewalValid = spec354BrowserException($tenant, $user, exceptionAttributes: [
'status' => FindingException::STATUS_PENDING,
'current_validity_state' => FindingException::VALIDITY_VALID,
'decision_metadata' => [
'previous_review_due_at' => now()->addDays(10)->toIso8601String(),
'previous_expires_at' => now()->addDays(30)->toIso8601String(),
],
], decisionType: FindingExceptionDecision::TYPE_RENEWAL_REQUESTED);
spec354AuthenticateBrowser($this, $user, $tenant);
visit(FindingExceptionResource::getUrl('view', ['record' => $incomplete], tenant: $tenant))
->resize(1440, 1100)
->waitForText(__('localization.accepted_risk_guidance.title_incomplete_governance'))
->assertNoJavaScriptErrors()
->assertNoConsoleLogs()
->assertSee(__('localization.accepted_risk_guidance.detail_missing_fields_label'))
->assertSee('Renew exception')
->screenshot(true, spec354BrowserScreenshot('ui-036-exception-detail-guidance'));
spec354CopyBrowserScreenshot('ui-036-exception-detail-guidance');
visit(FindingExceptionResource::getUrl('view', ['record' => $pendingRenewalValid], tenant: $tenant))
->waitForText(__('localization.accepted_risk_guidance.title_pending_renewal'))
->assertNoJavaScriptErrors()
->assertNoConsoleLogs()
->assertSee(__('localization.accepted_risk_guidance.primary_action_label'))
->assertSee(__('localization.accepted_risk_guidance.next_step_pending_renewal'))
->click(__('localization.accepted_risk_guidance.next_step_pending_renewal'))
->waitForText(__('localization.accepted_risk_guidance.title_pending_renewal'))
->assertSee($tenant->name);
});
it('smokes ready and missing-support detail semantics without fake remediation', function (): void {
[$user, $tenant] = createUserWithTenant(role: 'owner');
$ready = spec354BrowserException($tenant, $user);
$missingSupport = spec354BrowserException($tenant, $user, exceptionAttributes: [
'current_validity_state' => FindingException::VALIDITY_MISSING_SUPPORT,
]);
spec354AuthenticateBrowser($this, $user, $tenant);
visit(FindingExceptionResource::getUrl('view', ['record' => $ready], tenant: $tenant))
->resize(1440, 1100)
->waitForText(__('localization.accepted_risk_guidance.title_ready'))
->assertNoJavaScriptErrors()
->assertNoConsoleLogs()
->assertSee(__('localization.accepted_risk_guidance.review_focus_label'))
->assertSee(__('localization.accepted_risk_guidance.impact_ready'))
->assertDontSee(__('localization.accepted_risk_guidance.primary_action_label'))
->assertDontSee(__('localization.accepted_risk_guidance.title_expired'));
visit(FindingExceptionResource::getUrl('view', ['record' => $missingSupport], tenant: $tenant))
->waitForText(__('localization.accepted_risk_guidance.title_missing_support'))
->assertNoJavaScriptErrors()
->assertNoConsoleLogs()
->assertSee(__('localization.accepted_risk_guidance.review_focus_label'))
->assertSee(__('localization.accepted_risk_guidance.next_step_missing_support'))
->assertDontSee(__('localization.accepted_risk_guidance.primary_action_label'))
->assertDontSee('Fix accepted risk')
->assertDontSee('Resolve risk');
});