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, ]; }