self::fromExternalId($policyType, $subjectExternalId), default => self::fromDisplayName($displayName), }; } public static function fromDisplayName(?string $displayName): ?string { if (! is_string($displayName)) { return null; } $trimmed = trim($displayName); if ($trimmed === '') { return null; } $collapsed = preg_replace('/\\s+/u', ' ', $trimmed); $collapsed = is_string($collapsed) ? $collapsed : $trimmed; $normalized = mb_strtolower($collapsed); $normalized = trim($normalized); return $normalized !== '' ? $normalized : null; } public static function fromExternalId(string $policyType, ?string $subjectExternalId): ?string { if (! is_string($subjectExternalId)) { return null; } $normalizedId = trim(mb_strtolower($subjectExternalId)); if ($normalizedId === '') { return null; } return hash('sha256', trim(mb_strtolower($policyType)).'|'.$normalizedId); } public static function workspaceSafeSubjectExternalId(string $policyType, string $subjectKey): string { return hash('sha256', $policyType.'|'.$subjectKey); } public static function workspaceSafeSubjectExternalIdForPolicy(string $policyType, ?string $displayName = null, ?string $subjectExternalId = null): ?string { $identityInput = match (InventoryPolicyTypeMeta::baselineCompareIdentityStrategy($policyType)) { 'external_id' => is_string($subjectExternalId) ? trim(mb_strtolower($subjectExternalId)) : null, default => self::fromDisplayName($displayName), }; if (! is_string($identityInput) || $identityInput === '') { return null; } return self::workspaceSafeSubjectExternalId($policyType, $identityInput); } public static function forProviderResourceIdentity( string $subjectDomain, SubjectClass|string $subjectClass, string $subjectTypeKey, ResourceIdentity $identity, ): ?string { $domain = self::canonicalSegment($subjectDomain); $class = self::canonicalSegment($subjectClass instanceof SubjectClass ? $subjectClass->value : $subjectClass); $type = self::canonicalSegment($subjectTypeKey); $provider = self::canonicalSegment($identity->providerKey); $resourceType = self::canonicalSegment($identity->providerResourceType ?? 'none'); $stableIdentity = $identity->stableIdentityValue(); if ($domain === null || $class === null || $type === null || $provider === null || $resourceType === null || $stableIdentity === null) { return null; } return implode(':', [ 'provider-resource', 'v1', $domain, $class, $type, $provider, $resourceType, $identity->identityKind, hash('sha256', $stableIdentity), ]); } public static function fromProviderResourceIdentity( string $subjectDomain, SubjectClass|string $subjectClass, string $subjectTypeKey, string $providerKey, ?string $providerResourceType, string $stableIdentity, string $identityKind = 'provider_resource', ): ?string { return self::forProviderResourceIdentity( $subjectDomain, $subjectClass, $subjectTypeKey, new ResourceIdentity( providerKey: $providerKey, identityKind: $identityKind, providerResourceType: $providerResourceType, providerResourceId: $identityKind === 'provider_resource' ? $stableIdentity : null, canonicalDiscriminator: $identityKind === 'provider_resource' ? null : $stableIdentity, ), ); } private static function canonicalSegment(?string $value): ?string { if (! is_string($value)) { return null; } $normalized = trim(mb_strtolower($value)); $normalized = preg_replace('/[^a-z0-9._-]+/', '-', $normalized); $normalized = is_string($normalized) ? trim($normalized, '-') : null; return $normalized !== null && $normalized !== '' ? $normalized : null; } }