create([ 'name' => 'Spec 281 Environment', 'managed_environment_id' => '44444444-4444-4444-4444-444444444444', ]); $connection = ProviderConnection::factory()->dedicated()->consentGranted()->create([ 'workspace_id' => (int) $tenant->workspace_id, 'managed_environment_id' => (int) $tenant->getKey(), 'provider' => 'microsoft', 'entra_tenant_id' => '44444444-4444-4444-4444-444444444444', 'consent_status' => 'granted', ]); ProviderCredential::factory()->create([ 'provider_connection_id' => (int) $connection->getKey(), ]); $result = app(ProviderOperationStartGate::class)->start( tenant: $tenant, connection: $connection, operationType: 'provider.connection.check', dispatcher: fn (OperationRun $run): null => null, ); $context = $result->run->fresh()->context; expect($result->status)->toBe('started') ->and($context['target_scope'] ?? [])->toMatchArray([ 'provider' => 'microsoft', 'scope_kind' => 'tenant', 'scope_identifier' => '44444444-4444-4444-4444-444444444444', 'scope_display_name' => 'Spec 281 Environment', ]) ->and($context['target_scope'] ?? [])->not->toHaveKey('entra_tenant_id') ->and($context['provider_context']['details'][0] ?? [])->toMatchArray([ 'detail_key' => 'microsoft_tenant_id', 'detail_value' => '44444444-4444-4444-4444-444444444444', ]); }); it('stores neutral target-scope context when provider starts are blocked before a connection is resolved', function (): void { $tenant = ManagedEnvironment::factory()->create([ 'name' => 'Blocked Spec 281 Environment', 'managed_environment_id' => '55555555-5555-5555-5555-555555555555', ]); $result = app(ProviderOperationStartGate::class)->start( tenant: $tenant, connection: null, operationType: 'provider.connection.check', dispatcher: fn (): null => null, ); $context = $result->run->fresh()->context; $report = $context['verification_report'] ?? []; $report = is_array($report) ? $report : []; $identity = $report['identity'] ?? []; $identity = is_array($identity) ? $identity : []; $evidence = $report['checks'][0]['evidence'] ?? []; $evidence = is_array($evidence) ? $evidence : []; expect($result->status)->toBe('blocked') ->and($result->run->outcome)->toBe(OperationRunOutcome::Blocked->value) ->and($context['reason_code'] ?? null)->toBe(ProviderReasonCodes::ProviderConnectionMissing) ->and($context['target_scope'] ?? [])->toMatchArray([ 'provider' => 'microsoft', 'scope_kind' => 'tenant', 'scope_identifier' => '55555555-5555-5555-5555-555555555555', ]) ->and($context['target_scope'] ?? [])->not->toHaveKey('entra_tenant_id') ->and($identity['target_scope'] ?? [])->toMatchArray([ 'scope_identifier' => '55555555-5555-5555-5555-555555555555', ]) ->and($identity)->not->toHaveKey('entra_tenant_id') ->and(collect($evidence)->contains( fn (array $pointer): bool => ($pointer['kind'] ?? null) === 'target_scope_identifier' && ($pointer['value'] ?? null) === '55555555-5555-5555-5555-555555555555', ))->toBeTrue(); });