'tenant-1', 'name' => 'Tenant One', 'metadata' => [], 'rbac_status' => 'ok', 'rbac_last_checked_at' => now(), ]); $tenant->makeCurrent(); ensureDefaultProviderConnection($tenant, 'microsoft'); $policy = Policy::create([ 'tenant_id' => $tenant->id, 'external_id' => 'policy-1', 'policy_type' => 'deviceConfiguration', 'display_name' => 'Device Config Policy', 'platform' => 'windows', ]); $backupSet = BackupSet::create([ 'tenant_id' => $tenant->id, 'name' => 'Backup', 'status' => 'completed', 'item_count' => 1, ]); $backupItem = BackupItem::create([ 'tenant_id' => $tenant->id, 'backup_set_id' => $backupSet->id, 'policy_id' => $policy->id, 'policy_identifier' => $policy->external_id, 'policy_type' => $policy->policy_type, 'platform' => $policy->platform, 'payload' => ['id' => $policy->external_id], 'metadata' => [ 'displayName' => 'Backup Policy', ], ]); $user = User::factory()->create([ 'email' => 'tester@example.com', 'name' => 'Tester', ]); $this->actingAs($user); $user->tenants()->syncWithoutDetaching([ $tenant->getKey() => ['role' => 'owner'], ]); Filament::setTenant($tenant, true); Livewire::test(CreateRestoreRun::class) ->fillForm([ 'backup_set_id' => $backupSet->id, ]) ->goToNextWizardStep() ->fillForm([ 'scope_mode' => 'selected', 'backup_item_ids' => [$backupItem->id], ]) ->goToNextWizardStep() ->callFormComponentAction('check_results', 'run_restore_checks') ->goToNextWizardStep() ->callFormComponentAction('preview_diffs', 'run_restore_preview') ->goToNextWizardStep() ->fillForm([ 'is_dry_run' => false, ]) ->call('create') ->assertHasFormErrors(['acknowledged_impact', 'tenant_confirm']); expect(RestoreRun::count())->toBe(0); }); test('restore run wizard queues execution when gates are satisfied', function () { Bus::fake(); $tenant = Tenant::create([ 'tenant_id' => 'tenant-2', 'name' => 'Tenant Two', 'metadata' => [], 'rbac_status' => 'ok', 'rbac_last_checked_at' => now(), ]); $tenant->makeCurrent(); ensureDefaultProviderConnection($tenant, 'microsoft'); $policy = Policy::create([ 'tenant_id' => $tenant->id, 'external_id' => 'policy-2', 'policy_type' => 'deviceConfiguration', 'display_name' => 'Device Config Policy', 'platform' => 'windows', ]); $backupSet = BackupSet::create([ 'tenant_id' => $tenant->id, 'name' => 'Backup', 'status' => 'completed', 'item_count' => 1, ]); $backupItem = BackupItem::create([ 'tenant_id' => $tenant->id, 'backup_set_id' => $backupSet->id, 'policy_id' => $policy->id, 'policy_identifier' => $policy->external_id, 'policy_type' => $policy->policy_type, 'platform' => $policy->platform, 'payload' => ['id' => $policy->external_id], 'metadata' => [ 'displayName' => 'Backup Policy', ], ]); $user = User::factory()->create([ 'email' => 'executor@example.com', 'name' => 'Executor', ]); $this->actingAs($user); $user->tenants()->syncWithoutDetaching([ $tenant->getKey() => ['role' => 'owner'], ]); Filament::setTenant($tenant, true); Livewire::test(CreateRestoreRun::class) ->fillForm([ 'backup_set_id' => $backupSet->id, ]) ->goToNextWizardStep() ->fillForm([ 'scope_mode' => 'selected', 'backup_item_ids' => [$backupItem->id], ]) ->goToNextWizardStep() ->callFormComponentAction('check_results', 'run_restore_checks') ->goToNextWizardStep() ->callFormComponentAction('preview_diffs', 'run_restore_preview') ->goToNextWizardStep() ->fillForm([ 'is_dry_run' => false, 'acknowledged_impact' => true, 'tenant_confirm' => 'Tenant Two', ]) ->call('create') ->assertHasNoFormErrors(); $run = RestoreRun::query()->latest('id')->first(); expect($run)->not->toBeNull(); expect($run->status)->toBe(RestoreRunStatus::Queued->value); expect($run->is_dry_run)->toBeFalse(); expect($run->metadata['confirmed_by'] ?? null)->toBe('executor@example.com'); expect($run->metadata['confirmed_at'] ?? null)->toBeString(); $operationRun = OperationRun::query() ->where('tenant_id', $tenant->id) ->where('type', 'restore.execute') ->latest('id') ->first(); expect($operationRun)->not->toBeNull(); expect($operationRun?->status)->toBe('queued'); expect((int) ($operationRun?->context['restore_run_id'] ?? 0))->toBe((int) $run->getKey()); expect((int) ($run->refresh()->operation_run_id ?? 0))->toBe((int) ($operationRun?->getKey() ?? 0)); Bus::assertDispatched(ExecuteRestoreRunJob::class, function (ExecuteRestoreRunJob $job) use ($run, $operationRun): bool { return $job->restoreRunId === (int) $run->getKey() && $job->operationRun instanceof OperationRun && $job->operationRun->getKey() === $operationRun?->getKey(); }); }); test('admin restore run wizard ignores prefill query params for backup sets outside the canonical tenant', function () { $tenantA = Tenant::factory()->create([ 'name' => 'Phoenicon', 'environment' => 'dev', ]); [$user, $tenantA] = createUserWithTenant(tenant: $tenantA, role: 'owner'); $tenantB = Tenant::factory()->create([ 'workspace_id' => (int) $tenantA->workspace_id, 'name' => 'YPTW2', 'environment' => 'dev', ]); createUserWithTenant(tenant: $tenantB, user: $user, role: 'owner'); $policy = Policy::factory()->for($tenantB)->create([ 'external_id' => 'policy-admin-prefill-wrong-tenant', ]); $backupSet = BackupSet::factory()->for($tenantB)->create([ 'status' => 'completed', 'item_count' => 1, ]); $backupItem = BackupItem::factory()->for($tenantB)->for($backupSet)->for($policy)->create(); $this->actingAs($user); Filament::setCurrentPanel('admin'); Filament::setTenant(null, true); Filament::bootCurrentPanel(); session()->put(WorkspaceContext::SESSION_KEY, (int) $tenantA->workspace_id); session()->put(WorkspaceContext::LAST_TENANT_IDS_SESSION_KEY, [ (string) $tenantA->workspace_id => (int) $tenantA->getKey(), ]); $component = Livewire::withQueryParams([ 'backup_set_id' => $backupSet->id, 'scope_mode' => 'selected', 'backup_item_ids' => [$backupItem->id], ])->test(CreateRestoreRun::class); expect($component->get('data.backup_set_id'))->toBeNull(); expect($component->get('data.scope_mode'))->not->toBe('selected'); expect($component->get('data.backup_item_ids'))->toBe([]); });