Implemented report evidence reconciliation. Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #432
231 lines
8.6 KiB
PHP
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];
|
|
}
|