Added `ProviderResourceBinding` model, migrations, policies, and supporting framework for canonical resource identity mapping as defined in Spec 381. This provides the structural capability to resolve baseline and posture discrepancies by binding logical entities across source providers to canonical identities. Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #452
142 lines
5.3 KiB
PHP
142 lines
5.3 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Database\Factories;
|
|
|
|
use App\Models\ManagedEnvironment;
|
|
use App\Models\ProviderResourceBinding;
|
|
use App\Models\User;
|
|
use App\Support\Baselines\BaselineSubjectKey;
|
|
use App\Support\Baselines\SubjectClass;
|
|
use App\Support\Resources\ProviderResourceBindingStatus;
|
|
use App\Support\Resources\ProviderResourceResolutionMode;
|
|
use App\Support\Resources\ResourceIdentity;
|
|
use Illuminate\Database\Eloquent\Factories\Factory;
|
|
|
|
/**
|
|
* @extends Factory<ProviderResourceBinding>
|
|
*/
|
|
class ProviderResourceBindingFactory extends Factory
|
|
{
|
|
protected $model = ProviderResourceBinding::class;
|
|
|
|
/**
|
|
* @return array<string, mixed>
|
|
*/
|
|
public function definition(): array
|
|
{
|
|
$identity = ResourceIdentity::providerResource('fake-provider', 'policy', fake()->uuid());
|
|
$subjectDomain = 'baseline';
|
|
$subjectClass = SubjectClass::PolicyBacked;
|
|
$subjectTypeKey = 'deviceConfiguration';
|
|
|
|
return [
|
|
'managed_environment_id' => ManagedEnvironment::factory(),
|
|
'workspace_id' => function (array $attributes): int {
|
|
$tenantId = $attributes['managed_environment_id'] ?? null;
|
|
|
|
if (! is_numeric($tenantId)) {
|
|
return (int) ManagedEnvironment::factory()->create()->workspace_id;
|
|
}
|
|
|
|
$tenant = ManagedEnvironment::query()->whereKey((int) $tenantId)->firstOrFail();
|
|
|
|
return (int) $tenant->workspace_id;
|
|
},
|
|
'provider_key' => $identity->providerKey,
|
|
'provider_connection_id' => null,
|
|
'subject_domain' => $subjectDomain,
|
|
'subject_class' => $subjectClass->value,
|
|
'subject_type_key' => $subjectTypeKey,
|
|
'legacy_subject_key' => null,
|
|
'canonical_subject_key' => BaselineSubjectKey::forProviderResourceIdentity(
|
|
$subjectDomain,
|
|
$subjectClass,
|
|
$subjectTypeKey,
|
|
$identity,
|
|
),
|
|
'provider_resource_type' => $identity->providerResourceType,
|
|
'provider_resource_id' => $identity->providerResourceId,
|
|
'provider_resource_discriminator' => $identity->canonicalDiscriminator,
|
|
'provider_resource_identity_kind' => $identity->identityKind,
|
|
'provider_resource_fingerprint' => $identity->fingerprint(),
|
|
'display_label' => fake()->words(3, true),
|
|
'binding_status' => ProviderResourceBindingStatus::Active->value,
|
|
'resolution_mode' => ProviderResourceResolutionMode::ExactProviderIdentity->value,
|
|
'resolution_reason' => null,
|
|
'operator_note' => 'Binding decision recorded for test coverage.',
|
|
'source_operation_run_id' => null,
|
|
'source_baseline_snapshot_id' => null,
|
|
'source_inventory_item_id' => null,
|
|
'source_policy_version_id' => null,
|
|
'decided_by_user_id' => User::factory(),
|
|
'decided_at' => now(),
|
|
'ended_at' => null,
|
|
];
|
|
}
|
|
|
|
public function fakeProvider(): static
|
|
{
|
|
return $this->state(fn (): array => [
|
|
'provider_key' => 'fake-provider',
|
|
]);
|
|
}
|
|
|
|
public function providerResource(?ResourceIdentity $identity = null): static
|
|
{
|
|
$identity ??= ResourceIdentity::providerResource('fake-provider', 'policy', fake()->uuid());
|
|
|
|
return $this->withIdentity($identity, ProviderResourceResolutionMode::ExactProviderIdentity);
|
|
}
|
|
|
|
public function canonicalBuiltin(?ResourceIdentity $identity = null): static
|
|
{
|
|
$identity ??= ResourceIdentity::canonicalBuiltin('fake-provider', 'target', 'all-principals');
|
|
|
|
return $this->withIdentity($identity, ProviderResourceResolutionMode::CanonicalBuiltin);
|
|
}
|
|
|
|
public function revoked(): static
|
|
{
|
|
return $this->state(fn (): array => [
|
|
'binding_status' => ProviderResourceBindingStatus::Revoked->value,
|
|
'ended_at' => now(),
|
|
]);
|
|
}
|
|
|
|
public function superseded(): static
|
|
{
|
|
return $this->state(fn (): array => [
|
|
'binding_status' => ProviderResourceBindingStatus::Superseded->value,
|
|
'ended_at' => now(),
|
|
]);
|
|
}
|
|
|
|
private function withIdentity(ResourceIdentity $identity, ProviderResourceResolutionMode $resolutionMode): static
|
|
{
|
|
$subjectDomain = 'baseline';
|
|
$subjectClass = SubjectClass::PolicyBacked;
|
|
$subjectTypeKey = 'deviceConfiguration';
|
|
|
|
return $this->state(fn (): array => [
|
|
'provider_key' => $identity->providerKey,
|
|
'subject_domain' => $subjectDomain,
|
|
'subject_class' => $subjectClass->value,
|
|
'subject_type_key' => $subjectTypeKey,
|
|
'canonical_subject_key' => BaselineSubjectKey::forProviderResourceIdentity(
|
|
$subjectDomain,
|
|
$subjectClass,
|
|
$subjectTypeKey,
|
|
$identity,
|
|
),
|
|
'provider_resource_type' => $identity->providerResourceType,
|
|
'provider_resource_id' => $identity->providerResourceId,
|
|
'provider_resource_discriminator' => $identity->canonicalDiscriminator,
|
|
'provider_resource_identity_kind' => $identity->identityKind,
|
|
'provider_resource_fingerprint' => $identity->fingerprint(),
|
|
'resolution_mode' => $resolutionMode->value,
|
|
]);
|
|
}
|
|
}
|