Some checks failed
PR Fast Feedback / fast-feedback (pull_request) Failing after 59s
Implemented the first version of the operator resolution guidance framework. Added new foundation classes (ResolutionCase, ResolutionAction) and a ReviewPackOutputResolutionAdapter. Updated the Customer Review Workspace and Environment Review Resource to use the new adapter. Added extensive test coverage for the framework and UI integrations.
199 lines
7.5 KiB
PHP
199 lines
7.5 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Filament\Pages\Reviews\CustomerReviewWorkspace;
|
|
use App\Filament\Resources\EnvironmentReviewResource;
|
|
use App\Models\EnvironmentReview;
|
|
use App\Models\EvidenceSnapshot;
|
|
use App\Models\ManagedEnvironment;
|
|
use App\Models\ReviewPack;
|
|
use App\Models\User;
|
|
use App\Support\EnvironmentReviewCompletenessState;
|
|
use App\Support\EnvironmentReviewStatus;
|
|
use App\Support\Governance\Controls\ComplianceEvidenceMappingV1;
|
|
use App\Support\Workspaces\WorkspaceContext;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Illuminate\Support\Facades\Storage;
|
|
|
|
uses(RefreshDatabase::class);
|
|
|
|
pest()->browser()->timeout(60_000);
|
|
|
|
beforeEach(function (): void {
|
|
Storage::fake('exports');
|
|
});
|
|
|
|
it('Spec350 smokes the shared resolution path from workspace guidance into review detail', function (): void {
|
|
[$user, $environment] = createUserWithTenant(role: 'owner', workspaceRole: 'manager');
|
|
$environment->forceFill(['name' => 'Spec350 Browser Blocked'])->save();
|
|
|
|
[$review] = spec350BrowserCreatePublishedReviewWithPack(
|
|
$environment,
|
|
$user,
|
|
seedPartialEnvironmentReviewEvidence($environment, findingCount: 0, driftCount: 0),
|
|
[
|
|
'publish_blockers' => ['Operator approval note is still missing.'],
|
|
],
|
|
[
|
|
'include_pii' => false,
|
|
'include_operations' => true,
|
|
],
|
|
'review-packs/spec350-browser-blocked.zip',
|
|
markReady: false,
|
|
);
|
|
|
|
spec350AuthenticateBrowser($this, $user, $environment);
|
|
|
|
$detailUrl = EnvironmentReviewResource::environmentScopedUrl('view', ['record' => $review], $environment)
|
|
.'?'.http_build_query([
|
|
CustomerReviewWorkspace::DETAIL_CONTEXT_QUERY_KEY => 1,
|
|
'source_surface' => CustomerReviewWorkspace::SOURCE_SURFACE,
|
|
'tenant_filter_id' => (int) $environment->getKey(),
|
|
]);
|
|
|
|
$page = visit(CustomerReviewWorkspace::environmentFilterUrl($environment))
|
|
->resize(1236, 900)
|
|
->waitForText('What is the current review pack output state?')
|
|
->assertSee('Output not customer-ready')
|
|
->assertSee('Inspect review blockers')
|
|
->assertSee('Evidence basis incomplete')
|
|
->assertSee('Technical details')
|
|
->assertScript('document.querySelector("[data-testid=\"customer-review-primary-action\"]")?.getAttribute("href")', $detailUrl)
|
|
->assertNoJavaScriptErrors()
|
|
->assertNoConsoleLogs();
|
|
$page->screenshot(true, spec350BrowserScreenshotName('01-workspace-blocked'));
|
|
spec350CopyBrowserScreenshot('01-workspace-blocked');
|
|
|
|
$page = visit($detailUrl)
|
|
->waitForText('Output not customer-ready')
|
|
->assertSee('Review limitations below')
|
|
->assertSee('You are already on the review detail for this output.')
|
|
->assertDontSee('Open evidence basis')
|
|
->assertDontSee('Open operation proof')
|
|
->assertNoJavaScriptErrors()
|
|
->assertNoConsoleLogs();
|
|
$page->screenshot(true, spec350BrowserScreenshotName('02-detail-context'));
|
|
spec350CopyBrowserScreenshot('02-detail-context');
|
|
});
|
|
|
|
function spec350BrowserScreenshotName(string $name): string
|
|
{
|
|
return 'spec350-operator-resolution-guidance-'.$name;
|
|
}
|
|
|
|
function spec350CopyBrowserScreenshot(string $name): void
|
|
{
|
|
$filename = spec350BrowserScreenshotName($name).'.png';
|
|
$source = base_path('tests/Browser/Screenshots/'.$filename);
|
|
$targetDirectory = repo_path('specs/350-operator-resolution-guidance-framework-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.$name.'.png');
|
|
}
|
|
}
|
|
|
|
function spec350AuthenticateBrowser(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);
|
|
}
|
|
|
|
/**
|
|
* @param array<string, mixed> $summaryOverrides
|
|
* @param array<string, mixed> $packOptions
|
|
* @return array{0: EnvironmentReview, 1: ReviewPack}
|
|
*/
|
|
function spec350BrowserCreatePublishedReviewWithPack(
|
|
ManagedEnvironment $environment,
|
|
User $user,
|
|
EvidenceSnapshot $snapshot,
|
|
array $summaryOverrides = [],
|
|
array $packOptions = [],
|
|
string $filePath = 'review-packs/spec350-browser-review-pack.zip',
|
|
bool $markReady = true,
|
|
): array {
|
|
$review = composeEnvironmentReviewForTest($environment, $user, $snapshot);
|
|
$summary = array_replace_recursive(
|
|
is_array($review->summary) ? $review->summary : [],
|
|
[
|
|
'control_interpretation' => [
|
|
'version_key' => ComplianceEvidenceMappingV1::VERSION_KEY,
|
|
'controls' => [
|
|
[
|
|
'control_key' => 'customer-output',
|
|
'title' => 'Customer output',
|
|
'readiness_bucket' => $markReady ? 'evidence_on_record' : 'review_recommended',
|
|
'readiness_label' => $markReady ? 'Evidence on record' : 'Review recommended',
|
|
'primary_reason' => $markReady ? 'Evidence path is complete.' : 'Evidence basis needs review.',
|
|
'recommended_next_action' => $markReady ? 'Open the current customer review pack.' : 'Review the evidence basis before sharing.',
|
|
],
|
|
],
|
|
],
|
|
],
|
|
$summaryOverrides,
|
|
);
|
|
|
|
Storage::disk('exports')->put($filePath, 'PK-spec350-browser-test');
|
|
|
|
$review->forceFill([
|
|
'status' => EnvironmentReviewStatus::Published->value,
|
|
'completeness_state' => $markReady
|
|
? EnvironmentReviewCompletenessState::Complete->value
|
|
: (string) $review->completeness_state,
|
|
'summary' => $summary,
|
|
'generated_at' => now()->subMinutes(5),
|
|
'published_at' => now()->subMinutes(3),
|
|
'published_by_user_id' => (int) $user->getKey(),
|
|
])->save();
|
|
|
|
if ($markReady) {
|
|
$review = markEnvironmentReviewCustomerSafeReady($review);
|
|
}
|
|
|
|
$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(),
|
|
'initiated_by_user_id' => (int) $user->getKey(),
|
|
'options' => array_replace([
|
|
'include_pii' => false,
|
|
'include_operations' => true,
|
|
], $packOptions),
|
|
'file_path' => $filePath,
|
|
'file_disk' => 'exports',
|
|
'generated_at' => now()->subMinutes(4),
|
|
]);
|
|
|
|
$review->forceFill(['current_export_review_pack_id' => (int) $pack->getKey()])->save();
|
|
|
|
return [$review->fresh(['tenant', 'evidenceSnapshot', 'currentExportReviewPack.operationRun', 'operationRun']), $pack];
|
|
}
|