create(); $tenant = Tenant::factory()->create([ 'workspace_id' => (int) $workspace->getKey(), ]); $policy = Policy::query()->create([ 'tenant_id' => (int) $tenant->getKey(), 'external_id' => 'policy-derived-workspace', 'policy_type' => 'settingsCatalogPolicy', 'display_name' => 'Derived Workspace Policy', 'platform' => 'windows', ]); expect((int) $policy->workspace_id)->toBe((int) $tenant->workspace_id); }); it('rejects create when workspace_id mismatches tenant workspace', function (): void { $workspaceA = Workspace::factory()->create(); $workspaceB = Workspace::factory()->create(); $tenant = Tenant::factory()->create([ 'workspace_id' => (int) $workspaceA->getKey(), ]); expect(fn () => Policy::query()->create([ 'tenant_id' => (int) $tenant->getKey(), 'workspace_id' => (int) $workspaceB->getKey(), 'external_id' => 'policy-workspace-mismatch', 'policy_type' => 'settingsCatalogPolicy', 'display_name' => 'Workspace Mismatch Policy', 'platform' => 'windows', ]))->toThrow(WorkspaceIsolationViolation::class); }); it('rejects tenant_id changes after create', function (): void { $workspaceA = Workspace::factory()->create(); $workspaceB = Workspace::factory()->create(); $tenantA = Tenant::factory()->create([ 'workspace_id' => (int) $workspaceA->getKey(), ]); $tenantB = Tenant::factory()->create([ 'workspace_id' => (int) $workspaceB->getKey(), ]); $policy = Policy::query()->create([ 'tenant_id' => (int) $tenantA->getKey(), 'external_id' => 'policy-tenant-immutable', 'policy_type' => 'settingsCatalogPolicy', 'display_name' => 'Tenant Immutable Policy', 'platform' => 'windows', ]); expect(fn () => $policy->update([ 'tenant_id' => (int) $tenantB->getKey(), ]))->toThrow(WorkspaceIsolationViolation::class); $policy->refresh(); expect((int) $policy->tenant_id)->toBe((int) $tenantA->getKey()); expect((int) $policy->workspace_id)->toBe((int) $tenantA->workspace_id); });