Some checks failed
PR Fast Feedback / fast-feedback (pull_request) Failing after 5m7s
Added jobs, controllers, and PDF generation logic for management report runtime as defined in Spec 379. Includes artifact migrations, payload builders, and testing coverage.
222 lines
7.9 KiB
PHP
222 lines
7.9 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Filament\Resources\ReviewPackResource;
|
|
use App\Models\EnvironmentReview;
|
|
use App\Models\ManagedEnvironment;
|
|
use App\Models\ReviewPack;
|
|
use App\Models\StoredReport;
|
|
use App\Models\User;
|
|
use App\Support\ReviewPacks\ReportProfileRegistry;
|
|
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('Spec379 smokes the management PDF Review Pack detail states', function (): void {
|
|
config([
|
|
'tenantpilot.pdf_renderer.enabled' => true,
|
|
'tenantpilot.pdf_renderer.driver' => 'gotenberg',
|
|
'tenantpilot.pdf_renderer.runtime_validated' => false,
|
|
]);
|
|
|
|
[$user, $tenant, $review, $pack] = spec379BrowserCurrentReadyPack();
|
|
|
|
spec379BrowserAuthenticate($this, $user, $tenant);
|
|
|
|
$packUrl = ReviewPackResource::getUrl('view', ['record' => $pack], tenant: $tenant, panel: 'admin');
|
|
|
|
$page = visit($packUrl)
|
|
->resize(1280, 900)
|
|
->waitForText('More')
|
|
->assertSee('View customer-safe report')
|
|
->assertSee('Download customer-safe review pack')
|
|
->assertSee('More')
|
|
->assertDontSee('Generate management PDF')
|
|
->click('More')
|
|
->waitForText('Management PDF unavailable')
|
|
->assertSee('Management PDF unavailable')
|
|
->assertSee('Regenerate review pack')
|
|
->assertDontSee('Generate management PDF')
|
|
->assertNoJavaScriptErrors()
|
|
->assertNoConsoleLogs()
|
|
->screenshot(true, 'spec379-management-report-pdf-generate-state');
|
|
spec379BrowserCopyScreenshot('generate-state');
|
|
|
|
spec379BrowserReadyManagementPdf($pack);
|
|
|
|
$page = visit($packUrl)
|
|
->resize(1280, 900)
|
|
->waitForText('Download management PDF')
|
|
->assertSee('Download management PDF')
|
|
->assertSee('More')
|
|
->assertDontSee('Generate management PDF')
|
|
->assertNoJavaScriptErrors()
|
|
->assertNoConsoleLogs()
|
|
->screenshot(true, 'spec379-management-report-pdf-download-state');
|
|
spec379BrowserCopyScreenshot('download-state');
|
|
|
|
expect($review)->toBeInstanceOf(EnvironmentReview::class);
|
|
});
|
|
|
|
/**
|
|
* @return array{0: User, 1: ManagedEnvironment, 2: EnvironmentReview, 3: ReviewPack}
|
|
*/
|
|
function spec379BrowserCurrentReadyPack(): array
|
|
{
|
|
[$user, $tenant] = createUserWithTenant(role: 'owner', workspaceRole: 'manager', clearCapabilityCaches: true);
|
|
$tenant->forceFill(['name' => 'Spec379 Browser Environment'])->save();
|
|
$snapshot = seedEnvironmentReviewEvidence($tenant, findingCount: 0, driftCount: 0);
|
|
$review = composeEnvironmentReviewForTest($tenant, $user, $snapshot);
|
|
$review->forceFill([
|
|
'status' => 'published',
|
|
'published_at' => now(),
|
|
'published_by_user_id' => (int) $user->getKey(),
|
|
])->save();
|
|
$review = markEnvironmentReviewCustomerSafeReady($review);
|
|
|
|
$zipContents = spec379BrowserZipContents();
|
|
$filePath = sprintf('review-packs/%s/spec379-browser.zip', $tenant->external_id);
|
|
Storage::disk('exports')->put($filePath, $zipContents);
|
|
|
|
$pack = ReviewPack::factory()->ready()->create([
|
|
'managed_environment_id' => (int) $tenant->getKey(),
|
|
'workspace_id' => (int) $tenant->workspace_id,
|
|
'environment_review_id' => (int) $review->getKey(),
|
|
'evidence_snapshot_id' => (int) $snapshot->getKey(),
|
|
'initiated_by_user_id' => (int) $user->getKey(),
|
|
'options' => [
|
|
'include_pii' => false,
|
|
'include_operations' => true,
|
|
],
|
|
'summary' => [
|
|
'governance_package' => [
|
|
'executive_summary' => 'Spec379 browser management handoff summary.',
|
|
],
|
|
'control_interpretation' => [
|
|
'non_certification_disclosure' => 'TenantPilot summarizes available evidence. This report is not a certification, legal attestation, audit opinion, or compliance guarantee.',
|
|
],
|
|
],
|
|
'file_path' => $filePath,
|
|
'file_disk' => 'exports',
|
|
'file_size' => strlen($zipContents),
|
|
'sha256' => hash('sha256', $zipContents),
|
|
'expires_at' => now()->addDay(),
|
|
]);
|
|
|
|
$review->forceFill([
|
|
'current_export_review_pack_id' => (int) $pack->getKey(),
|
|
])->save();
|
|
|
|
return [$user, $tenant, $review->fresh(['sections', 'evidenceSnapshot', 'currentExportReviewPack']), $pack->fresh(['tenant', 'environmentReview'])];
|
|
}
|
|
|
|
function spec379BrowserReadyManagementPdf(ReviewPack $pack): StoredReport
|
|
{
|
|
$pack->loadMissing('tenant');
|
|
$pdfBytes = '%PDF-1.7 Spec379 browser management report';
|
|
$filePath = sprintf('management-reports/%s/browser-%d.pdf', $pack->tenant->external_id, (int) $pack->getKey());
|
|
|
|
Storage::disk('exports')->put($filePath, $pdfBytes);
|
|
|
|
return StoredReport::factory()->managementReportPdf([
|
|
'title' => 'TenantPilot Management Report',
|
|
])->create([
|
|
'workspace_id' => (int) $pack->workspace_id,
|
|
'managed_environment_id' => (int) $pack->managed_environment_id,
|
|
'source_environment_review_id' => (int) $pack->environment_review_id,
|
|
'source_review_pack_id' => (int) $pack->getKey(),
|
|
'profile' => ReportProfileRegistry::CUSTOMER_EXECUTIVE,
|
|
'file_disk' => 'exports',
|
|
'file_path' => $filePath,
|
|
'file_size' => strlen($pdfBytes),
|
|
'sha256' => hash('sha256', $pdfBytes),
|
|
'generated_at' => now(),
|
|
]);
|
|
}
|
|
|
|
function spec379BrowserZipContents(): string
|
|
{
|
|
$tempFile = tempnam(sys_get_temp_dir(), 'spec379-browser-pack-');
|
|
|
|
if ($tempFile === false) {
|
|
throw new RuntimeException('Failed to allocate Spec379 browser archive.');
|
|
}
|
|
|
|
try {
|
|
$zip = new ZipArchive;
|
|
$result = $zip->open($tempFile, ZipArchive::CREATE | ZipArchive::OVERWRITE);
|
|
|
|
if ($result !== true) {
|
|
throw new RuntimeException("Failed to create Spec379 browser archive: {$result}");
|
|
}
|
|
|
|
$zip->addFromString('metadata.json', json_encode(['fixture' => 'spec379-browser'], JSON_THROW_ON_ERROR));
|
|
$zip->addFromString('executive-summary.md', 'Spec379 browser review pack.');
|
|
$zip->close();
|
|
|
|
$contents = file_get_contents($tempFile);
|
|
|
|
if (! is_string($contents) || $contents === '') {
|
|
throw new RuntimeException('Spec379 browser archive is empty.');
|
|
}
|
|
|
|
return $contents;
|
|
} finally {
|
|
if (file_exists($tempFile)) {
|
|
unlink($tempFile);
|
|
}
|
|
}
|
|
}
|
|
|
|
function spec379BrowserAuthenticate(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 spec379BrowserCopyScreenshot(string $name): void
|
|
{
|
|
$filename = 'spec379-management-report-pdf-'.$name.'.png';
|
|
$source = base_path('tests/Browser/Screenshots/'.$filename);
|
|
$targetDirectory = repo_path('specs/379-management-report-pdf-runtime/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');
|
|
}
|
|
}
|