TenantAtlas/apps/platform/app/Support/Baselines/BaselineSubjectKey.php
Ahmed Darrazi fb2642e941
Some checks failed
PR Fast Feedback / fast-feedback (pull_request) Failing after 1m9s
feat(resources): implement provider resource identity binding
Added ProviderResourceBinding model, migrations, policies, and supporting framework for canonical resource identity mapping as defined in Spec 381.
2026-06-15 17:37:06 +02:00

141 lines
4.7 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Support\Baselines;
use App\Support\Inventory\InventoryPolicyTypeMeta;
use App\Support\Resources\ResourceIdentity;
final class BaselineSubjectKey
{
public static function forPolicy(string $policyType, ?string $displayName = null, ?string $subjectExternalId = null): ?string
{
return match (InventoryPolicyTypeMeta::baselineCompareIdentityStrategy($policyType)) {
'external_id' => 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;
}
}