'tenant-policy-version-wizard', 'name' => 'Tenant', 'metadata' => [], ]); $tenant->makeCurrent(); $policy = Policy::create([ 'tenant_id' => $tenant->id, 'external_id' => 'policy-1', 'policy_type' => 'settingsCatalogPolicy', 'display_name' => 'Settings Catalog', 'platform' => 'windows', ]); $version = PolicyVersion::create([ 'tenant_id' => $tenant->id, 'policy_id' => $policy->id, 'version_number' => 3, 'policy_type' => $policy->policy_type, 'platform' => $policy->platform, 'captured_at' => now(), 'snapshot' => ['id' => $policy->external_id, 'displayName' => $policy->display_name], 'assignments' => [['intent' => 'apply']], 'scope_tags' => [ 'ids' => ['st-1'], 'names' => ['Tag 1'], ], ]); $user = User::factory()->create(['email' => 'tester@example.com']); $user->tenants()->syncWithoutDetaching([ $tenant->getKey() => ['role' => 'owner'], ]); $this->actingAs($user); Filament::setTenant($tenant, true); Livewire::test(ListPolicyVersions::class) ->callTableAction('restore_via_wizard', $version) ->assertRedirectContains(RestoreRunResource::getUrl('create', [], false, tenant: $tenant)); $backupSet = BackupSet::query()->where('metadata->source', 'policy_version')->first(); expect($backupSet)->not->toBeNull(); expect($backupSet->tenant_id)->toBe($tenant->id); expect($backupSet->metadata['policy_version_id'] ?? null)->toBe($version->id); $backupItem = BackupItem::query()->where('backup_set_id', $backupSet->id)->first(); expect($backupItem)->not->toBeNull(); expect($backupItem->policy_version_id)->toBe($version->id); expect($backupItem->policy_identifier)->toBe($policy->external_id); expect($backupItem->metadata['scope_tag_ids'] ?? null)->toBe(['st-1']); expect($backupItem->metadata['scope_tag_names'] ?? null)->toBe(['Tag 1']); }); test('readonly users cannot open restore wizard via policy version row action', function () { $tenant = Tenant::create([ 'tenant_id' => 'tenant-policy-version-wizard-readonly', 'name' => 'Tenant', 'metadata' => [], ]); $tenant->makeCurrent(); $policy = Policy::create([ 'tenant_id' => $tenant->id, 'external_id' => 'policy-ro-1', 'policy_type' => 'settingsCatalogPolicy', 'display_name' => 'Settings Catalog', 'platform' => 'windows', ]); $version = PolicyVersion::create([ 'tenant_id' => $tenant->id, 'policy_id' => $policy->id, 'version_number' => 1, 'policy_type' => $policy->policy_type, 'platform' => $policy->platform, 'captured_at' => now(), 'snapshot' => ['id' => $policy->external_id, 'displayName' => $policy->display_name], ]); $user = User::factory()->create(['email' => 'readonly@example.com']); $user->tenants()->syncWithoutDetaching([ $tenant->getKey() => ['role' => 'readonly'], ]); $this->actingAs($user); Filament::setTenant($tenant, true); Livewire::test(ListPolicyVersions::class) ->assertTableActionDisabled('restore_via_wizard', $version) ->callTableAction('restore_via_wizard', $version); expect(BackupSet::query()->where('metadata->source', 'policy_version')->exists())->toBeFalse(); expect(BackupItem::query()->exists())->toBeFalse(); }); test('restore run wizard can be prefilled from query params for policy version backup set', function () { $tenant = Tenant::create([ 'tenant_id' => 'tenant-policy-version-prefill', 'name' => 'Tenant', 'metadata' => [], ]); $tenant->makeCurrent(); $policy = Policy::create([ 'tenant_id' => $tenant->id, 'external_id' => 'policy-2', 'policy_type' => 'settingsCatalogPolicy', 'display_name' => 'Settings Catalog', 'platform' => 'windows', ]); $version = PolicyVersion::create([ 'tenant_id' => $tenant->id, 'policy_id' => $policy->id, 'version_number' => 1, 'policy_type' => $policy->policy_type, 'platform' => $policy->platform, 'captured_at' => now(), 'snapshot' => ['id' => $policy->external_id], 'assignments' => [[ 'target' => [ '@odata.type' => '#microsoft.graph.groupAssignmentTarget', 'groupId' => 'source-group-1', 'group_display_name' => 'Source Group', ], 'intent' => 'apply', ]], ]); $backupSet = BackupSet::create([ 'tenant_id' => $tenant->id, 'name' => 'Policy Version Restore', 'status' => 'completed', 'item_count' => 1, 'completed_at' => now(), 'metadata' => [ 'source' => 'policy_version', 'policy_version_id' => $version->id, ], ]); $backupItem = BackupItem::create([ 'tenant_id' => $tenant->id, 'backup_set_id' => $backupSet->id, 'policy_id' => $policy->id, 'policy_version_id' => $version->id, 'policy_identifier' => $policy->external_id, 'policy_type' => $policy->policy_type, 'platform' => $policy->platform, 'payload' => $version->snapshot ?? [], 'assignments' => $version->assignments, ]); $this->mock(GroupResolver::class, function (MockInterface $mock) { $mock->shouldReceive('resolveGroupIds') ->andReturnUsing(function (array $groupIds): array { return collect($groupIds) ->mapWithKeys(fn (string $id) => [$id => [ 'id' => $id, 'displayName' => null, 'orphaned' => true, ]]) ->all(); }); }); $user = User::factory()->create(); $user->tenants()->syncWithoutDetaching([ $tenant->getKey() => ['role' => 'owner'], ]); $this->actingAs($user); Filament::setTenant($tenant, true); $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'))->toBe($backupSet->id); expect($component->get('data.scope_mode'))->toBe('selected'); expect($component->get('data.backup_item_ids'))->toBe([$backupItem->id]); $mapping = $component->get('data.group_mapping'); expect($mapping)->toBeArray(); expect(array_key_exists('source-group-1', $mapping))->toBeTrue(); expect($mapping['source-group-1'])->toBeNull(); $component ->goToNextWizardStep() ->assertFormFieldVisible('group_mapping.source-group-1'); });