TenantAtlas/tests/Feature/Filament/PolicyVersionTest.php
ahmido c6e7591d19 feat: add Intune RBAC inventory and backup support (#155)
## Summary
- add Intune RBAC role definitions and role assignments as foundation-backed inventory, backup, and versioned snapshot types
- add RBAC-specific normalization, coverage, permission-warning handling, and preview-only restore safety behavior across existing Filament and service surfaces
- add spec 127 artifacts, contracts, audits, and focused regression coverage for inventory, backup, versioning, verification, and authorization behavior

## Testing
- `vendor/bin/sail bin pint --dirty --format agent`
- `vendor/bin/sail artisan test --compact tests/Feature/Inventory/InventorySyncServiceTest.php tests/Feature/Filament/InventoryCoverageTableTest.php tests/Feature/FoundationBackupTest.php tests/Feature/Filament/RestoreExecutionTest.php tests/Feature/RestoreUnknownPolicyTypeSafetyTest.php tests/Unit/GraphContractRegistryTest.php tests/Unit/FoundationSnapshotServiceTest.php tests/Feature/Verification/IntuneRbacPermissionCoverageTest.php tests/Unit/IntuneRoleDefinitionNormalizerTest.php tests/Unit/IntuneRoleAssignmentNormalizerTest.php`

## Notes
- tasks in `specs/127-rbac-inventory-backup/tasks.md` are complete except `T041`, which is the documented manual QA validation step

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #155
2026-03-09 10:40:51 +00:00

127 lines
4.4 KiB
PHP

<?php
use App\Models\Policy;
use App\Models\PolicyVersion;
use App\Models\Tenant;
use App\Models\User;
use App\Models\WorkspaceMembership;
use App\Services\Intune\VersionService;
use Illuminate\Foundation\Testing\RefreshDatabase;
uses(RefreshDatabase::class);
test('policy versions render with timeline data', function () {
$tenant = Tenant::factory()->create();
$policy = Policy::create([
'tenant_id' => $tenant->id,
'external_id' => 'policy-1',
'policy_type' => 'deviceConfiguration',
'display_name' => 'Policy A',
'platform' => 'windows',
]);
$service = app(VersionService::class);
$service->captureVersion($policy, ['value' => 1], 'tester');
$service->captureVersion($policy, ['value' => 2], 'tester');
$user = User::factory()->create();
[$user, $tenant] = createUserWithTenant(tenant: $tenant, user: $user, role: 'owner');
$this->actingAs($user)
->get(route('filament.admin.resources.policy-versions.index', filamentTenantRouteParams($tenant)))
->assertOk()
->assertSee('Policy A')
->assertSee((string) PolicyVersion::max('version_number'));
});
test('policy version detail renders readable normalized RBAC assignment content', function () {
$tenant = Tenant::factory()->create();
[$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'owner');
$policy = Policy::factory()->create([
'tenant_id' => $tenant->id,
'external_id' => 'rbac-assign-1',
'policy_type' => 'intuneRoleAssignment',
'display_name' => 'Current assignment name',
'platform' => 'all',
'last_synced_at' => null,
]);
$version = PolicyVersion::factory()->create([
'tenant_id' => $tenant->id,
'policy_id' => $policy->id,
'policy_type' => 'intuneRoleAssignment',
'platform' => 'all',
'snapshot' => [
'@odata.type' => '#microsoft.graph.deviceAndAppManagementRoleAssignment',
'displayName' => 'Helpdesk Assignment',
'description' => 'Delegated access for helpdesk operators',
'scopeType' => 'allDevicesAssignment',
'members' => [
['displayName' => 'Helpdesk Group', 'id' => 'group-1'],
'group-2',
],
'scopeMembers' => ['scope-group-1'],
'resourceScopes' => ['/', '/deviceManagement/managedDevices'],
'roleDefinition' => [
'id' => 'role-1',
'displayName' => 'Policy and Profile Manager',
],
],
]);
$tenant->makeCurrent();
$response = $this->actingAs($user)
->get(\App\Filament\Resources\PolicyVersionResource::getUrl('view', ['record' => $version]).'?tab=normalized-settings&tenant='.(string) $tenant->external_id);
$response->assertOk();
$response->assertSee('Helpdesk Assignment');
$response->assertSee('Role assignment');
$response->assertSee('Policy and Profile Manager (role-1)');
$response->assertSee('Helpdesk Group (group-1)');
$response->assertSee('group-2');
$response->assertSee('scope-group-1');
$response->assertSee('/deviceManagement/managedDevices');
});
test('policy version detail returns 404 for non-members on RBAC versions', function () {
$tenant = Tenant::factory()->create();
[$owner, $tenant] = createUserWithTenant(tenant: $tenant, role: 'owner');
$policy = Policy::factory()->create([
'tenant_id' => $tenant->id,
'external_id' => 'rbac-assign-404',
'policy_type' => 'intuneRoleAssignment',
'display_name' => 'Hidden assignment',
'platform' => 'all',
'last_synced_at' => null,
]);
$version = PolicyVersion::factory()->create([
'tenant_id' => $tenant->id,
'policy_id' => $policy->id,
'policy_type' => 'intuneRoleAssignment',
'platform' => 'all',
'snapshot' => [
'displayName' => 'Hidden assignment',
],
]);
$outsider = User::factory()->create();
WorkspaceMembership::factory()->create([
'workspace_id' => (int) $tenant->workspace_id,
'user_id' => (int) $outsider->getKey(),
'role' => 'owner',
]);
$tenant->makeCurrent();
$this->actingAs($outsider)
->get(\App\Filament\Resources\PolicyVersionResource::getUrl('view', ['record' => $version]).'?tenant='.(string) $tenant->external_id)
->assertNotFound();
});