TenantAtlas/apps/platform/tests/Browser/Spec361ArtifactReconciliationSmokeTest.php
ahmido 252cd4513d feat: implement report evidence reconciliation (#432)
Implemented report evidence reconciliation.

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #432
2026-06-06 22:40:59 +00:00

231 lines
8.6 KiB
PHP

<?php
declare(strict_types=1);
use App\Models\ManagedEnvironment;
use App\Models\OperationRun;
use App\Models\ReviewPack;
use App\Models\User;
use App\Services\OperationRunService;
use App\Services\ReviewPackService;
use App\Support\Evidence\EvidenceCompletenessState;
use App\Support\Evidence\EvidenceSnapshotStatus;
use App\Support\OperationRunLinks;
use App\Support\OperationRunOutcome;
use App\Support\OperationRunStatus;
use App\Support\ReviewPackStatus;
use App\Support\Workspaces\WorkspaceContext;
use Illuminate\Foundation\Testing\RefreshDatabase;
uses(RefreshDatabase::class);
pest()->browser()->timeout(60_000);
it('Spec361 smokes canonical evidence snapshot reconciliation drill-through on the existing operations surfaces', function (): void {
[$user, $environment] = createUserWithTenant(role: 'owner', workspaceRole: 'manager');
spec361AuthenticateBrowser($this, $user, $environment);
$snapshot = restateEnvironmentReviewEvidenceSnapshot(
seedEnvironmentReviewEvidence($environment, operationRunCount: 2),
EvidenceCompletenessState::Complete,
);
$run = spec361BrowserCreateCanonicalReconciledEvidenceRun($environment, $user, $snapshot);
visit(OperationRunLinks::index($environment))
->resize(1440, 1100)
->waitForText('Operations Hub')
->assertSee('Automatically reconciled')
->assertSee('No action needed.')
->assertNoJavaScriptErrors()
->assertNoConsoleLogs();
visit(OperationRunLinks::tenantlessView($run))
->waitForText('Monitoring detail')
->assertSee('Automatically reconciled')
->click('Open')
->assertSee('View evidence snapshot')
->assertNoJavaScriptErrors()
->assertNoConsoleLogs();
});
it('Spec361 smokes canonical review-pack reconciliation drill-through on the existing operations surfaces', function (): void {
[$user, $environment] = createUserWithTenant(role: 'owner', workspaceRole: 'manager');
spec361AuthenticateBrowser($this, $user, $environment);
[$pack, $run] = spec361BrowserCreateCanonicalReconciledReviewPackRun($environment, $user);
visit(OperationRunLinks::index($environment))
->resize(1440, 1100)
->waitForText('Operations Hub')
->assertSee('Automatically reconciled')
->assertSee('Review the source review before sharing this pack.')
->assertNoJavaScriptErrors()
->assertNoConsoleLogs();
visit(OperationRunLinks::tenantlessView($run))
->waitForText('Monitoring detail')
->assertSee('Automatically reconciled')
->click('Open')
->assertSee('View review pack')
->assertNoJavaScriptErrors()
->assertNoConsoleLogs();
});
function spec361AuthenticateBrowser(mixed $test, User $user, ManagedEnvironment $environment): void
{
$workspaceId = (int) $environment->workspace_id;
$test->actingAs($user)->withSession([
WorkspaceContext::SESSION_KEY => $workspaceId,
WorkspaceContext::LAST_ENVIRONMENT_IDS_SESSION_KEY => [
(string) $workspaceId => (int) $environment->getKey(),
],
]);
session()->put(WorkspaceContext::SESSION_KEY, $workspaceId);
session()->put(WorkspaceContext::LAST_ENVIRONMENT_IDS_SESSION_KEY, [
(string) $workspaceId => (int) $environment->getKey(),
]);
setAdminPanelContext($environment);
}
function spec361BrowserCreateCanonicalReconciledEvidenceRun(
ManagedEnvironment $environment,
User $user,
mixed $snapshot,
): OperationRun {
$run = OperationRun::factory()->forTenant($environment)->create([
'user_id' => (int) $user->getKey(),
'initiator_name' => $user->name,
'type' => 'tenant.evidence.snapshot.generate',
'status' => OperationRunStatus::Queued->value,
'outcome' => OperationRunOutcome::Pending->value,
'created_at' => now()->subMinutes(30),
'context' => [
'workspace_id' => (int) $environment->workspace_id,
'managed_environment_id' => (int) $environment->getKey(),
'fingerprint' => (string) $snapshot->fingerprint,
],
]);
return app(OperationRunService::class)->updateRunWithReconciliation(
run: $run,
status: OperationRunStatus::Completed->value,
outcome: OperationRunOutcome::Succeeded->value,
summaryCounts: [
'finding_count' => (int) data_get($snapshot->summary, 'finding_count', 0),
'report_count' => (int) data_get($snapshot->summary, 'report_count', 0),
'operation_count' => (int) data_get($snapshot->summary, 'operation_count', 0),
],
failures: [],
reasonCode: 'run.adapter_out_of_sync',
reasonMessage: 'A matching evidence snapshot was already available for this run.',
source: 'adapter_reconciler',
evidence: [
'fingerprint' => (string) $snapshot->fingerprint,
],
adapter: 'evidence_snapshot',
decision: 'reconciled_succeeded',
related: [
'type' => 'evidence_snapshot',
'id' => (int) $snapshot->getKey(),
'status' => EvidenceSnapshotStatus::Active->value,
'completeness_state' => EvidenceCompletenessState::Complete->value,
],
)->fresh();
}
/**
* @return array{0: ReviewPack, 1: OperationRun}
*/
function spec361BrowserCreateCanonicalReconciledReviewPackRun(
ManagedEnvironment $environment,
User $user,
): array {
$snapshot = restateEnvironmentReviewEvidenceSnapshot(
seedEnvironmentReviewEvidence($environment, operationRunCount: 2),
EvidenceCompletenessState::Complete,
);
$review = composeEnvironmentReviewForTest($environment, $user, $snapshot);
$options = [
'include_pii' => false,
'include_operations' => true,
];
$fingerprint = app(ReviewPackService::class)->computeFingerprintForReview($review, $options);
$publishedRun = OperationRun::factory()->forTenant($environment)->create([
'user_id' => (int) $user->getKey(),
'initiator_name' => $user->name,
'type' => 'environment.review_pack.generate',
'status' => OperationRunStatus::Completed->value,
'outcome' => OperationRunOutcome::Succeeded->value,
'completed_at' => now()->subMinutes(5),
]);
$pack = ReviewPack::factory()->ready()->create([
'managed_environment_id' => (int) $environment->getKey(),
'workspace_id' => (int) $environment->workspace_id,
'environment_review_id' => (int) $review->getKey(),
'evidence_snapshot_id' => (int) $snapshot->getKey(),
'operation_run_id' => (int) $publishedRun->getKey(),
'initiated_by_user_id' => (int) $user->getKey(),
'fingerprint' => $fingerprint,
'options' => $options,
'status' => ReviewPackStatus::Ready->value,
'summary' => [
'finding_count' => 4,
'report_count' => 2,
'operation_count' => 3,
],
]);
$run = OperationRun::factory()->forTenant($environment)->create([
'user_id' => (int) $user->getKey(),
'initiator_name' => $user->name,
'type' => 'environment.review_pack.generate',
'status' => OperationRunStatus::Queued->value,
'outcome' => OperationRunOutcome::Pending->value,
'created_at' => now()->subMinutes(30),
'context' => [
'workspace_id' => (int) $environment->workspace_id,
'managed_environment_id' => (int) $environment->getKey(),
'environment_review_id' => (int) $review->getKey(),
'evidence_snapshot_id' => (int) $snapshot->getKey(),
'include_pii' => $options['include_pii'],
'include_operations' => $options['include_operations'],
],
]);
$run = app(OperationRunService::class)->updateRunWithReconciliation(
run: $run,
status: OperationRunStatus::Completed->value,
outcome: OperationRunOutcome::Succeeded->value,
summaryCounts: [
'finding_count' => 4,
'report_count' => 2,
'operation_count' => 3,
],
failures: [],
reasonCode: 'run.adapter_out_of_sync',
reasonMessage: 'A matching review pack was already available for this run.',
source: 'adapter_reconciler',
evidence: [
'fingerprint' => $fingerprint,
],
adapter: 'review_pack',
decision: 'reconciled_succeeded',
related: [
'type' => 'review_pack',
'id' => (int) $pack->getKey(),
'status' => ReviewPackStatus::Ready->value,
'environment_review_id' => (int) $review->getKey(),
'evidence_snapshot_id' => (int) $snapshot->getKey(),
],
)->fresh();
return [$pack, $run];
}