create($tenant, $initialSnapshot, $user); $review = $reviewService->compose($review); EvidenceSnapshot::query() ->where('managed_environment_id', (int) $tenant->getKey()) ->where('status', 'active') ->update([ 'status' => 'expired', 'expires_at' => now(), ]); $refreshSnapshot = seedEnvironmentReviewEvidence( tenant: $tenant, findingCount: 6, driftCount: 2, operationRunCount: 2, ); $review = $reviewService->refresh($review, $user, $refreshSnapshot); $review = $reviewService->compose($review->fresh()); $published = $lifecycle->publish($review, $user, 'Publishing the current review pack.'); EvidenceSnapshot::query() ->where('managed_environment_id', (int) $tenant->getKey()) ->where('status', 'active') ->update([ 'status' => 'expired', 'expires_at' => now(), ]); $pack = app(ReviewPackService::class)->generateFromReview($published, $user, [ 'include_pii' => true, 'include_operations' => true, ]); $job = new GenerateReviewPackJob( reviewPackId: (int) $pack->getKey(), operationRunId: (int) $pack->operation_run_id, ); app()->call([$job, 'handle']); $nextReview = $lifecycle->createNextReview($published->fresh(), $user, seedEnvironmentReviewEvidence( tenant: $tenant, findingCount: 7, driftCount: 1, operationRunCount: 3, )); $lifecycle->archive($nextReview, $user, 'Replacing with a newer governance review.'); expect(AuditLog::query()->where('action', AuditActionId::EnvironmentReviewCreated->value)->exists())->toBeTrue() ->and(AuditLog::query()->where('action', AuditActionId::EnvironmentReviewRefreshed->value)->exists())->toBeTrue() ->and(AuditLog::query()->where('action', AuditActionId::EnvironmentReviewPublished->value)->exists())->toBeTrue() ->and(AuditLog::query()->where('action', AuditActionId::EnvironmentReviewExported->value)->exists())->toBeTrue() ->and(AuditLog::query()->where('action', AuditActionId::EnvironmentReviewSuccessorCreated->value)->exists())->toBeTrue() ->and(AuditLog::query()->where('action', AuditActionId::EnvironmentReviewArchived->value)->exists())->toBeTrue(); $exportAudit = AuditLog::query() ->where('action', AuditActionId::EnvironmentReviewExported->value) ->latest('id') ->first(); $publishAudit = AuditLog::query() ->where('action', AuditActionId::EnvironmentReviewPublished->value) ->latest('id') ->first(); $archiveAudit = AuditLog::query() ->where('action', AuditActionId::EnvironmentReviewArchived->value) ->latest('id') ->first(); expect($exportAudit)->not->toBeNull() ->and($exportAudit?->resource_type)->toBe('environment_review') ->and(data_get($exportAudit?->metadata, 'review_pack_id'))->toBe((int) $pack->getKey()) ->and(data_get($publishAudit?->metadata, 'reason'))->toBe('Publishing the current review pack.') ->and(data_get($archiveAudit?->metadata, 'reason'))->toBe('Replacing with a newer governance review.'); }); it('records customer workspace interpretation metadata when a environment review is opened', function (): void { [$user, $tenant] = createUserWithTenant(role: 'readonly'); $snapshot = seedEnvironmentReviewEvidence($tenant); $review = composeEnvironmentReviewForTest($tenant, $user, $snapshot); $review->forceFill([ 'status' => 'published', 'published_at' => now(), 'published_by_user_id' => (int) $user->getKey(), ])->save(); setAdminEnvironmentContext($tenant); $this->actingAs($user) ->get(EnvironmentReviewResource::environmentScopedUrl('view', ['record' => $review], $tenant).'?'.http_build_query([ CustomerReviewWorkspace::DETAIL_CONTEXT_QUERY_KEY => 1, 'source_surface' => CustomerReviewWorkspace::SOURCE_SURFACE, 'tenant_filter_id' => (string) $tenant->getKey(), 'interpretation_version' => $review->controlInterpretationVersion(), ])) ->assertOk(); $audit = AuditLog::query() ->where('action', AuditActionId::EnvironmentReviewOpened->value) ->latest('id') ->first(); expect($audit)->not->toBeNull() ->and($audit?->resource_type)->toBe('environment_review') ->and(data_get($audit?->metadata, 'review_id'))->toBe((int) $review->getKey()) ->and(data_get($audit?->metadata, 'source_surface'))->toBe(CustomerReviewWorkspace::SOURCE_SURFACE) ->and(data_get($audit?->metadata, 'tenant_filter_id'))->toBe((string) $tenant->getKey()) ->and(data_get($audit?->metadata, 'interpretation_version'))->toBe($review->controlInterpretationVersion()); });