create(['name' => 'Spec342 Ready Environment']); [$user, $environment] = createUserWithTenant(tenant: $environment, role: 'owner', workspaceRole: 'manager'); $snapshot = seedEnvironmentReviewEvidence($environment, findingCount: 0, driftCount: 0); $run = OperationRun::factory()->forTenant($environment)->create([ 'type' => OperationRunType::ReviewPackGenerate->value, 'status' => OperationRunStatus::Completed->value, 'initiator_name' => 'Spec342 Operator', ]); $review = spec342PublishedReview($environment, $user, $snapshot, [ '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' => [], ], ], ]); $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(), 'operation_run_id' => (int) $run->getKey(), 'initiated_by_user_id' => (int) $user->getKey(), 'options' => [ 'include_pii' => false, 'include_operations' => true, ], ]); $review->forceFill([ 'current_export_review_pack_id' => (int) $pack->getKey(), 'operation_run_id' => (int) $run->getKey(), ])->save(); $component = spec342WorkspaceComponent($user, $environment); $component ->assertSee('What is the current review pack output state?') ->assertSee('Customer-safe review pack ready') ->assertSee('Stakeholders can use the current review pack and released review as the evidence path.') ->assertSee('Review consumption flow') ->assertSee('Review data') ->assertSee('Findings triaged') ->assertSee('Accepted risks reviewed') ->assertSee('Customer-safe output') ->assertSee('Findings needing attention') ->assertSee('No open findings require customer action.') ->assertSee('Review pack state') ->assertSee('Export ready') ->assertSee('Download customer-safe review pack') ->assertSee('Operation proof') ->assertSee('Spec342 Operator') ->assertDontSee('Auditor-ready') ->assertDontSee('environment is healthy') ->assertDontSee('compliant'); $html = $component->html(); expect(substr_count($html, 'data-testid="customer-review-primary-action"'))->toBe(1) ->and(substr_count($html, 'data-testid="customer-review-readiness-step"'))->toBe(6) ->and($html)->toContain('source_surface=customer_review_workspace') ->and($html)->not->toContain('/admin/t/'); }); it('shows not-ready proof states without raw diagnostics or false output claims', function (): void { $environment = ManagedEnvironment::factory()->create(['name' => 'Spec342 Evidence Missing']); [$user, $environment] = createUserWithTenant(tenant: $environment, role: 'readonly'); $snapshot = seedPartialEnvironmentReviewEvidence($environment, findingCount: 0, driftCount: 0); $review = spec342PublishedReview($environment, $user, $snapshot, [ 'debug_payload' => 'raw payload should stay hidden', 'provider_response' => 'provider response should stay hidden', 'stack_trace' => 'stack trace should stay hidden', 'source_fingerprint' => 'spec342-hidden-fingerprint', 'control_interpretation' => [ 'version_key' => ComplianceEvidenceMappingV1::VERSION_KEY, 'controls' => [ [ 'control_key' => 'customer-output', 'title' => 'Customer output', 'readiness_bucket' => 'review_recommended', 'readiness_label' => 'Review recommended', 'primary_reason' => 'Evidence basis needs review.', 'recommended_next_action' => 'Review evidence before sharing.', ], ], ], 'governance_package' => [ 'decision_summary' => [ 'status' => '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' => [], ], ], ], normalizeOutputReadiness: false); $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' => [ 'include_pii' => false, 'include_operations' => true, ], ]); $review->forceFill(['current_export_review_pack_id' => (int) $pack->getKey()])->save(); $component = spec342WorkspaceComponent($user, $environment) ->assertSee('Published with limitations') ->assertSee('The review package is published, but the evidence basis is incomplete.') ->assertSee('Customer-safe output') ->assertSee('Needs review') ->assertSee('Diagnostics') ->assertSee('Collapsed') ->assertDontSee('Ready to share') ->assertSee('Export ready') ->assertSee('Download review pack with limitations') ->assertDontSee('raw payload should stay hidden') ->assertDontSee('provider response should stay hidden') ->assertDontSee('stack trace should stay hidden') ->assertDontSee('spec342-hidden-fingerprint'); expect($component->html())->not->toContain('data-testid="customer-review-diagnostics" open'); }); it('uses concrete findings follow-up copy and keeps review-pack download primary-only', function (): void { $environment = ManagedEnvironment::factory()->create(['name' => 'Spec342 Findings Follow-up']); [$user, $environment] = createUserWithTenant(tenant: $environment, role: 'owner', workspaceRole: 'manager'); $snapshot = seedEnvironmentReviewEvidence($environment, findingCount: 0, driftCount: 0); $run = OperationRun::factory()->forTenant($environment)->create([ 'type' => OperationRunType::ReviewPackGenerate->value, 'status' => OperationRunStatus::Completed->value, 'initiator_name' => 'Spec342 Operator', ]); $review = spec342PublishedReview($environment, $user, $snapshot); $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(), 'operation_run_id' => (int) $run->getKey(), 'initiated_by_user_id' => (int) $user->getKey(), 'options' => [ 'include_pii' => false, 'include_operations' => true, ], ]); $review->forceFill([ 'current_export_review_pack_id' => (int) $pack->getKey(), 'operation_run_id' => (int) $run->getKey(), ])->save(); Finding::factory()->create([ 'managed_environment_id' => (int) $environment->getKey(), 'workspace_id' => (int) $environment->workspace_id, 'severity' => Finding::SEVERITY_CRITICAL, 'status' => Finding::STATUS_NEW, ]); $component = spec342WorkspaceComponent($user, $environment) ->assertSee('Published with limitations') ->assertSee('1 open finding needs attention; 1 is high impact. Keep open findings visible before customer handoff.') ->assertSee('Do not treat this review as share-ready until open findings are resolved, accepted, or explicitly reviewed.') ->assertSee('Open review') ->assertSee('Review pack state') ->assertSee('Download review pack with limitations') ->assertDontSee('TenantPilot recorded an access, scope, or configuration issue'); $html = $component->html(); expect(substr_count($html, 'data-testid="customer-review-primary-action"'))->toBe(1) ->and($html)->toContain('data-testid="customer-review-findings-summary"') ->and($html)->not->toContain('data-testid="customer-review-readiness-dimensions"'); }); it('surfaces accepted-risk owner rationale and missing review dates when repo-backed', function (): void { $environment = ManagedEnvironment::factory()->create(['name' => 'Spec342 Accepted Risk']); [$user, $environment] = createUserWithTenant(tenant: $environment, role: 'readonly'); $owner = User::factory()->create(['name' => 'Spec342 Risk Owner']); $finding = Finding::factory()->create([ 'managed_environment_id' => (int) $environment->getKey(), 'workspace_id' => (int) $environment->workspace_id, 'status' => Finding::STATUS_RISK_ACCEPTED, ]); $findingWithoutReviewDate = Finding::factory()->create([ 'managed_environment_id' => (int) $environment->getKey(), 'workspace_id' => (int) $environment->workspace_id, 'status' => Finding::STATUS_RISK_ACCEPTED, ]); FindingException::query()->create([ 'workspace_id' => (int) $environment->workspace_id, 'managed_environment_id' => (int) $environment->getKey(), 'finding_id' => (int) $findingWithoutReviewDate->getKey(), 'status' => FindingException::STATUS_ACTIVE, 'current_validity_state' => FindingException::VALIDITY_VALID, 'requested_by_user_id' => (int) $user->getKey(), 'request_reason' => 'Customer-approved maintenance window.', 'owner_user_id' => (int) $owner->getKey(), 'approved_by_user_id' => (int) $owner->getKey(), 'requested_at' => now()->subDays(3), 'approved_at' => now()->subDays(2), 'effective_from' => now()->subDays(2), 'review_due_at' => now()->addDays(30), ]); FindingException::query()->create([ 'workspace_id' => (int) $environment->workspace_id, 'managed_environment_id' => (int) $environment->getKey(), 'finding_id' => (int) $finding->getKey(), 'status' => FindingException::STATUS_ACTIVE, 'current_validity_state' => FindingException::VALIDITY_EXPIRING, 'requested_by_user_id' => (int) $user->getKey(), 'request_reason' => 'Pending owner confirmation.', 'requested_at' => now()->subDay(), 'approved_at' => now()->subDay(), 'effective_from' => now()->subDay(), 'review_due_at' => null, 'expires_at' => null, ]); $snapshot = seedEnvironmentReviewEvidence($environment, findingCount: 0, driftCount: 0); spec342PublishedReview($environment, $user, $snapshot, [ 'governance_package' => [ 'accepted_risks' => [ [ 'title' => 'Accepted risk renewal', 'governance_state' => 'expiring_exception', 'customer_summary' => 'Accepted risk requires customer awareness.', ], ], ], ]); spec342WorkspaceComponent($user, $environment) ->assertSee('Accepted risks') ->assertSee('2') ->assertSee('Spec342 Risk Owner') ->assertSee(now()->addDays(30)->toDateString()) ->assertSee('Customer-approved maintenance window.') ->assertSee('Review date not recorded') ->assertSee('Accepted risk requires customer awareness.') ->assertDontSee('raw operation'); }); it('keeps environment_id as the only canonical workspace filter and rejects cross-workspace targets', function (): void { $allowed = ManagedEnvironment::factory()->create(['name' => 'Spec342 Allowed Environment']); [$user, $allowed] = createUserWithTenant(tenant: $allowed, role: 'readonly'); $other = ManagedEnvironment::factory()->create([ 'workspace_id' => (int) $allowed->workspace_id, 'name' => 'Spec342 Other Environment', ]); createUserWithTenant(tenant: $other, user: $user, role: 'readonly'); $foreign = ManagedEnvironment::factory()->create(['name' => 'Spec342 Foreign Environment']); spec342PublishedReview($allowed, $user, seedEnvironmentReviewEvidence($allowed)); spec342PublishedReview($other, $user, seedEnvironmentReviewEvidence($other)); $this->actingAs($user)->withSession([WorkspaceContext::SESSION_KEY => (int) $allowed->workspace_id]); Livewire::withQueryParams([ 'environment_id' => (int) $allowed->getKey(), 'tenant' => (string) $other->external_id, 'tenant_id' => (int) $other->getKey(), ]) ->actingAs($user) ->test(CustomerReviewWorkspace::class) ->assertSet('tableFilters.managed_environment_id.value', (string) $allowed->getKey()) ->assertCanSeeTableRecords([$allowed->fresh()]) ->assertCanNotSeeTableRecords([$other->fresh()]) ->assertSee('Environment filter:') ->assertSee('Spec342 Allowed Environment') ->assertDontSee('/admin/t', false) ->assertDontSee('tenant_id=', false); $this->actingAs($user) ->withSession([WorkspaceContext::SESSION_KEY => (int) $allowed->workspace_id]) ->get(CustomerReviewWorkspace::getUrl(panel: 'admin').'?environment_id='.(string) $foreign->getKey()) ->assertNotFound(); }); function spec342WorkspaceComponent(User $user, ManagedEnvironment $environment): mixed { $workspaceId = (int) $environment->workspace_id; session()->put(WorkspaceContext::SESSION_KEY, $workspaceId); setAdminPanelContext(); return Livewire::actingAs($user) ->test(CustomerReviewWorkspace::class); } function spec342PublishedReview( ManagedEnvironment $environment, User $user, \App\Models\EvidenceSnapshot $snapshot, array $summaryOverrides = [], bool $normalizeOutputReadiness = true, ): \App\Models\EnvironmentReview { $review = composeEnvironmentReviewForTest($environment, $user, $snapshot); $summary = array_replace_recursive(is_array($review->summary) ? $review->summary : [], $summaryOverrides); $review->forceFill([ 'status' => EnvironmentReviewStatus::Published->value, 'summary' => $summary, 'generated_at' => now(), 'published_at' => now(), 'published_by_user_id' => (int) $user->getKey(), ])->save(); if ($normalizeOutputReadiness) { return markEnvironmentReviewCustomerSafeReady($review); } return $review->refresh(); }