## 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
127 lines
4.4 KiB
PHP
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();
|
|
});
|