strategyFor(spec420IdentityResourceType()); expect($strategy['strategy_identifier'])->toBe('graph.conditional_access_policy.v1') ->and($strategy['preferred_identity_fields'])->toContain('id') ->and($strategy['stable_key_kind'])->toBe(CanonicalKeyKind::GraphObjectId->value) ->and($strategy['requires_provider_connection_scope'])->toBeTrue() ->and($strategy['derived_claims_allowed'])->toBeFalse(); }); it('Spec420 never treats Conditional Access display names as stable identity', function (): void { $resolver = app(CanonicalIdentityResolver::class); $resourceType = spec420IdentityResourceType(); $stable = $resolver->resolve($resourceType, [ 'id' => 'cap-1', 'displayName' => 'Require MFA', ]); $missing = $resolver->resolve($resourceType, [ 'displayName' => 'Require MFA', ]); expect($stable->identityState)->toBe(IdentityState::Stable) ->and($stable->keyKind)->toBe(CanonicalKeyKind::GraphObjectId) ->and($missing->identityState)->toBe(IdentityState::MissingExternalId) ->and($missing->canonicalResourceKey)->not->toContain('Require MFA'); }); function spec420IdentityResourceType(): TenantConfigurationResourceType { $definition = collect(ResourceTypeRegistry::defaultDefinitions()) ->firstWhere('canonical_type', 'conditionalAccessPolicy'); expect($definition)->not->toBeNull('Missing default resource type definition for conditionalAccessPolicy.'); return new TenantConfigurationResourceType($definition); }