TenantAtlas/apps/platform/tests/Browser/Spec357ReportProfilesSmokeTest.php
ahmido b7907bd69d feat: add report profile and disclosure policy to rendered review reports (#428)
Implementing report profiles and disclosure policy as per spec 357.

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #428
2026-06-06 09:41:19 +00:00

295 lines
12 KiB
PHP

<?php
declare(strict_types=1);
use App\Models\ManagedEnvironment;
use App\Models\ReviewPack;
use App\Models\User;
use App\Services\ReviewPackService;
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('Spec357 smokes report profile variants on the rendered report route', function (): void {
[$user, $customerEnvironment, $customerReview, $customerPack] = spec357BrowserCreateProfilePack(
environmentName: 'Spec357 Browser Customer',
customerSafeReady: true,
);
[$limitedUser, $limitedEnvironment, $limitedReview, $limitedPack] = spec357BrowserCreateProfilePack(
user: $user,
workspaceId: (int) $customerEnvironment->workspace_id,
environmentName: 'Spec357 Browser Limited',
customerSafeReady: true,
packOverrides: [
'options' => [
'include_pii' => true,
'include_operations' => true,
],
],
);
spec357AuthenticateBrowser($this, $user, $customerEnvironment);
$customerExecutiveUrl = app(ReviewPackService::class)->generateRenderedReportUrl($customerPack, [
'source_surface' => 'review_pack',
'review_id' => (int) $customerReview->getKey(),
'interpretation_version' => $customerReview->controlInterpretationVersion(),
ReportProfileRegistry::QUERY_PARAMETER => ReportProfileRegistry::CUSTOMER_EXECUTIVE,
]);
visit($customerExecutiveUrl)
->resize(1280, 1440)
->waitForText(__('localization.review.report_profile_customer_executive'))
->assertSee(ReportProfileRegistry::CUSTOMER_EXECUTIVE)
->assertSee(__('localization.review.report_appendix_hidden_for_profile'))
->assertDontSee('Spec357 Technical Control')
->assertNoJavaScriptErrors()
->assertNoConsoleLogs()
->screenshot(true, spec357BrowserScreenshotName('01-customer-executive'));
spec357CopyBrowserScreenshot('01-customer-executive');
$customerTechnicalUrl = app(ReviewPackService::class)->generateRenderedReportUrl($customerPack, [
'source_surface' => 'review_pack',
'review_id' => (int) $customerReview->getKey(),
'interpretation_version' => $customerReview->controlInterpretationVersion(),
ReportProfileRegistry::QUERY_PARAMETER => ReportProfileRegistry::CUSTOMER_TECHNICAL,
]);
visit($customerTechnicalUrl)
->resize(1280, 1440)
->waitForText(__('localization.review.report_profile_customer_technical'))
->assertSee('Spec357 Technical Control')
->assertDontSee(__('localization.review.report_appendix_hidden_for_profile'))
->assertNoJavaScriptErrors()
->assertNoConsoleLogs()
->screenshot(true, spec357BrowserScreenshotName('02-customer-technical'));
spec357CopyBrowserScreenshot('02-customer-technical');
$internalUrl = app(ReviewPackService::class)->generateRenderedReportUrl($limitedPack, [
'source_surface' => 'review_pack',
'review_id' => (int) $limitedReview->getKey(),
'interpretation_version' => $limitedReview->controlInterpretationVersion(),
ReportProfileRegistry::QUERY_PARAMETER => ReportProfileRegistry::INTERNAL_MSP_REVIEW,
]);
visit($internalUrl)
->resize(1280, 1440)
->waitForText(__('localization.review.report_profile_internal_msp_review'))
->assertSee(__('localization.review.report_profile_internal_msp_review'))
->assertSee(__('localization.review.proof_state_not_applicable'))
->assertSee('Spec357 Technical Control')
->assertNoJavaScriptErrors()
->assertNoConsoleLogs()
->screenshot(true, spec357BrowserScreenshotName('03-internal-msp'));
spec357CopyBrowserScreenshot('03-internal-msp');
$auditorUrl = app(ReviewPackService::class)->generateRenderedReportUrl($customerPack, [
'source_surface' => 'review_pack',
'review_id' => (int) $customerReview->getKey(),
'interpretation_version' => $customerReview->controlInterpretationVersion(),
ReportProfileRegistry::QUERY_PARAMETER => ReportProfileRegistry::AUDITOR_APPENDIX,
]);
visit($auditorUrl)
->resize(1280, 1440)
->waitForText(__('localization.review.report_profile_auditor_appendix'))
->assertSee(__('localization.review.report_audience_controlled_auditor'))
->assertSee('Spec357 Technical Control')
->assertNoJavaScriptErrors()
->assertNoConsoleLogs()
->screenshot(true, spec357BrowserScreenshotName('04-auditor-appendix'));
spec357CopyBrowserScreenshot('04-auditor-appendix');
$fallbackUrl = app(ReviewPackService::class)->generateRenderedReportUrl($customerPack, [
'source_surface' => 'review_pack',
'review_id' => (int) $customerReview->getKey(),
'interpretation_version' => $customerReview->controlInterpretationVersion(),
ReportProfileRegistry::QUERY_PARAMETER => ReportProfileRegistry::FRAMEWORK_READINESS,
]);
visit($fallbackUrl)
->resize(1280, 1440)
->waitForText(__('localization.review.report_profile_fallback_notice'))
->assertSee(ReportProfileRegistry::FRAMEWORK_READINESS)
->assertSee(ReportProfileRegistry::INTERNAL_MSP_REVIEW)
->assertSee(__('localization.review.report_profile_internal_msp_review'))
->assertNoJavaScriptErrors()
->assertNoConsoleLogs()
->screenshot(true, spec357BrowserScreenshotName('05-fallback-framework'));
spec357CopyBrowserScreenshot('05-fallback-framework');
expect($limitedUser)->toBeInstanceOf(User::class);
});
function spec357BrowserScreenshotName(string $name): string
{
return 'spec357-report-profiles-'.$name;
}
function spec357CopyBrowserScreenshot(string $name): void
{
$filename = spec357BrowserScreenshotName($name).'.png';
$primarySource = base_path('tests/Browser/Screenshots/'.$filename);
$fallbackSource = \Pest\Browser\Support\Screenshot::path($filename);
$targetDirectory = repo_path('specs/357-report-profiles-disclosure-policy-v1/artifacts/screenshots');
if (! is_dir($targetDirectory)) {
@mkdir($targetDirectory, 0755, true);
}
$source = null;
for ($attempt = 0; $attempt < 50 && $source === null; $attempt++) {
foreach ([$primarySource, $fallbackSource] as $candidate) {
if (is_file($candidate)) {
$source = $candidate;
break;
}
}
if ($source !== null) {
break;
}
usleep(100_000);
clearstatcache(true, $primarySource);
clearstatcache(true, $fallbackSource);
}
if (is_string($source) && is_file($source) && is_dir($targetDirectory) && is_writable($targetDirectory)) {
@copy($source, $targetDirectory.DIRECTORY_SEPARATOR.$name.'.png');
}
}
function spec357AuthenticateBrowser(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>|null $packOverrides
* @return array{0:User,1:ManagedEnvironment,2:\App\Models\EnvironmentReview,3:ReviewPack}
*/
function spec357BrowserCreateProfilePack(
?User $user = null,
?int $workspaceId = null,
string $environmentName = 'Spec357 Browser Environment',
bool $customerSafeReady = false,
?array $packOverrides = [],
): array {
$workspaceId ??= null;
$environment = ManagedEnvironment::factory()->active()->create([
'workspace_id' => $workspaceId,
'name' => $environmentName,
]);
if ($user === null) {
[$user, $environment] = createUserWithTenant(tenant: $environment, role: 'owner', workspaceRole: 'manager');
} else {
createUserWithTenant(tenant: $environment, user: $user, role: 'owner', workspaceRole: 'manager');
}
$snapshot = seedEnvironmentReviewEvidence($environment, findingCount: 0, driftCount: 0);
$review = composeEnvironmentReviewForTest($environment, $user, $snapshot);
$review->forceFill([
'status' => 'published',
'published_at' => now(),
'published_by_user_id' => (int) $user->getKey(),
])->save();
if ($customerSafeReady) {
$review = markEnvironmentReviewCustomerSafeReady($review);
}
$review->loadMissing('sections');
$appendixSection = $review->sections->first();
if ($appendixSection instanceof \App\Models\EnvironmentReviewSection) {
$appendixSection->forceFill([
'render_payload' => array_replace_recursive(
is_array($appendixSection->render_payload) ? $appendixSection->render_payload : [],
[
'entries' => [
[
'title' => 'Spec357 Technical Control',
'summary' => 'Visible only on appendix-capable profiles.',
],
],
],
),
])->save();
}
$filePath = 'review-packs/'.($environment->external_id ?: 'spec357').'/browser-report.zip';
Storage::disk('exports')->put($filePath, 'PK-spec357-browser-report');
$summary = array_replace_recursive([
'governance_package' => [
'executive_summary' => 'Spec 357 browser report summary.',
'top_findings' => [],
'accepted_risks' => [],
'decision_summary' => [
'status' => 'none',
'summary' => '',
'next_action' => '',
'entries' => [],
],
],
'control_interpretation' => [
'non_certification_disclosure' => 'Spec 357 browser non-certification disclosure.',
],
'recommended_next_actions' => [],
'delivery_bundle' => [
'executive_entrypoint_file' => 'executive-summary.md',
'appendix_files' => ['metadata.json', 'summary.json', 'sections.json'],
],
], is_array($packOverrides['summary'] ?? null) ? $packOverrides['summary'] : []);
$pack = ReviewPack::factory()->ready()->create(array_merge([
'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' => [
'include_pii' => false,
'include_operations' => true,
],
'summary' => $summary,
'file_path' => $filePath,
'file_disk' => 'exports',
'generated_at' => now()->subMinutes(3),
'expires_at' => now()->addDay(),
], $packOverrides ?? []));
$review->forceFill([
'current_export_review_pack_id' => (int) $pack->getKey(),
])->save();
return [$user, $environment, $review->fresh(['sections', 'evidenceSnapshot', 'currentExportReviewPack']), $pack->fresh()];
}