Some checks failed
PR Fast Feedback / fast-feedback (pull_request) Failing after 1m0s
Implemented the output contract and readiness semantics for review packs. Also added spec 348. Includes changes to ChooseEnvironment, CustomerReviewWorkspace, GenerateReviewPackJob and related blade views. Added comprehensive tests.
257 lines
9.5 KiB
PHP
257 lines
9.5 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Filament\Pages\Reviews\CustomerReviewWorkspace;
|
|
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('Spec347 smokes review pack output readiness states', function (): void {
|
|
[$user, $readyEnvironment] = createUserWithTenant(role: 'owner', workspaceRole: 'manager');
|
|
$readyEnvironment->forceFill(['name' => 'Spec347 Browser Ready'])->save();
|
|
$limitedEnvironment = spec347BrowserEnvironmentFor($user, $readyEnvironment, 'Spec347 Browser Limited');
|
|
$internalEnvironment = spec347BrowserEnvironmentFor($user, $readyEnvironment, 'Spec347 Browser Internal');
|
|
|
|
spec347BrowserCreatePublishedReviewWithPack(
|
|
$readyEnvironment,
|
|
$user,
|
|
seedEnvironmentReviewEvidence($readyEnvironment, findingCount: 0, driftCount: 0),
|
|
[],
|
|
[
|
|
'include_pii' => false,
|
|
'include_operations' => true,
|
|
],
|
|
'review-packs/spec347-browser-ready.zip',
|
|
);
|
|
|
|
spec347BrowserCreatePublishedReviewWithPack(
|
|
$limitedEnvironment,
|
|
$user,
|
|
seedPartialEnvironmentReviewEvidence($limitedEnvironment, findingCount: 0, driftCount: 0),
|
|
[
|
|
'governance_package' => [
|
|
'decision_summary' => [
|
|
'status' => 'incomplete',
|
|
'evidence_state' => EnvironmentReviewCompletenessState::Partial->value,
|
|
'decision_data_state' => 'incomplete',
|
|
'total_count' => 1,
|
|
'summary' => 'Decision evidence is incomplete for this released review.',
|
|
'next_action' => 'Review the evidence basis before relying on the decision summary.',
|
|
'entries' => [],
|
|
],
|
|
],
|
|
],
|
|
[
|
|
'include_pii' => false,
|
|
'include_operations' => true,
|
|
],
|
|
'review-packs/spec347-browser-limited.zip',
|
|
normalizeOutputReadiness: false,
|
|
);
|
|
|
|
spec347BrowserCreatePublishedReviewWithPack(
|
|
$internalEnvironment,
|
|
$user,
|
|
seedEnvironmentReviewEvidence($internalEnvironment, findingCount: 0, driftCount: 0),
|
|
[],
|
|
[
|
|
'include_pii' => true,
|
|
'include_operations' => true,
|
|
],
|
|
'review-packs/spec347-browser-internal.zip',
|
|
);
|
|
|
|
spec347AuthenticateBrowser($this, $user, $readyEnvironment);
|
|
|
|
$page = visit(CustomerReviewWorkspace::environmentFilterUrl($readyEnvironment))
|
|
->resize(1236, 900)
|
|
->waitForText('Customer-safe review pack ready')
|
|
->assertSee('Download customer-safe review pack')
|
|
->assertSee('PII excluded')
|
|
->assertDontSee('Ready to share')
|
|
->assertNoJavaScriptErrors()
|
|
->assertNoConsoleLogs();
|
|
$page->screenshot(true, spec347BrowserScreenshotName('01-customer-safe-ready'));
|
|
spec347CopyBrowserScreenshot('01-customer-safe-ready');
|
|
|
|
$page = visit(CustomerReviewWorkspace::environmentFilterUrl($limitedEnvironment))
|
|
->waitForText('Published with limitations')
|
|
->assertSee('The review package is published, but the evidence basis is incomplete.')
|
|
->assertSee('Download review pack with limitations')
|
|
->assertSee('Requires review')
|
|
->assertNoJavaScriptErrors()
|
|
->assertNoConsoleLogs();
|
|
$page->screenshot(true, spec347BrowserScreenshotName('02-published-with-limitations'));
|
|
spec347CopyBrowserScreenshot('02-published-with-limitations');
|
|
|
|
$page = visit(CustomerReviewWorkspace::environmentFilterUrl($internalEnvironment))
|
|
->waitForText('Internal review package available')
|
|
->assertSee('Contains PII')
|
|
->assertSee('Download internal review pack')
|
|
->assertSee('Internal only')
|
|
->assertNoJavaScriptErrors()
|
|
->assertNoConsoleLogs();
|
|
$page->screenshot(true, spec347BrowserScreenshotName('03-internal-review-package'));
|
|
spec347CopyBrowserScreenshot('03-internal-review-package');
|
|
});
|
|
|
|
function spec347BrowserScreenshotName(string $name): string
|
|
{
|
|
return 'spec347-review-pack-output-readiness-'.$name;
|
|
}
|
|
|
|
function spec347CopyBrowserScreenshot(string $name): void
|
|
{
|
|
$filename = spec347BrowserScreenshotName($name).'.png';
|
|
$source = base_path('tests/Browser/Screenshots/'.$filename);
|
|
$targetDirectory = repo_path('specs/347-review-pack-output-contract-readiness-semantics/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 spec347AuthenticateBrowser(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 spec347BrowserEnvironmentFor(User $user, ManagedEnvironment $baseEnvironment, string $name): ManagedEnvironment
|
|
{
|
|
$environment = ManagedEnvironment::factory()->active()->create([
|
|
'workspace_id' => (int) $baseEnvironment->workspace_id,
|
|
'name' => $name,
|
|
]);
|
|
|
|
createUserWithTenant(tenant: $environment, user: $user, role: 'owner', workspaceRole: 'manager');
|
|
|
|
return $environment;
|
|
}
|
|
|
|
/**
|
|
* @param array<string, mixed> $summaryOverrides
|
|
* @param array<string, mixed> $packOptions
|
|
* @return array{0: EnvironmentReview, 1: ReviewPack}
|
|
*/
|
|
function spec347BrowserCreatePublishedReviewWithPack(
|
|
ManagedEnvironment $environment,
|
|
User $user,
|
|
EvidenceSnapshot $snapshot,
|
|
array $summaryOverrides = [],
|
|
array $packOptions = [],
|
|
string $filePath = 'review-packs/spec347-browser-review-pack.zip',
|
|
bool $normalizeOutputReadiness = 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' => 'evidence_on_record',
|
|
'readiness_label' => 'Evidence on record',
|
|
'primary_reason' => 'Evidence path is complete.',
|
|
'recommended_next_action' => 'Open the current customer review pack.',
|
|
],
|
|
],
|
|
],
|
|
'governance_package' => [
|
|
'decision_summary' => [
|
|
'status' => 'none',
|
|
'evidence_state' => EnvironmentReviewCompletenessState::Complete->value,
|
|
'decision_data_state' => 'complete',
|
|
'total_count' => 0,
|
|
'summary' => 'No governance decisions require customer awareness.',
|
|
'next_action' => 'Open the current customer review pack.',
|
|
'entries' => [],
|
|
],
|
|
],
|
|
],
|
|
$summaryOverrides,
|
|
);
|
|
|
|
Storage::disk('exports')->put($filePath, 'PK-spec347-browser-test');
|
|
|
|
$review->forceFill([
|
|
'status' => EnvironmentReviewStatus::Published->value,
|
|
'completeness_state' => EnvironmentReviewCompletenessState::Complete->value,
|
|
'summary' => $summary,
|
|
'generated_at' => now()->subMinutes(5),
|
|
'published_at' => now()->subMinutes(3),
|
|
'published_by_user_id' => (int) $user->getKey(),
|
|
])->save();
|
|
|
|
if ($normalizeOutputReadiness) {
|
|
$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->refresh(), $pack->refresh()];
|
|
}
|