TenantAtlas/apps/platform/app/Services/TenantConfiguration/CoverageResourceUpserter.php
Ahmed Darrazi 736e61c73e
Some checks failed
PR Fast Feedback / fast-feedback (pull_request) Failing after 1m37s
feat: add generic content-backed coverage capture
2026-06-25 21:55:27 +02:00

115 lines
3.9 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Services\TenantConfiguration;
use App\Models\ManagedEnvironment;
use App\Models\ProviderConnection;
use App\Models\TenantConfigurationResource;
use App\Models\TenantConfigurationResourceType;
use App\Support\TenantConfiguration\ClaimState;
use App\Support\TenantConfiguration\EvidenceState;
use App\Support\TenantConfiguration\IdentityState;
use App\Support\TenantConfiguration\SourceClass;
use InvalidArgumentException;
final class CoverageResourceUpserter
{
/**
* @param array<string, mixed> $payload
* @param array<string, mixed> $sourceMetadata
*/
public function upsert(
ManagedEnvironment $tenant,
ProviderConnection $providerConnection,
TenantConfigurationResourceType $resourceType,
array $payload,
array $sourceMetadata = [],
): TenantConfigurationResource {
$this->assertScoped($tenant, $providerConnection);
$sourceResourceId = $this->extractSourceResourceId($payload);
$canonicalType = (string) $resourceType->canonical_type;
$canonicalResourceKey = sprintf('%s:%s', $canonicalType, $sourceResourceId);
$sourceClass = $resourceType->source_class instanceof SourceClass
? $resourceType->source_class->value
: (string) $resourceType->source_class;
$resource = TenantConfigurationResource::query()->firstOrNew([
'workspace_id' => (int) $tenant->workspace_id,
'managed_environment_id' => (int) $tenant->getKey(),
'provider_connection_id' => (int) $providerConnection->getKey(),
'resource_type_id' => (int) $resourceType->getKey(),
'canonical_resource_key' => $canonicalResourceKey,
]);
$resource->fill([
'source_class' => $sourceClass,
'canonical_type' => $canonicalType,
'source_resource_id' => $sourceResourceId,
'source_display_name' => $this->extractDisplayName($payload),
'source_metadata' => $sourceMetadata,
]);
if (! $resource->exists) {
$resource->forceFill([
'latest_evidence_state' => EvidenceState::NotCaptured->value,
'latest_identity_state' => IdentityState::Stable->value,
'latest_claim_state' => ClaimState::InternalOnly->value,
]);
}
$resource->save();
return $resource;
}
private function assertScoped(ManagedEnvironment $tenant, ProviderConnection $providerConnection): void
{
if ((int) $providerConnection->managed_environment_id !== (int) $tenant->getKey()) {
throw new InvalidArgumentException('Provider connection does not belong to the managed environment.');
}
if ((int) $providerConnection->workspace_id !== (int) $tenant->workspace_id) {
throw new InvalidArgumentException('Provider connection does not belong to the managed environment workspace.');
}
}
/**
* @param array<string, mixed> $payload
*/
private function extractSourceResourceId(array $payload): string
{
$id = $payload['id'] ?? $payload['sourceId'] ?? null;
if (! is_scalar($id)) {
throw new InvalidArgumentException('Captured resource payload must include a stable source id.');
}
$id = trim((string) $id);
if ($id === '') {
throw new InvalidArgumentException('Captured resource payload must include a non-empty source id.');
}
return $id;
}
/**
* @param array<string, mixed> $payload
*/
private function extractDisplayName(array $payload): ?string
{
$displayName = $payload['displayName'] ?? $payload['name'] ?? null;
if (! is_scalar($displayName)) {
return null;
}
$displayName = trim((string) $displayName);
return $displayName !== '' ? $displayName : null;
}
}