302 lines
11 KiB
PHP
302 lines
11 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Models\BackupSet;
|
|
use App\Models\EnvironmentReview;
|
|
use App\Models\EvidenceSnapshot;
|
|
use App\Models\ManagedEnvironment;
|
|
use App\Models\OperationRun;
|
|
use App\Models\RestoreRun;
|
|
use App\Models\ReviewPack;
|
|
use App\Models\User;
|
|
use App\Services\EnvironmentReviews\EnvironmentReviewFingerprint;
|
|
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\RestoreRunStatus;
|
|
use App\Support\Workspaces\WorkspaceContext;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
|
|
uses(RefreshDatabase::class);
|
|
|
|
pest()->browser()->timeout(60_000);
|
|
|
|
it('Spec365 smokes confirmed review reconciliation guidance on operations surfaces', function (): void {
|
|
[$user, $environment] = createUserWithTenant(role: 'owner', workspaceRole: 'manager');
|
|
|
|
spec365BrowserAuthenticate($this, $user, $environment);
|
|
|
|
$snapshot = seedEnvironmentReviewEvidence($environment, operationRunCount: 0);
|
|
$fingerprint = app(EnvironmentReviewFingerprint::class)->forSnapshot($environment, $snapshot);
|
|
$run = spec365BrowserCreateStaleReviewRun($environment, $user, $fingerprint, $snapshot);
|
|
|
|
spec365BrowserCreateReadyReviewTruth($environment, $user, $snapshot, $fingerprint);
|
|
|
|
visit(OperationRunLinks::index($environment))
|
|
->resize(1440, 1100)
|
|
->waitForText('Operations Hub')
|
|
->assertSee('Reconcile run')
|
|
->assertSee('Existing repository proof may safely reconcile this stale run.')
|
|
->assertDontSee('SQLSTATE')
|
|
->assertDontSee('access token')
|
|
->assertDontSee('client secret')
|
|
->assertDontSee('serialized job')
|
|
->assertNoJavaScriptErrors()
|
|
->assertNoConsoleLogs();
|
|
|
|
visit(OperationRunLinks::tenantlessView($run))
|
|
->waitForText('Monitoring detail')
|
|
->assertSee('Reconcile run')
|
|
->click('Reconcile run')
|
|
->assertSee('Reconcile this operation run?')
|
|
->assertSee('This does not retry or change the Microsoft tenant.')
|
|
->assertDontSee('SQLSTATE')
|
|
->assertDontSee('environment_reviews_fingerprint_mutable_unique')
|
|
->assertNoJavaScriptErrors()
|
|
->assertNoConsoleLogs();
|
|
});
|
|
|
|
it('Spec365 smokes related proof actions across evidence report sync and backup states', function (): void {
|
|
[$user, $environment] = createUserWithTenant(role: 'owner', workspaceRole: 'manager');
|
|
|
|
spec365BrowserAuthenticate($this, $user, $environment);
|
|
spec365BrowserCreateEvidenceRun($environment, $user);
|
|
spec365BrowserCreateReviewPackRun($environment, $user);
|
|
spec365BrowserCreatePartialInventoryRun($environment, $user);
|
|
spec365BrowserCreateBlockedBackupRun($environment, $user);
|
|
|
|
visit(OperationRunLinks::index($environment))
|
|
->resize(1440, 1100)
|
|
->waitForText('Operations Hub')
|
|
->assertSee('View evidence')
|
|
->assertSee('View report')
|
|
->assertSee('View affected families')
|
|
->assertSee('View backup details')
|
|
->assertDontSee('SQLSTATE')
|
|
->assertDontSee('Guzzle')
|
|
->assertDontSee('stack trace')
|
|
->assertDontSee('access token')
|
|
->assertDontSee('client secret')
|
|
->assertNoJavaScriptErrors()
|
|
->assertNoConsoleLogs();
|
|
});
|
|
|
|
it('Spec365 smokes high-risk restore guidance without unsafe operator actions', function (): void {
|
|
[$user, $environment] = createUserWithTenant(role: 'owner', workspaceRole: 'manager');
|
|
|
|
spec365BrowserAuthenticate($this, $user, $environment);
|
|
|
|
$run = spec365BrowserCreateStaleRestoreRun($environment, $user);
|
|
|
|
visit(OperationRunLinks::tenantlessView($run))
|
|
->resize(1440, 1100)
|
|
->waitForText('Monitoring detail')
|
|
->assertSee('View restore details')
|
|
->assertSee('High-risk operations cannot be retried from this view.')
|
|
->assertDontSee('Retry restore')
|
|
->assertDontSee('Force complete')
|
|
->assertDontSee('Mark succeeded')
|
|
->assertDontSee('Delete run')
|
|
->assertDontSee('Purge run')
|
|
->assertDontSee('stack trace')
|
|
->assertDontSee('access token')
|
|
->assertDontSee('client secret')
|
|
->assertNoJavaScriptErrors()
|
|
->assertNoConsoleLogs();
|
|
});
|
|
|
|
function spec365BrowserAuthenticate(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 spec365BrowserCreateStaleReviewRun(
|
|
ManagedEnvironment $environment,
|
|
User $user,
|
|
string $fingerprint,
|
|
EvidenceSnapshot $snapshot,
|
|
): OperationRun {
|
|
return OperationRun::factory()->forTenant($environment)->create([
|
|
'user_id' => (int) $user->getKey(),
|
|
'initiator_name' => $user->name,
|
|
'type' => 'environment.review.compose',
|
|
'status' => OperationRunStatus::Queued->value,
|
|
'outcome' => OperationRunOutcome::Pending->value,
|
|
'created_at' => now()->subMinutes(10),
|
|
'context' => [
|
|
'workspace_id' => (int) $environment->workspace_id,
|
|
'managed_environment_id' => (int) $environment->getKey(),
|
|
'evidence_snapshot_id' => (int) $snapshot->getKey(),
|
|
'review_fingerprint' => $fingerprint,
|
|
],
|
|
]);
|
|
}
|
|
|
|
function spec365BrowserCreateReadyReviewTruth(
|
|
ManagedEnvironment $environment,
|
|
User $user,
|
|
EvidenceSnapshot $snapshot,
|
|
string $fingerprint,
|
|
): EnvironmentReview {
|
|
$publishedRun = OperationRun::factory()->forTenant($environment)->create([
|
|
'user_id' => (int) $user->getKey(),
|
|
'initiator_name' => $user->name,
|
|
'type' => 'environment.review.compose',
|
|
'status' => OperationRunStatus::Completed->value,
|
|
'outcome' => OperationRunOutcome::Succeeded->value,
|
|
'completed_at' => now()->subMinutes(5),
|
|
'context' => [
|
|
'workspace_id' => (int) $environment->workspace_id,
|
|
'managed_environment_id' => (int) $environment->getKey(),
|
|
'review_fingerprint' => $fingerprint,
|
|
],
|
|
]);
|
|
|
|
return EnvironmentReview::factory()->ready()->create([
|
|
'workspace_id' => (int) $environment->workspace_id,
|
|
'managed_environment_id' => (int) $environment->getKey(),
|
|
'evidence_snapshot_id' => (int) $snapshot->getKey(),
|
|
'initiated_by_user_id' => (int) $user->getKey(),
|
|
'operation_run_id' => (int) $publishedRun->getKey(),
|
|
'fingerprint' => $fingerprint,
|
|
'summary' => [
|
|
'finding_count' => 4,
|
|
'report_count' => 2,
|
|
'operation_count' => 1,
|
|
],
|
|
]);
|
|
}
|
|
|
|
function spec365BrowserCreateStaleRestoreRun(ManagedEnvironment $environment, User $user): OperationRun
|
|
{
|
|
$backupSet = BackupSet::factory()->for($environment)->create(['status' => 'completed']);
|
|
$run = OperationRun::factory()->forTenant($environment)->create([
|
|
'user_id' => (int) $user->getKey(),
|
|
'initiator_name' => $user->name,
|
|
'type' => 'restore.execute',
|
|
'status' => OperationRunStatus::Queued->value,
|
|
'outcome' => OperationRunOutcome::Pending->value,
|
|
'created_at' => now()->subMinutes(10),
|
|
]);
|
|
|
|
$restoreRun = RestoreRun::withoutEvents(fn (): RestoreRun => RestoreRun::factory()
|
|
->for($environment, 'tenant')
|
|
->for($backupSet)
|
|
->create([
|
|
'workspace_id' => (int) $environment->workspace_id,
|
|
'operation_run_id' => (int) $run->getKey(),
|
|
'status' => RestoreRunStatus::Completed->value,
|
|
'is_dry_run' => false,
|
|
]));
|
|
|
|
$run->forceFill([
|
|
'context' => [
|
|
'restore_run_id' => (int) $restoreRun->getKey(),
|
|
'backup_set_id' => (int) $backupSet->getKey(),
|
|
],
|
|
])->save();
|
|
|
|
return $run->fresh();
|
|
}
|
|
|
|
function spec365BrowserCreateEvidenceRun(ManagedEnvironment $environment, User $user): OperationRun
|
|
{
|
|
$run = OperationRun::factory()->forTenant($environment)->create([
|
|
'user_id' => (int) $user->getKey(),
|
|
'initiator_name' => $user->name,
|
|
'type' => 'tenant.evidence.snapshot.generate',
|
|
'status' => OperationRunStatus::Completed->value,
|
|
'outcome' => OperationRunOutcome::Succeeded->value,
|
|
'completed_at' => now()->subMinutes(3),
|
|
]);
|
|
|
|
EvidenceSnapshot::query()->create([
|
|
'workspace_id' => (int) $environment->workspace_id,
|
|
'managed_environment_id' => (int) $environment->getKey(),
|
|
'operation_run_id' => (int) $run->getKey(),
|
|
'initiated_by_user_id' => (int) $user->getKey(),
|
|
'fingerprint' => hash('sha256', 'spec365-browser-evidence-'.$run->getKey()),
|
|
'status' => EvidenceSnapshotStatus::Active->value,
|
|
'completeness_state' => EvidenceCompletenessState::Complete->value,
|
|
'summary' => ['source' => 'spec365-browser'],
|
|
'generated_at' => now()->subMinutes(3),
|
|
]);
|
|
|
|
return $run->fresh();
|
|
}
|
|
|
|
function spec365BrowserCreateReviewPackRun(ManagedEnvironment $environment, User $user): OperationRun
|
|
{
|
|
$run = 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(4),
|
|
]);
|
|
|
|
ReviewPack::factory()->ready()->create([
|
|
'workspace_id' => (int) $environment->workspace_id,
|
|
'managed_environment_id' => (int) $environment->getKey(),
|
|
'operation_run_id' => (int) $run->getKey(),
|
|
'initiated_by_user_id' => (int) $user->getKey(),
|
|
]);
|
|
|
|
return $run->fresh();
|
|
}
|
|
|
|
function spec365BrowserCreatePartialInventoryRun(ManagedEnvironment $environment, User $user): OperationRun
|
|
{
|
|
return OperationRun::factory()->forTenant($environment)->create([
|
|
'user_id' => (int) $user->getKey(),
|
|
'initiator_name' => $user->name,
|
|
'type' => 'inventory.sync',
|
|
'status' => OperationRunStatus::Completed->value,
|
|
'outcome' => OperationRunOutcome::PartiallySucceeded->value,
|
|
'completed_at' => now()->subMinutes(5),
|
|
'summary_counts' => [
|
|
'total' => 4,
|
|
'processed' => 4,
|
|
'succeeded' => 2,
|
|
'failed' => 1,
|
|
'skipped' => 1,
|
|
],
|
|
]);
|
|
}
|
|
|
|
function spec365BrowserCreateBlockedBackupRun(ManagedEnvironment $environment, User $user): OperationRun
|
|
{
|
|
$backupSet = BackupSet::factory()->for($environment)->create(['status' => 'completed']);
|
|
|
|
return OperationRun::factory()->forTenant($environment)->create([
|
|
'user_id' => (int) $user->getKey(),
|
|
'initiator_name' => $user->name,
|
|
'type' => 'backup.schedule.execute',
|
|
'status' => OperationRunStatus::Completed->value,
|
|
'outcome' => OperationRunOutcome::Blocked->value,
|
|
'completed_at' => now()->subMinutes(6),
|
|
'context' => [
|
|
'backup_set_id' => (int) $backupSet->getKey(),
|
|
'reason_code' => 'missing_provider_permission',
|
|
],
|
|
]);
|
|
}
|