TenantAtlas/tests/Feature/WorkspaceIsolation/TenantOwnedWorkspaceInvariantTest.php

124 lines
4.5 KiB
PHP

<?php
use App\Models\BackupItem;
use App\Models\BackupSchedule;
use App\Models\BackupSet;
use App\Models\EntraGroup;
use App\Models\EntraRoleDefinition;
use App\Models\Finding;
use App\Models\InventoryItem;
use App\Models\InventoryLink;
use App\Models\Policy;
use App\Models\PolicyVersion;
use App\Models\RestoreRun;
use App\Models\Tenant;
use App\Models\TenantPermission;
use App\Models\Workspace;
use App\Support\WorkspaceIsolation\WorkspaceIsolationViolation;
use Illuminate\Foundation\Testing\RefreshDatabase;
uses(RefreshDatabase::class);
it('enforces tenant workspace binding for tenant-owned models even when events are disabled', function (): void {
$workspaceA = Workspace::factory()->create();
$workspaceB = Workspace::factory()->create();
$tenant = Tenant::factory()->create([
'workspace_id' => $workspaceA->getKey(),
]);
$policy = Policy::factory()->create([
'tenant_id' => $tenant->getKey(),
'workspace_id' => $workspaceA->getKey(),
]);
$backupSet = BackupSet::factory()->create([
'tenant_id' => $tenant->getKey(),
'workspace_id' => $workspaceA->getKey(),
]);
$cases = [
'policies' => fn (int $workspaceId) => Policy::factory()->make([
'tenant_id' => $tenant->getKey(),
'workspace_id' => $workspaceId,
]),
'policy_versions' => fn (int $workspaceId) => PolicyVersion::factory()->make([
'tenant_id' => $tenant->getKey(),
'workspace_id' => $workspaceId,
'policy_id' => $policy->getKey(),
]),
'backup_sets' => fn (int $workspaceId) => BackupSet::factory()->make([
'tenant_id' => $tenant->getKey(),
'workspace_id' => $workspaceId,
]),
'backup_items' => fn (int $workspaceId) => BackupItem::factory()->make([
'tenant_id' => $tenant->getKey(),
'workspace_id' => $workspaceId,
'backup_set_id' => $backupSet->getKey(),
'policy_id' => $policy->getKey(),
]),
'restore_runs' => fn (int $workspaceId) => RestoreRun::factory()->make([
'tenant_id' => $tenant->getKey(),
'workspace_id' => $workspaceId,
'backup_set_id' => $backupSet->getKey(),
]),
'backup_schedules' => fn (int $workspaceId) => BackupSchedule::make([
'tenant_id' => $tenant->getKey(),
'workspace_id' => $workspaceId,
'name' => 'Weekly backup',
'is_enabled' => true,
'timezone' => 'UTC',
'frequency' => 'daily',
'time_of_day' => '00:00:00',
'days_of_week' => null,
'policy_types' => ['settingsCatalogPolicy'],
'include_foundations' => true,
'retention_keep_last' => 30,
]),
'inventory_items' => fn (int $workspaceId) => InventoryItem::factory()->make([
'tenant_id' => $tenant->getKey(),
'workspace_id' => $workspaceId,
]),
'inventory_links' => fn (int $workspaceId) => InventoryLink::factory()->make([
'tenant_id' => $tenant->getKey(),
'workspace_id' => $workspaceId,
]),
'entra_groups' => fn (int $workspaceId) => EntraGroup::factory()->make([
'tenant_id' => $tenant->getKey(),
'workspace_id' => $workspaceId,
]),
'findings' => fn (int $workspaceId) => Finding::factory()->make([
'tenant_id' => $tenant->getKey(),
'workspace_id' => $workspaceId,
]),
'entra_role_definitions' => fn (int $workspaceId) => EntraRoleDefinition::factory()->make([
'tenant_id' => $tenant->getKey(),
'workspace_id' => $workspaceId,
]),
'tenant_permissions' => fn (int $workspaceId) => TenantPermission::make([
'tenant_id' => $tenant->getKey(),
'workspace_id' => $workspaceId,
'permission_key' => 'test.permission.'.uniqid(),
'status' => 'missing',
]),
];
foreach ($cases as $table => $makeModel) {
$model = $makeModel((int) $workspaceA->getKey());
($model::class)::withoutEvents(function () use ($model): void {
$model->save();
});
$this->assertDatabaseHas($table, [
'tenant_id' => $tenant->getKey(),
'workspace_id' => $workspaceA->getKey(),
]);
$mismatched = $makeModel((int) $workspaceB->getKey());
expect(fn () => $mismatched->save())
->toThrow(WorkspaceIsolationViolation::class);
}
});