create([ 'tenant_id' => (int) $tenant->getKey(), 'report_type' => StoredReport::REPORT_TYPE_ENTRA_ADMIN_ROLES, 'payload' => [ 'roles' => [ ['displayName' => 'Global Administrator'], ], ], ]); Finding::factory()->create([ 'tenant_id' => (int) $tenant->getKey(), 'workspace_id' => (int) $tenant->workspace_id, ]); Finding::factory()->create([ 'tenant_id' => (int) $tenant->getKey(), 'workspace_id' => (int) $tenant->workspace_id, 'finding_type' => Finding::FINDING_TYPE_DRIFT, ]); OperationRun::factory()->forTenant($tenant)->create(); /** @var EvidenceSnapshotService $service */ $service = app(EvidenceSnapshotService::class); $payload = $service->buildSnapshotPayload($tenant); $snapshot = EvidenceSnapshot::query()->create([ 'tenant_id' => (int) $tenant->getKey(), 'workspace_id' => (int) $tenant->workspace_id, 'status' => EvidenceSnapshotStatus::Active->value, 'fingerprint' => $payload['fingerprint'], 'completeness_state' => $payload['completeness'], 'summary' => $payload['summary'], 'generated_at' => now(), ]); foreach ($payload['items'] as $item) { $snapshot->items()->create([ 'tenant_id' => (int) $tenant->getKey(), 'workspace_id' => (int) $tenant->workspace_id, 'dimension_key' => $item['dimension_key'], 'state' => $item['state'], 'required' => $item['required'], 'source_kind' => $item['source_kind'], 'source_record_type' => $item['source_record_type'], 'source_record_id' => $item['source_record_id'], 'source_fingerprint' => $item['source_fingerprint'], 'measured_at' => $item['measured_at'], 'freshness_at' => $item['freshness_at'], 'summary_payload' => $item['summary_payload'], 'sort_order' => $item['sort_order'], ]); } return $snapshot; } it('redacts protected report fields while preserving safe configuration evidence in review-pack exports', function (): void { [$user, $tenant] = createUserWithTenant(); StoredReport::factory()->create([ 'tenant_id' => (int) $tenant->getKey(), 'report_type' => StoredReport::REPORT_TYPE_PERMISSION_POSTURE, 'payload' => [ 'passwordMinimumLength' => 14, 'clientSecret' => 'super-secret-value', ], ]); createRedactionReviewPackSnapshot($tenant); Notification::fake(); $pack = app(ReviewPackService::class)->generate($tenant, $user, [ 'include_pii' => true, 'include_operations' => false, ]); $job = new GenerateReviewPackJob( reviewPackId: (int) $pack->getKey(), operationRunId: (int) $pack->operation_run_id, ); app()->call([$job, 'handle']); $pack->refresh(); $zipContent = Storage::disk('exports')->get($pack->file_path); $tempFile = tempnam(sys_get_temp_dir(), 'spec120-review-pack-'); file_put_contents($tempFile, $zipContent); $zip = new ZipArchive; $zip->open($tempFile); $report = json_decode((string) $zip->getFromName('reports/permission_posture.json'), true, 512, JSON_THROW_ON_ERROR); $metadata = json_decode((string) $zip->getFromName('metadata.json'), true, 512, JSON_THROW_ON_ERROR); expect($report['passwordMinimumLength'] ?? null)->toBe(14); expect($report['clientSecret'] ?? null)->toBe('[REDACTED]'); expect(data_get($metadata, 'redaction_integrity.protected_values_hidden'))->toBeTrue(); $zip->close(); unlink($tempFile); });