resolver = new BaselinePolicyVersionResolver; }); test('resolves baseline policy version id within observed second', function () { $tenant = Tenant::factory()->create(); $displayName = 'Policy Alpha'; $subjectKey = BaselineSubjectKey::fromDisplayName($displayName); expect($subjectKey)->not->toBeNull(); $policy = Policy::factory()->create([ 'tenant_id' => (int) $tenant->getKey(), 'policy_type' => 'settingsCatalogPolicy', 'display_name' => $displayName, ]); $capturedAt = CarbonImmutable::parse('2026-03-05 12:00:00.123456'); $version = PolicyVersion::factory()->create([ 'tenant_id' => (int) $tenant->getKey(), 'policy_id' => (int) $policy->getKey(), 'policy_type' => (string) $policy->policy_type, 'version_number' => 1, 'captured_at' => $capturedAt, ]); $resolved = $this->resolver->resolve( tenant: $tenant, policyType: (string) $policy->policy_type, subjectKey: (string) $subjectKey, observedAt: $capturedAt->toIso8601String(), ); expect($resolved)->toBe((int) $version->getKey()); }); test('returns null when no policy matches subject key', function () { $tenant = Tenant::factory()->create(); Policy::factory()->create([ 'tenant_id' => (int) $tenant->getKey(), 'policy_type' => 'settingsCatalogPolicy', 'display_name' => 'Some Other Policy', ]); $resolved = $this->resolver->resolve( tenant: $tenant, policyType: 'settingsCatalogPolicy', subjectKey: 'missing-subject-key', observedAt: CarbonImmutable::parse('2026-03-05 12:00:00')->toIso8601String(), ); expect($resolved)->toBeNull(); }); test('returns null when observed_at is invalid', function () { $tenant = Tenant::factory()->create(); $policy = Policy::factory()->create([ 'tenant_id' => (int) $tenant->getKey(), 'policy_type' => 'settingsCatalogPolicy', 'display_name' => 'Policy Alpha', ]); $subjectKey = BaselineSubjectKey::fromDisplayName((string) $policy->display_name); expect($subjectKey)->not->toBeNull(); $resolved = $this->resolver->resolve( tenant: $tenant, policyType: (string) $policy->policy_type, subjectKey: (string) $subjectKey, observedAt: 'not-a-date', ); expect($resolved)->toBeNull(); }); test('uses a deterministic tie-breaker when multiple candidates exist', function () { $tenant = Tenant::factory()->create(); $displayName = 'Policy Alpha'; $subjectKey = BaselineSubjectKey::fromDisplayName($displayName); expect($subjectKey)->not->toBeNull(); $policy = Policy::factory()->create([ 'tenant_id' => (int) $tenant->getKey(), 'policy_type' => 'settingsCatalogPolicy', 'display_name' => $displayName, ]); $versionEarly = PolicyVersion::factory()->create([ 'tenant_id' => (int) $tenant->getKey(), 'policy_id' => (int) $policy->getKey(), 'policy_type' => (string) $policy->policy_type, 'version_number' => 1, 'captured_at' => CarbonImmutable::parse('2026-03-05 12:00:00.100000'), ]); $versionLate = PolicyVersion::factory()->create([ 'tenant_id' => (int) $tenant->getKey(), 'policy_id' => (int) $policy->getKey(), 'policy_type' => (string) $policy->policy_type, 'version_number' => 2, 'captured_at' => CarbonImmutable::parse('2026-03-05 12:00:00.900000'), ]); $resolved = $this->resolver->resolve( tenant: $tenant, policyType: (string) $policy->policy_type, subjectKey: (string) $subjectKey, observedAt: CarbonImmutable::parse('2026-03-05 12:00:00')->toIso8601String(), ); expect($resolved) ->toBe((int) $versionLate->getKey()) ->and($resolved)->not->toBe((int) $versionEarly->getKey()); }); test('resolves intune role definition versions by external-id identity', function () { $tenant = Tenant::factory()->create(); $policy = Policy::factory()->create([ 'tenant_id' => (int) $tenant->getKey(), 'policy_type' => 'intuneRoleDefinition', 'external_id' => 'role-def-42', 'display_name' => 'Security Reader', ]); $capturedAt = CarbonImmutable::parse('2026-03-08 12:00:00.123456'); $version = PolicyVersion::factory()->create([ 'tenant_id' => (int) $tenant->getKey(), 'policy_id' => (int) $policy->getKey(), 'policy_type' => (string) $policy->policy_type, 'version_number' => 1, 'captured_at' => $capturedAt, ]); $subjectKey = BaselineSubjectKey::forPolicy('intuneRoleDefinition', 'Security Reader', 'role-def-42'); expect($subjectKey)->not->toBeNull(); $resolved = $this->resolver->resolve( tenant: $tenant, policyType: 'intuneRoleDefinition', subjectKey: (string) $subjectKey, observedAt: $capturedAt->toIso8601String(), ); expect($resolved)->toBe((int) $version->getKey()); });