create([ 'status' => 'active', 'name' => 'Visible ManagedEnvironment', 'external_id' => 'visible-tenant', ]); [$user, $visibleTenant] = createUserWithTenant($visibleTenant, role: 'readonly', workspaceRole: 'readonly'); $hiddenTenant = ManagedEnvironment::factory()->create([ 'status' => 'active', 'workspace_id' => (int) $visibleTenant->workspace_id, 'name' => 'Hidden ManagedEnvironment', 'external_id' => 'hidden-tenant', ]); decisionRegisterPageException( tenant: $visibleTenant, actor: $user, status: FindingException::STATUS_PENDING, validityState: FindingException::VALIDITY_MISSING_SUPPORT, decisionType: FindingExceptionDecision::TYPE_REQUESTED, decisionReason: 'Visible approval request', exceptionAttributes: [ 'requested_at' => now()->subDays(2), 'review_due_at' => now()->addDay(), ], decisionAttributes: [ 'decided_at' => now()->subDays(2), ], ); decisionRegisterPageException( tenant: $visibleTenant, actor: $user, status: FindingException::STATUS_REJECTED, validityState: FindingException::VALIDITY_REJECTED, decisionType: FindingExceptionDecision::TYPE_REJECTED, decisionReason: 'Recently rejected closure reason', exceptionAttributes: [ 'rejected_at' => now()->subDays(2), 'review_due_at' => now()->subDays(3), ], decisionAttributes: [ 'decided_at' => now()->subDays(2), ], ); decisionRegisterPageException( tenant: $hiddenTenant, actor: $user, status: FindingException::STATUS_PENDING, validityState: FindingException::VALIDITY_MISSING_SUPPORT, decisionType: FindingExceptionDecision::TYPE_REQUESTED, decisionReason: 'Hidden tenant request', ); $this->actingAs($user) ->withSession([WorkspaceContext::SESSION_KEY => (int) $visibleTenant->workspace_id]) ->get(DecisionRegister::getUrl(panel: 'admin')) ->assertOk() ->assertSee('Decision register') ->assertSee('Visible ManagedEnvironment') ->assertSee('Review approval') ->assertSee('Open decision') ->assertDontSee('Recently rejected closure reason') ->assertDontSee('Hidden tenant request'); $this->actingAs($user) ->withSession([WorkspaceContext::SESSION_KEY => (int) $visibleTenant->workspace_id]) ->get(DecisionRegister::getUrl(panel: 'admin').'?register_state=recently_closed') ->assertOk() ->assertSee('Recently rejected closure reason') ->assertDontSee('Visible approval request'); }); it('shows truthful filtered empty states for tenant and register-state filters', function (): void { $alphaTenant = ManagedEnvironment::factory()->create([ 'status' => 'active', 'name' => 'Alpha ManagedEnvironment', 'external_id' => 'alpha-tenant', ]); [$user, $alphaTenant] = createUserWithTenant($alphaTenant, role: 'owner', workspaceRole: 'owner'); $bravoTenant = ManagedEnvironment::factory()->create([ 'status' => 'active', 'workspace_id' => (int) $alphaTenant->workspace_id, 'name' => 'Bravo ManagedEnvironment', 'external_id' => 'bravo-tenant', ]); $user->tenants()->syncWithoutDetaching([ (int) $bravoTenant->getKey() => ['role' => 'owner'], ]); decisionRegisterPageException( tenant: $bravoTenant, actor: $user, status: FindingException::STATUS_PENDING, validityState: FindingException::VALIDITY_MISSING_SUPPORT, decisionType: FindingExceptionDecision::TYPE_REQUESTED, decisionReason: 'Bravo tenant request', ); $this->actingAs($user) ->withSession([WorkspaceContext::SESSION_KEY => (int) $alphaTenant->workspace_id]) ->get(DecisionRegister::getUrl(panel: 'admin').'?managed_environment_id='.(string) $alphaTenant->getKey()) ->assertOk() ->assertSee('This environment filter is hiding other visible decision follow-through') ->assertSee('Clear environment filter'); $this->actingAs($user) ->withSession([WorkspaceContext::SESSION_KEY => (int) $alphaTenant->workspace_id]) ->get(DecisionRegister::getUrl(panel: 'admin').'?register_state=recently_closed') ->assertOk() ->assertSee('No recently closed decisions match this filter right now.'); }); it('renders proof and operation affordances only when real links are available', function (): void { $tenant = ManagedEnvironment::factory()->create([ 'status' => 'active', 'name' => 'Proof ManagedEnvironment', 'external_id' => 'proof-tenant', ]); [$user, $tenant] = createUserWithTenant($tenant, role: 'owner', workspaceRole: 'owner'); $run = OperationRun::factory()->forTenant($tenant)->create([ 'type' => 'tenant.evidence.snapshot.generate', 'status' => OperationRunStatus::Completed->value, 'outcome' => OperationRunOutcome::Succeeded->value, 'completed_at' => now(), ]); $snapshot = EvidenceSnapshot::query()->create([ 'workspace_id' => (int) $tenant->workspace_id, 'managed_environment_id' => (int) $tenant->getKey(), 'operation_run_id' => (int) $run->getKey(), 'status' => EvidenceSnapshotStatus::Active->value, 'completeness_state' => EvidenceCompletenessState::Complete->value, 'summary' => ['finding_count' => 1], 'generated_at' => now(), ]); $withProof = decisionRegisterPageException( tenant: $tenant, actor: $user, status: FindingException::STATUS_PENDING, validityState: FindingException::VALIDITY_MISSING_SUPPORT, decisionType: FindingExceptionDecision::TYPE_REQUESTED, decisionReason: 'Proof-backed request', exceptionAttributes: [ 'evidence_summary' => ['reference_count' => 1], 'review_due_at' => now()->addDay(), ], ); $withProof->evidenceReferences()->create([ 'workspace_id' => (int) $tenant->workspace_id, 'managed_environment_id' => (int) $tenant->getKey(), 'source_type' => 'evidence_snapshot', 'source_id' => (string) $snapshot->getKey(), 'label' => 'Current evidence snapshot', 'summary_payload' => [], ]); decisionRegisterPageException( tenant: $tenant, actor: $user, status: FindingException::STATUS_ACTIVE, validityState: FindingException::VALIDITY_VALID, decisionType: FindingExceptionDecision::TYPE_APPROVED, decisionReason: 'No proof request', exceptionAttributes: [ 'approved_by_user_id' => (int) $user->getKey(), 'approved_at' => now()->subDay(), 'effective_from' => now()->subDay(), 'evidence_summary' => ['reference_count' => 0], 'review_due_at' => now()->addDays(2), ], ); $this->actingAs($user) ->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id]) ->get(DecisionRegister::getUrl(panel: 'admin')) ->assertOk() ->assertSee('1 proof item') ->assertSee('View evidence') ->assertSee('View operation') ->assertSee('No linked proof') ->assertSee('No operation linked') ->assertDontSee('/admin/t', false); }); /** * @param array $exceptionAttributes * @param array $decisionAttributes */ function decisionRegisterPageException( ManagedEnvironment $tenant, User $actor, string $status, string $validityState, string $decisionType, string $decisionReason, array $exceptionAttributes = [], array $decisionAttributes = [], ): FindingException { $finding = Finding::factory()->for($tenant)->create([ 'workspace_id' => (int) $tenant->workspace_id, ]); $exception = FindingException::query()->create(array_merge([ 'workspace_id' => (int) $tenant->workspace_id, 'managed_environment_id' => (int) $tenant->getKey(), 'finding_id' => (int) $finding->getKey(), 'requested_by_user_id' => (int) $actor->getKey(), 'owner_user_id' => (int) $actor->getKey(), 'status' => $status, 'current_validity_state' => $validityState, 'request_reason' => 'Decision register page test', 'requested_at' => now()->subDay(), 'review_due_at' => now()->addDay(), 'evidence_summary' => ['reference_count' => 0], ], $exceptionAttributes)); $decision = $exception->decisions()->create(array_merge([ 'workspace_id' => (int) $tenant->workspace_id, 'managed_environment_id' => (int) $tenant->getKey(), 'actor_user_id' => (int) $actor->getKey(), 'decision_type' => $decisionType, 'reason' => $decisionReason, 'metadata' => [], 'decided_at' => now()->subDay(), ], $decisionAttributes)); $exception->forceFill(['current_decision_id' => (int) $decision->getKey()])->save(); return $exception->fresh(['currentDecision']); }