TenantAtlas/apps/platform/tests/Feature/TenantConfiguration/Spec415ProviderConnectionScopeTest.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

292 lines
12 KiB
PHP

<?php
declare(strict_types=1);
use App\Jobs\TenantConfiguration\CaptureTenantConfigurationEvidenceJob;
use App\Models\ManagedEnvironment;
use App\Models\OperationRun;
use App\Models\ProviderConnection;
use App\Models\TenantConfigurationResource;
use App\Models\TenantConfigurationResourceEvidence;
use App\Models\TenantConfigurationResourceType;
use App\Models\User;
use App\Models\Workspace;
use App\Services\TenantConfiguration\ResourceTypeRegistry;
use App\Services\TenantConfiguration\StartTenantConfigurationCapture;
use App\Support\OperationRunOutcome;
use App\Support\OperationRunStatus;
use App\Support\OperationRunType;
use App\Support\TenantConfiguration\ClaimState;
use App\Support\TenantConfiguration\EvidenceState;
use App\Support\TenantConfiguration\IdentityState;
use App\Support\TenantConfiguration\SourceClass;
use Illuminate\Database\QueryException;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Queue;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
it('allows provider connections in the same managed environment and workspace', function (): void {
Queue::fake();
[$user, $tenant] = createMinimalUserWithTenant(role: 'owner');
$connection = ProviderConnection::factory()->create([
'workspace_id' => (int) $tenant->workspace_id,
'managed_environment_id' => (int) $tenant->getKey(),
]);
$run = app(StartTenantConfigurationCapture::class)->start($tenant, $connection, $user, [
'deviceAndAppManagementAssignmentFilter',
]);
expect((int) data_get($run->context, 'target_scope.provider_connection_id'))->toBe((int) $connection->getKey());
Queue::assertPushed(CaptureTenantConfigurationEvidenceJob::class);
});
it('rejects provider connections from another managed environment or workspace', function (): void {
Queue::fake();
[$user, $tenant] = createMinimalUserWithTenant(role: 'owner');
[, $otherTenant] = createMinimalUserWithTenant(role: 'owner');
$otherConnection = ProviderConnection::factory()->create([
'workspace_id' => (int) $otherTenant->workspace_id,
'managed_environment_id' => (int) $otherTenant->getKey(),
]);
expect(fn () => app(StartTenantConfigurationCapture::class)->start($tenant, $otherConnection, $user))
->toThrow(NotFoundHttpException::class);
Queue::assertNothingPushed();
});
it('enforces provider connection scope at the PostgreSQL constraint layer', function (): void {
if (DB::getDriverName() !== 'pgsql') {
test()->markTestSkipped('PostgreSQL composite foreign key constraint coverage.');
}
[, $tenant] = createMinimalUserWithTenant(role: 'owner');
[, $otherTenant] = createMinimalUserWithTenant(role: 'owner');
$resourceType = spec415CaptureResourceType();
$foreignConnection = ProviderConnection::factory()->create([
'workspace_id' => (int) $otherTenant->workspace_id,
'managed_environment_id' => (int) $otherTenant->getKey(),
]);
expect(fn () => TenantConfigurationResource::query()->create([
'workspace_id' => (int) $tenant->workspace_id,
'managed_environment_id' => (int) $tenant->getKey(),
'provider_connection_id' => (int) $foreignConnection->getKey(),
'resource_type_id' => (int) $resourceType->getKey(),
'source_class' => SourceClass::Tcm->value,
'canonical_type' => (string) $resourceType->canonical_type,
'canonical_resource_key' => 'deviceAndAppManagementAssignmentFilter:foreign-provider',
'source_resource_id' => 'foreign-provider',
'source_metadata' => ['fixture' => 'provider-scope'],
'latest_evidence_state' => EvidenceState::NotCaptured->value,
'latest_identity_state' => IdentityState::Stable->value,
'latest_claim_state' => ClaimState::InternalOnly->value,
]))->toThrow(QueryException::class);
});
it('enforces provider connection workspace/environment binding at the PostgreSQL constraint layer', function (): void {
if (DB::getDriverName() !== 'pgsql') {
test()->markTestSkipped('PostgreSQL composite foreign key constraint coverage.');
}
[, $tenant] = createMinimalUserWithTenant(role: 'owner');
$foreignWorkspace = Workspace::factory()->create();
expect(fn () => ProviderConnection::factory()->create([
'workspace_id' => (int) $foreignWorkspace->getKey(),
'managed_environment_id' => (int) $tenant->getKey(),
]))->toThrow(QueryException::class);
});
it('enforces evidence resource/provider scope at the PostgreSQL constraint layer', function (): void {
if (DB::getDriverName() !== 'pgsql') {
test()->markTestSkipped('PostgreSQL composite foreign key constraint coverage.');
}
[$user, $tenant] = createMinimalUserWithTenant(role: 'owner');
$resourceType = spec415CaptureResourceType();
$connection = ProviderConnection::factory()->create([
'workspace_id' => (int) $tenant->workspace_id,
'managed_environment_id' => (int) $tenant->getKey(),
]);
$otherScopedConnection = ProviderConnection::factory()->create([
'workspace_id' => (int) $tenant->workspace_id,
'managed_environment_id' => (int) $tenant->getKey(),
]);
$resource = spec415CaptureResource($tenant, $connection, $resourceType, 'provider-mismatch');
$run = spec415CaptureRun($tenant, $user);
expect(fn () => DB::table('tenant_configuration_resource_evidence')->insert(
spec415EvidenceRow($tenant, $resource, $otherScopedConnection, $resourceType, $run),
))->toThrow(QueryException::class);
});
it('enforces latest evidence pointer scope at the PostgreSQL constraint layer', function (): void {
if (DB::getDriverName() !== 'pgsql') {
test()->markTestSkipped('PostgreSQL composite foreign key constraint coverage.');
}
[$user, $tenant] = createMinimalUserWithTenant(role: 'owner');
$resourceType = spec415CaptureResourceType();
$connection = ProviderConnection::factory()->create([
'workspace_id' => (int) $tenant->workspace_id,
'managed_environment_id' => (int) $tenant->getKey(),
]);
$sourceResource = spec415CaptureResource($tenant, $connection, $resourceType, 'latest-source');
$targetResource = spec415CaptureResource($tenant, $connection, $resourceType, 'latest-target');
$run = spec415CaptureRun($tenant, $user);
$sourceEvidence = TenantConfigurationResourceEvidence::factory()->create([
'resource_id' => (int) $sourceResource->getKey(),
'workspace_id' => (int) $tenant->workspace_id,
'managed_environment_id' => (int) $tenant->getKey(),
'provider_connection_id' => (int) $connection->getKey(),
'resource_type_id' => (int) $resourceType->getKey(),
'operation_run_id' => (int) $run->getKey(),
]);
expect(fn () => $targetResource->forceFill([
'latest_evidence_id' => (int) $sourceEvidence->getKey(),
])->save())->toThrow(QueryException::class);
});
it('allows resource deletion after latest evidence is linked at the PostgreSQL constraint layer', function (): void {
if (DB::getDriverName() !== 'pgsql') {
test()->markTestSkipped('PostgreSQL composite foreign key lifecycle coverage.');
}
[$user, $tenant] = createMinimalUserWithTenant(role: 'owner');
$resourceType = spec415CaptureResourceType();
$connection = ProviderConnection::factory()->create([
'workspace_id' => (int) $tenant->workspace_id,
'managed_environment_id' => (int) $tenant->getKey(),
]);
$resource = spec415CaptureResource($tenant, $connection, $resourceType, 'latest-delete');
$run = spec415CaptureRun($tenant, $user);
$evidence = TenantConfigurationResourceEvidence::factory()->create([
'resource_id' => (int) $resource->getKey(),
'workspace_id' => (int) $tenant->workspace_id,
'managed_environment_id' => (int) $tenant->getKey(),
'provider_connection_id' => (int) $connection->getKey(),
'resource_type_id' => (int) $resourceType->getKey(),
'operation_run_id' => (int) $run->getKey(),
]);
$resource->forceFill([
'latest_evidence_id' => (int) $evidence->getKey(),
])->save();
$resource->delete();
expect(TenantConfigurationResource::query()->whereKey($resource->getKey())->exists())->toBeFalse()
->and(TenantConfigurationResourceEvidence::query()->whereKey($evidence->getKey())->exists())->toBeFalse();
});
it('enforces evidence operation run scope at the PostgreSQL constraint layer', function (): void {
if (DB::getDriverName() !== 'pgsql') {
test()->markTestSkipped('PostgreSQL composite foreign key constraint coverage.');
}
[$user, $tenant] = createMinimalUserWithTenant(role: 'owner');
[, $otherTenant] = createMinimalUserWithTenant(role: 'owner');
$resourceType = spec415CaptureResourceType();
$connection = ProviderConnection::factory()->create([
'workspace_id' => (int) $tenant->workspace_id,
'managed_environment_id' => (int) $tenant->getKey(),
]);
$resource = spec415CaptureResource($tenant, $connection, $resourceType, 'operation-mismatch');
$foreignRun = OperationRun::factory()->forTenant($otherTenant)->create([
'type' => OperationRunType::TenantConfigurationCapture->value,
'status' => OperationRunStatus::Completed->value,
'outcome' => OperationRunOutcome::Succeeded->value,
]);
expect(fn () => DB::table('tenant_configuration_resource_evidence')->insert(
spec415EvidenceRow($tenant, $resource, $connection, $resourceType, $foreignRun),
))->toThrow(QueryException::class);
});
function spec415CaptureResourceType(): TenantConfigurationResourceType
{
app(ResourceTypeRegistry::class)->syncDefaults();
return TenantConfigurationResourceType::query()
->where('canonical_type', 'deviceAndAppManagementAssignmentFilter')
->firstOrFail();
}
function spec415CaptureResource(
ManagedEnvironment $tenant,
ProviderConnection $connection,
TenantConfigurationResourceType $resourceType,
string $suffix,
): TenantConfigurationResource {
return TenantConfigurationResource::query()->create([
'workspace_id' => (int) $tenant->workspace_id,
'managed_environment_id' => (int) $tenant->getKey(),
'provider_connection_id' => (int) $connection->getKey(),
'resource_type_id' => (int) $resourceType->getKey(),
'source_class' => SourceClass::Tcm->value,
'canonical_type' => (string) $resourceType->canonical_type,
'canonical_resource_key' => 'deviceAndAppManagementAssignmentFilter:'.$suffix,
'source_resource_id' => $suffix,
'source_metadata' => ['fixture' => 'resource-scope'],
'latest_evidence_state' => EvidenceState::NotCaptured->value,
'latest_identity_state' => IdentityState::Stable->value,
'latest_claim_state' => ClaimState::InternalOnly->value,
]);
}
function spec415CaptureRun(ManagedEnvironment $tenant, User $user): OperationRun
{
return OperationRun::factory()->withUser($user)->forTenant($tenant)->create([
'type' => OperationRunType::TenantConfigurationCapture->value,
'status' => OperationRunStatus::Completed->value,
'outcome' => OperationRunOutcome::Succeeded->value,
]);
}
function spec415EvidenceRow(
ManagedEnvironment $tenant,
TenantConfigurationResource $resource,
ProviderConnection $connection,
TenantConfigurationResourceType $resourceType,
OperationRun $run,
): array {
$now = now();
return [
'resource_id' => (int) $resource->getKey(),
'workspace_id' => (int) $tenant->workspace_id,
'managed_environment_id' => (int) $tenant->getKey(),
'provider_connection_id' => (int) $connection->getKey(),
'resource_type_id' => (int) $resourceType->getKey(),
'operation_run_id' => (int) $run->getKey(),
'source_contract_key' => 'assignmentFilter',
'source_endpoint' => '/deviceManagement/assignmentFilters',
'source_version' => 'v1.0',
'source_metadata' => json_encode(['fixture' => 'evidence-scope'], JSON_THROW_ON_ERROR),
'raw_payload' => json_encode(['id' => 'assignment-filter-'.$resource->getKey()], JSON_THROW_ON_ERROR),
'normalized_payload' => json_encode(['id' => 'assignment-filter-'.$resource->getKey()], JSON_THROW_ON_ERROR),
'payload_hash' => hash('sha256', 'assignment-filter-'.$resource->getKey()),
'permission_context' => json_encode(['scopes_granted' => []], JSON_THROW_ON_ERROR),
'evidence_state' => EvidenceState::ContentBacked->value,
'coverage_level' => 'content_backed',
'capture_outcome' => 'captured',
'captured_at' => $now,
'created_at' => $now,
'updated_at' => $now,
];
}