tenant = Tenant::factory()->create(['status' => 'active']); ensureDefaultProviderConnection($this->tenant); $this->policy = Policy::factory()->create([ 'tenant_id' => $this->tenant->id, 'policy_type' => 'deviceConfiguration', 'platform' => 'windows', 'display_name' => 'Test Policy', ]); config()->set('tenantpilot.foundation_types', [ [ 'type' => 'assignmentFilter', 'label' => 'Assignment Filter', 'category' => 'Foundations', 'platform' => 'all', 'endpoint' => 'deviceManagement/assignmentFilters', 'backup' => 'full', 'restore' => 'enabled', 'risk' => 'low', ], ]); $this->mock(PolicySnapshotService::class, function (MockInterface $mock) { $mock->shouldReceive('fetch') ->andReturn([ 'payload' => [ '@odata.type' => '#microsoft.graph.deviceConfiguration', 'id' => 'policy-1', 'displayName' => 'Test Policy', ], 'metadata' => [], 'warnings' => [], ]); }); $this->mock(FoundationSnapshotService::class, function (MockInterface $mock) { $mock->shouldReceive('fetchAll') ->zeroOrMoreTimes() ->andReturn([ 'items' => [ [ 'source_id' => 'filter-1', 'display_name' => 'Filter One', 'payload' => [ 'id' => 'filter-1', 'displayName' => 'Filter One', ], 'metadata' => [ 'displayName' => 'Filter One', 'kind' => 'assignmentFilter', 'graph' => [ 'resource' => 'deviceManagement/assignmentFilters', 'apiVersion' => 'beta', ], ], ], ], 'failures' => [], ]); }); }); it('creates foundation backup items when requested', function () { $service = app(BackupService::class); $backupSet = $service->createBackupSet( tenant: $this->tenant, policyIds: [$this->policy->id], name: 'Foundation Backup', includeFoundations: true, ); expect($backupSet->items)->toHaveCount(2); $foundationItem = BackupItem::query() ->where('backup_set_id', $backupSet->id) ->where('policy_type', 'assignmentFilter') ->first(); expect($foundationItem)->not->toBeNull(); expect($foundationItem->policy_id)->toBeNull(); expect($foundationItem->policy_identifier)->toBe('filter-1'); expect($foundationItem->metadata['displayName'])->toBe('Filter One'); }); it('captures RBAC foundations with linked immutable policy versions', function () { config()->set('tenantpilot.foundation_types', [ [ 'type' => 'intuneRoleDefinition', 'label' => 'Intune Role Definition', 'category' => 'RBAC', 'platform' => 'all', 'endpoint' => 'deviceManagement/roleDefinitions', 'backup' => 'full', 'restore' => 'preview-only', 'risk' => 'high', ], [ 'type' => 'intuneRoleAssignment', 'label' => 'Intune Role Assignment', 'category' => 'RBAC', 'platform' => 'all', 'endpoint' => 'deviceManagement/roleAssignments', 'backup' => 'full', 'restore' => 'preview-only', 'risk' => 'high', ], ]); $this->mock(FoundationSnapshotService::class, function (MockInterface $mock) { $mock->shouldReceive('fetchAll') ->twice() ->andReturnUsing(function (Tenant $tenant, string $foundationType): array { return match ($foundationType) { 'intuneRoleDefinition' => [ 'items' => [[ 'source_id' => 'role-def-1', 'display_name' => 'Policy and Profile Manager', 'payload' => [ 'id' => 'role-def-1', 'displayName' => 'Policy and Profile Manager', 'description' => 'Built-in RBAC role', 'isBuiltIn' => true, 'rolePermissions' => [ [ 'resourceActions' => [ [ 'allowedResourceActions' => [ 'Microsoft.Intune/deviceConfigurations/read', ], ], ], ], ], ], 'metadata' => [ 'displayName' => 'Policy and Profile Manager', 'kind' => 'intuneRoleDefinition', 'graph' => [ 'resource' => 'deviceManagement/roleDefinitions', 'apiVersion' => 'beta', ], ], ]], 'failures' => [], ], 'intuneRoleAssignment' => [ 'items' => [[ 'source_id' => 'role-assign-1', 'display_name' => 'Helpdesk Assignment', 'payload' => [ 'id' => 'role-assign-1', 'displayName' => 'Helpdesk Assignment', 'members' => ['group-1'], 'scopeMembers' => ['scope-group-1'], 'resourceScopes' => ['/'], 'roleDefinition' => [ 'id' => 'role-def-1', 'displayName' => 'Policy and Profile Manager', ], ], 'metadata' => [ 'displayName' => 'Helpdesk Assignment', 'kind' => 'intuneRoleAssignment', 'graph' => [ 'resource' => 'deviceManagement/roleAssignments', 'apiVersion' => 'beta', ], ], ]], 'failures' => [], ], default => [ 'items' => [], 'failures' => [], ], }; }); }); $service = app(BackupService::class); $backupSet = $service->createBackupSet( tenant: $this->tenant, policyIds: [], name: 'RBAC Foundation Backup', includeFoundations: true, ); $definitionItem = BackupItem::query() ->where('backup_set_id', $backupSet->id) ->where('policy_type', 'intuneRoleDefinition') ->first(); $assignmentItem = BackupItem::query() ->where('backup_set_id', $backupSet->id) ->where('policy_type', 'intuneRoleAssignment') ->first(); expect($backupSet->item_count)->toBe(2); expect($definitionItem)->not->toBeNull(); expect($assignmentItem)->not->toBeNull(); expect($definitionItem->policy_id)->not->toBeNull(); expect($definitionItem->policy_version_id)->not->toBeNull(); expect($definitionItem->resolvedDisplayName())->toBe('Policy and Profile Manager'); expect($assignmentItem->policy_id)->not->toBeNull(); expect($assignmentItem->policy_version_id)->not->toBeNull(); expect($assignmentItem->resolvedDisplayName())->toBe('Helpdesk Assignment'); expect(Policy::query()->where('tenant_id', $this->tenant->id)->where('policy_type', 'intuneRoleDefinition')->count())->toBe(1); expect(PolicyVersion::query()->where('tenant_id', $this->tenant->id)->where('policy_type', 'intuneRoleAssignment')->count())->toBe(1); });