create(); $user = User::factory()->create(); WorkspaceMembership::factory()->create([ 'workspace_id' => $workspace->getKey(), 'user_id' => $user->getKey(), 'role' => 'owner', ]); session()->put(WorkspaceContext::SESSION_KEY, (int) $workspace->getKey()); $this->actingAs($user); $tenantGuid = '10101010-1010-1010-1010-101010101010'; $component = Livewire::actingAs($user)->test(ManagedEnvironmentOnboardingWizard::class); $component->call('identifyManagedEnvironment', [ 'entra_tenant_id' => $tenantGuid, 'environment' => 'prod', 'name' => 'Acme', 'primary_domain' => 'acme.example', 'notes' => 'Provider start test', ]); $tenant = ManagedEnvironment::query()->forTenant($tenantGuid)->firstOrFail(); $connection = ProviderConnection::factory()->platform()->consentGranted()->create([ 'managed_environment_id' => (int) $tenant->getKey(), 'provider' => 'microsoft', 'entra_tenant_id' => $tenantGuid, 'is_default' => true, ]); OperationRun::query()->create([ 'managed_environment_id' => (int) $tenant->getKey(), 'user_id' => (int) $user->getKey(), 'initiator_name' => $user->name, 'type' => 'inventory.sync', 'status' => 'queued', 'outcome' => 'pending', 'run_identity_hash' => sha1('busy-onboarding-'.(string) $connection->getKey()), 'context' => [ 'provider_connection_id' => (int) $connection->getKey(), ], ]); $component->set('selectedProviderConnectionId', (int) $connection->getKey()); $component->call('startVerification'); expect(OperationRun::query() ->where('managed_environment_id', (int) $tenant->getKey()) ->where('type', 'provider.connection.check') ->count())->toBe(0); Bus::assertNotDispatched(ProviderConnectionHealthCheckJob::class); }); it('does not disclose a resolution-scoped busy verification run in onboarding state audit or notifications', function (): void { Bus::fake(); $workspace = Workspace::factory()->create(); $user = User::factory()->create(); WorkspaceMembership::factory()->create([ 'workspace_id' => $workspace->getKey(), 'user_id' => $user->getKey(), 'role' => 'owner', ]); session()->put(WorkspaceContext::SESSION_KEY, (int) $workspace->getKey()); $this->actingAs($user); $tenantGuid = '30303030-3030-3030-3030-303030303030'; $component = Livewire::actingAs($user)->test(ManagedEnvironmentOnboardingWizard::class); $component->call('identifyManagedEnvironment', [ 'entra_tenant_id' => $tenantGuid, 'environment' => 'prod', 'name' => 'Acme', 'primary_domain' => 'acme.example', 'notes' => 'Provider start disclosure test', ]); $tenant = ManagedEnvironment::query()->forTenant($tenantGuid)->firstOrFail(); $connection = ProviderConnection::factory()->platform()->consentGranted()->create([ 'workspace_id' => (int) $workspace->getKey(), 'managed_environment_id' => (int) $tenant->getKey(), 'provider' => 'microsoft', 'entra_tenant_id' => $tenantGuid, 'is_default' => true, ]); $resolutionRun = OperationRun::query()->create([ 'workspace_id' => (int) $workspace->getKey(), 'managed_environment_id' => (int) $tenant->getKey(), 'user_id' => (int) $user->getKey(), 'initiator_name' => $user->name, 'type' => 'provider.connection.check', 'status' => 'running', 'outcome' => 'pending', 'run_identity_hash' => sha1('resolution-verification-busy-'.(string) $connection->getKey()), 'context' => [ 'provider_connection_id' => (int) $connection->getKey(), 'trigger' => 'review_publication_resolution', 'review_publication_resolution_case_id' => 388101, 'environment_review_id' => 388102, ], ]); $component->set('selectedProviderConnectionId', (int) $connection->getKey()); $component->call('startVerification'); $session = ManagedEnvironmentOnboardingSession::query() ->where('workspace_id', (int) $workspace->getKey()) ->where('managed_environment_id', (int) $tenant->getKey()) ->firstOrFail(); expect(OperationRun::query() ->where('managed_environment_id', (int) $tenant->getKey()) ->where('type', 'provider.connection.check') ->count())->toBe(1) ->and($session->state['verification_operation_run_id'] ?? null)->toBeNull(); $notificationActions = collect(session('filament.notifications', [])) ->flatMap(static fn (array $notification): array => is_array($notification['actions'] ?? null) ? $notification['actions'] : []); $encodedActions = json_encode($notificationActions->all(), JSON_THROW_ON_ERROR); expect($notificationActions->pluck('name')->all())->not->toContain('view_run') ->and($encodedActions)->not->toContain(OperationRunLinks::tenantlessView((int) $resolutionRun->getKey())); $auditLogs = AuditLog::query() ->where('workspace_id', (int) $workspace->getKey()) ->whereIn('action', [ AuditActionId::ManagedEnvironmentOnboardingVerificationStart->value, AuditActionId::ManagedEnvironmentOnboardingVerificationPersisted->value, ]) ->get(); expect($auditLogs)->not->toBeEmpty(); $auditLogs->each(function (AuditLog $auditLog): void { expect($auditLog->operation_run_id)->toBeNull() ->and($auditLog->resource_type)->not->toBe('operation_run') ->and($auditLog->metadata['operation_run_id'] ?? null)->toBeNull(); }); Bus::assertNotDispatched(ProviderConnectionHealthCheckJob::class); }); it('serializes onboarding bootstrap so only one selected provider-backed action starts at a time', function (): void { Bus::fake(); $workspace = Workspace::factory()->create(); $user = User::factory()->create(); WorkspaceMembership::factory()->create([ 'workspace_id' => $workspace->getKey(), 'user_id' => $user->getKey(), 'role' => 'owner', ]); session()->put(WorkspaceContext::SESSION_KEY, (int) $workspace->getKey()); $this->actingAs($user); $tenantGuid = '20202020-2020-2020-2020-202020202020'; $component = Livewire::actingAs($user)->test(ManagedEnvironmentOnboardingWizard::class); $component->call('identifyManagedEnvironment', [ 'entra_tenant_id' => $tenantGuid, 'environment' => 'prod', 'name' => 'Acme', 'primary_domain' => 'acme.example', 'notes' => 'Provider start test', ]); $tenant = ManagedEnvironment::query()->forTenant($tenantGuid)->firstOrFail(); $connection = ProviderConnection::factory()->platform()->consentGranted()->create([ 'managed_environment_id' => (int) $tenant->getKey(), 'provider' => 'microsoft', 'entra_tenant_id' => $tenantGuid, 'is_default' => true, ]); spec283SeedRequirementRows($tenant, ['permissions.intune_configuration', 'permissions.intune_apps']); $verificationRun = OperationRun::query()->create([ 'managed_environment_id' => (int) $tenant->getKey(), 'user_id' => (int) $user->getKey(), 'initiator_name' => $user->name, 'type' => 'provider.connection.check', 'status' => 'completed', 'outcome' => 'succeeded', 'run_identity_hash' => sha1('verify-ok-bootstrap-provider-start-'.(string) $connection->getKey()), 'context' => [ 'provider_connection_id' => (int) $connection->getKey(), ], ]); $session = ManagedEnvironmentOnboardingSession::query() ->where('workspace_id', (int) $workspace->getKey()) ->where('managed_environment_id', (int) $tenant->getKey()) ->firstOrFail(); $session->update([ 'state' => array_merge($session->state ?? [], [ 'provider_connection_id' => (int) $connection->getKey(), 'verification_operation_run_id' => (int) $verificationRun->getKey(), ]), ]); $component->call('startBootstrap', ['inventory_sync', 'compliance.snapshot']); $inventoryRun = OperationRun::query() ->where('managed_environment_id', (int) $tenant->getKey()) ->where('type', 'inventory.sync') ->latest('id') ->firstOrFail(); expect(OperationRun::query() ->where('managed_environment_id', (int) $tenant->getKey()) ->where('type', 'compliance.snapshot') ->count())->toBe(0); $inventoryRun->forceFill([ 'status' => 'completed', 'outcome' => 'succeeded', ])->save(); $component->call('startBootstrap', ['inventory.sync', 'compliance.snapshot']); expect(OperationRun::query() ->where('managed_environment_id', (int) $tenant->getKey()) ->where('type', 'compliance.snapshot') ->count())->toBe(1); Bus::assertDispatchedTimes(ProviderInventorySyncJob::class, 1); Bus::assertDispatchedTimes(ProviderComplianceSnapshotJob::class, 1); }); it('does not disclose a resolution-scoped busy bootstrap run in onboarding state audit or notifications', function (): void { Bus::fake(); $workspace = Workspace::factory()->create(); $user = User::factory()->create(); WorkspaceMembership::factory()->create([ 'workspace_id' => $workspace->getKey(), 'user_id' => $user->getKey(), 'role' => 'owner', ]); session()->put(WorkspaceContext::SESSION_KEY, (int) $workspace->getKey()); $this->actingAs($user); $tenantGuid = '40404040-4040-4040-4040-404040404040'; $component = Livewire::actingAs($user)->test(ManagedEnvironmentOnboardingWizard::class); $component->call('identifyManagedEnvironment', [ 'entra_tenant_id' => $tenantGuid, 'environment' => 'prod', 'name' => 'Acme', 'primary_domain' => 'acme.example', 'notes' => 'Bootstrap disclosure test', ]); $tenant = ManagedEnvironment::query()->forTenant($tenantGuid)->firstOrFail(); $connection = ProviderConnection::factory()->platform()->consentGranted()->create([ 'workspace_id' => (int) $workspace->getKey(), 'managed_environment_id' => (int) $tenant->getKey(), 'provider' => 'microsoft', 'entra_tenant_id' => $tenantGuid, 'is_default' => true, ]); spec283SeedRequirementRows($tenant, ['permissions.intune_configuration', 'permissions.intune_apps']); $verificationRun = OperationRun::query()->create([ 'workspace_id' => (int) $workspace->getKey(), 'managed_environment_id' => (int) $tenant->getKey(), 'user_id' => (int) $user->getKey(), 'initiator_name' => $user->name, 'type' => 'provider.connection.check', 'status' => 'completed', 'outcome' => 'succeeded', 'run_identity_hash' => sha1('bootstrap-disclosure-verification-'.(string) $connection->getKey()), 'context' => [ 'provider_connection_id' => (int) $connection->getKey(), ], ]); $session = ManagedEnvironmentOnboardingSession::query() ->where('workspace_id', (int) $workspace->getKey()) ->where('managed_environment_id', (int) $tenant->getKey()) ->firstOrFail(); $session->update([ 'state' => array_merge($session->state ?? [], [ 'provider_connection_id' => (int) $connection->getKey(), 'verification_operation_run_id' => (int) $verificationRun->getKey(), ]), ]); $resolutionRun = OperationRun::query()->create([ 'workspace_id' => (int) $workspace->getKey(), 'managed_environment_id' => (int) $tenant->getKey(), 'user_id' => (int) $user->getKey(), 'initiator_name' => $user->name, 'type' => 'inventory.sync', 'status' => 'running', 'outcome' => 'pending', 'run_identity_hash' => sha1('resolution-bootstrap-busy-'.(string) $connection->getKey()), 'context' => [ 'provider_connection_id' => (int) $connection->getKey(), 'trigger' => 'review_publication_resolution', 'review_publication_resolution_case_id' => 388201, 'environment_review_id' => 388202, ], ]); $component->set('selectedProviderConnectionId', (int) $connection->getKey()); $component->call('startBootstrap', ['inventory.sync']); $session->refresh(); expect(OperationRun::query() ->where('managed_environment_id', (int) $tenant->getKey()) ->where('type', 'inventory.sync') ->count())->toBe(1) ->and($session->state['bootstrap_operation_runs'] ?? [])->toBe([]); $notificationActions = collect(session('filament.notifications', [])) ->flatMap(static fn (array $notification): array => is_array($notification['actions'] ?? null) ? $notification['actions'] : []); $encodedActions = json_encode($notificationActions->all(), JSON_THROW_ON_ERROR); expect($notificationActions->pluck('name')->all())->not->toContain('view_run') ->and($encodedActions)->not->toContain(OperationRunLinks::tenantlessView((int) $resolutionRun->getKey())); $auditLog = AuditLog::query() ->where('workspace_id', (int) $workspace->getKey()) ->where('action', AuditActionId::ManagedEnvironmentOnboardingBootstrapStarted->value) ->latest('id') ->firstOrFail(); expect($auditLog->operation_run_id)->toBeNull() ->and($auditLog->metadata['operation_run_id'] ?? null)->toBeNull(); Bus::assertNotDispatched(ProviderInventorySyncJob::class); });