Implementing report profiles and disclosure policy as per spec 357. Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #428
210 lines
9.0 KiB
PHP
210 lines
9.0 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Models\ManagedEnvironment;
|
|
use App\Models\ReviewPack;
|
|
use App\Services\ReviewPackService;
|
|
use App\Support\ReviewPacks\ReportProfileRegistry;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Illuminate\Support\Facades\Storage;
|
|
|
|
uses(RefreshDatabase::class);
|
|
|
|
beforeEach(function (): void {
|
|
Storage::fake('exports');
|
|
});
|
|
|
|
it('renders customer executive profile metadata and hides detailed appendix content on the signed report route', function (): void {
|
|
[$user, $tenant, $review, $pack] = spec357CreateCurrentReviewPackForRenderedReport(customerSafeReady: true);
|
|
|
|
$signedUrl = app(ReviewPackService::class)->generateRenderedReportUrl($pack, [
|
|
'source_surface' => 'review_pack',
|
|
'review_id' => (int) $review->getKey(),
|
|
'interpretation_version' => $review->controlInterpretationVersion(),
|
|
ReportProfileRegistry::QUERY_PARAMETER => ReportProfileRegistry::CUSTOMER_EXECUTIVE,
|
|
]);
|
|
|
|
$this->actingAs($user)
|
|
->get($signedUrl)
|
|
->assertOk()
|
|
->assertSee(__('localization.review.report_profile'))
|
|
->assertSee(__('localization.review.report_effective_profile'))
|
|
->assertSee(ReportProfileRegistry::CUSTOMER_EXECUTIVE)
|
|
->assertSee(__('localization.review.report_profile_customer_executive'))
|
|
->assertSee(__('localization.review.report_audience_customer_executive'))
|
|
->assertSee(__('localization.review.disclosure_policy'))
|
|
->assertSee(__('localization.review.proof_state_assumed'))
|
|
->assertSee(__('localization.review.report_appendix_hidden_for_profile'))
|
|
->assertDontSee('Spec357 Technical Control');
|
|
});
|
|
|
|
it('shows appendix detail for the technical customer profile while keeping the route signed and read-only', function (): void {
|
|
[$user, $tenant, $review, $pack] = spec357CreateCurrentReviewPackForRenderedReport(customerSafeReady: true);
|
|
|
|
$signedUrl = app(ReviewPackService::class)->generateRenderedReportUrl($pack, [
|
|
'source_surface' => 'review_pack',
|
|
'review_id' => (int) $review->getKey(),
|
|
'interpretation_version' => $review->controlInterpretationVersion(),
|
|
ReportProfileRegistry::QUERY_PARAMETER => ReportProfileRegistry::CUSTOMER_TECHNICAL,
|
|
]);
|
|
|
|
$this->actingAs($user)
|
|
->get($signedUrl)
|
|
->assertOk()
|
|
->assertSee(ReportProfileRegistry::CUSTOMER_TECHNICAL)
|
|
->assertSee(__('localization.review.report_profile_customer_technical'))
|
|
->assertSee('Spec357 Technical Control')
|
|
->assertDontSee(__('localization.review.report_appendix_hidden_for_profile'));
|
|
});
|
|
|
|
it('fails closed to the internal msp review profile for invalid or placeholder profile requests', function (string $requestedProfile): void {
|
|
[$user, $tenant, $review, $pack] = spec357CreateCurrentReviewPackForRenderedReport(customerSafeReady: true);
|
|
|
|
$signedUrl = app(ReviewPackService::class)->generateRenderedReportUrl($pack, [
|
|
'source_surface' => 'review_pack',
|
|
'review_id' => (int) $review->getKey(),
|
|
'interpretation_version' => $review->controlInterpretationVersion(),
|
|
ReportProfileRegistry::QUERY_PARAMETER => $requestedProfile,
|
|
]);
|
|
|
|
$response = $this->actingAs($user)->get($signedUrl);
|
|
|
|
$response->assertOk()
|
|
->assertSee(__('localization.review.report_profile_internal_msp_review'))
|
|
->assertSee(ReportProfileRegistry::INTERNAL_MSP_REVIEW)
|
|
->assertSee($requestedProfile)
|
|
->assertSee(__('localization.review.report_effective_profile'))
|
|
->assertSee(__('localization.review.report_requested_profile'))
|
|
->assertSee(__('localization.review.report_profile_fallback_notice'))
|
|
->assertSee(__('localization.review.proof_state_verified'));
|
|
})->with([
|
|
'unknown profile' => ['unknown_profile_key'],
|
|
'framework placeholder' => [ReportProfileRegistry::FRAMEWORK_READINESS],
|
|
]);
|
|
|
|
it('keeps customer-facing profiles visibly limited when pii-bearing output is requested', function (): void {
|
|
[$user, $tenant, $review, $pack] = spec357CreateCurrentReviewPackForRenderedReport(
|
|
packOverrides: [
|
|
'options' => [
|
|
'include_pii' => true,
|
|
'include_operations' => true,
|
|
],
|
|
],
|
|
customerSafeReady: true,
|
|
);
|
|
|
|
$signedUrl = app(ReviewPackService::class)->generateRenderedReportUrl($pack, [
|
|
'source_surface' => 'review_pack',
|
|
'review_id' => (int) $review->getKey(),
|
|
'interpretation_version' => $review->controlInterpretationVersion(),
|
|
ReportProfileRegistry::QUERY_PARAMETER => ReportProfileRegistry::CUSTOMER_EXECUTIVE,
|
|
]);
|
|
|
|
$this->actingAs($user)
|
|
->get($signedUrl)
|
|
->assertOk()
|
|
->assertSee(__('localization.review.report_profile_customer_executive'))
|
|
->assertSee(__('localization.review.report_external_sharing_warning'))
|
|
->assertSee(__('localization.review.report_disclosure_customer_profile_internal_only'))
|
|
->assertSee(__('localization.review.proof_state_missing'))
|
|
->assertDontSee(__('localization.review.report_state_customer_safe_ready'));
|
|
});
|
|
|
|
/**
|
|
* @param array<string, mixed>|null $packOverrides
|
|
* @return array{0:\App\Models\User,1:ManagedEnvironment,2:\App\Models\EnvironmentReview,3:ReviewPack}
|
|
*/
|
|
function spec357CreateCurrentReviewPackForRenderedReport(
|
|
?array $packOverrides = [],
|
|
bool $customerSafeReady = false,
|
|
?\App\Models\EvidenceSnapshot $snapshot = null,
|
|
): array {
|
|
$packOverrides ??= [];
|
|
$tenant = ManagedEnvironment::factory()->create();
|
|
[$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'owner');
|
|
$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();
|
|
|
|
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.',
|
|
],
|
|
],
|
|
'highlights' => ['Spec357 appendix highlight.'],
|
|
],
|
|
),
|
|
])->save();
|
|
}
|
|
|
|
$filePath = 'review-packs/'.$tenant->external_id.'/spec357-rendered-report.zip';
|
|
Storage::disk('exports')->put($filePath, 'PK-spec357-rendered-report-content');
|
|
|
|
$summary = array_replace_recursive([
|
|
'governance_package' => [
|
|
'executive_summary' => 'The released review is ready for management handoff.',
|
|
'evidence_basis_summary' => 'The report is anchored to the current released evidence snapshot.',
|
|
'top_findings' => [],
|
|
'accepted_risks' => [],
|
|
'decision_summary' => [
|
|
'status' => 'none',
|
|
'summary' => '',
|
|
'next_action' => '',
|
|
'entries' => [],
|
|
],
|
|
],
|
|
'control_interpretation' => [
|
|
'non_certification_disclosure' => 'TenantPilot summarizes available service-delivery evidence for governance review. This report is not a certification, legal attestation, audit opinion, or compliance guarantee.',
|
|
],
|
|
'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'] : []);
|
|
|
|
$packAttributes = array_merge([
|
|
'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' => $summary,
|
|
'file_path' => $filePath,
|
|
'file_disk' => 'exports',
|
|
'sha256' => hash('sha256', 'PK-spec357-rendered-report-content'),
|
|
'expires_at' => now()->addDay(),
|
|
], $packOverrides);
|
|
$packAttributes['summary'] = $summary;
|
|
|
|
$pack = ReviewPack::factory()->ready()->create($packAttributes);
|
|
|
|
$review->forceFill([
|
|
'current_export_review_pack_id' => (int) $pack->getKey(),
|
|
])->save();
|
|
|
|
return [$user, $tenant, $review->fresh(['sections', 'evidenceSnapshot', 'currentExportReviewPack']), $pack->fresh()];
|
|
}
|