TenantAtlas/tests/Feature/PolicyTypes017Test.php
ahmido 412dd7ad66 feat/017-policy-types-mam-endpoint-security-baselines (#23)
Hydrate configurationPolicies/{id}/settings for endpoint security/baseline policies so snapshots include real rule data.
Treat those types like Settings Catalog policies in the normalizer so they show the searchable settings table, recognizable categories, and readable choice values (firewall-specific formatting + interface badge parsing).
Improve “General” tab cards: badge lists for platforms/technologies, template reference summary (name/family/version/ID), and ISO timestamps rendered as YYYY‑MM‑DD HH:MM:SS; added regression test for the view.

Co-authored-by: Ahmed Darrazi <ahmeddarrazi@adsmac.local>
Reviewed-on: #23
2026-01-03 02:06:35 +00:00

268 lines
9.7 KiB
PHP

<?php
use App\Models\BackupItem;
use App\Models\BackupSet;
use App\Models\Policy;
use App\Models\PolicyVersion;
use App\Models\Tenant;
use App\Models\User;
use App\Services\Graph\GraphClientInterface;
use App\Services\Graph\GraphResponse;
use App\Services\Intune\BackupService;
use App\Services\Intune\PolicyCaptureOrchestrator;
use App\Services\Intune\RestoreService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Mockery\MockInterface;
uses(RefreshDatabase::class);
class PolicyTypes017GraphClient implements GraphClientInterface
{
/** @var array<int, array{method:string,policyType?:string,policyId?:string,path?:string,options:array<string,mixed>}> */
public array $requests = [];
public function listPolicies(string $policyType, array $options = []): GraphResponse
{
$this->requests[] = ['method' => 'listPolicies', 'policyType' => $policyType, 'options' => $options];
return new GraphResponse(success: true, data: []);
}
public function getPolicy(string $policyType, string $policyId, array $options = []): GraphResponse
{
$this->requests[] = ['method' => 'getPolicy', 'policyType' => $policyType, 'policyId' => $policyId, 'options' => $options];
$payload = match ($policyType) {
'mamAppConfiguration' => [
'id' => $policyId,
'displayName' => 'MAM App Config',
'@odata.type' => '#microsoft.graph.targetedManagedAppConfiguration',
'roleScopeTagIds' => ['0'],
],
'endpointSecurityPolicy' => [
'id' => $policyId,
'name' => 'Endpoint Security Policy',
'@odata.type' => '#microsoft.graph.deviceManagementConfigurationPolicy',
'technologies' => ['endpointSecurity'],
'roleScopeTagIds' => ['0'],
],
'securityBaselinePolicy' => [
'id' => $policyId,
'name' => 'Security Baseline Policy',
'@odata.type' => '#microsoft.graph.deviceManagementConfigurationPolicy',
'templateReference' => ['templateFamily' => 'securityBaseline'],
'roleScopeTagIds' => ['0'],
],
default => [
'id' => $policyId,
'name' => 'Settings Catalog Policy',
'@odata.type' => '#microsoft.graph.deviceManagementConfigurationPolicy',
'technologies' => ['mdm'],
'roleScopeTagIds' => ['0'],
],
};
return new GraphResponse(success: true, data: ['payload' => $payload]);
}
public function getOrganization(array $options = []): GraphResponse
{
$this->requests[] = ['method' => 'getOrganization', 'options' => $options];
return new GraphResponse(success: true, data: []);
}
public function applyPolicy(string $policyType, string $policyId, array $payload, array $options = []): GraphResponse
{
$this->requests[] = ['method' => 'applyPolicy', 'policyType' => $policyType, 'policyId' => $policyId, 'options' => $options];
return new GraphResponse(success: true, data: []);
}
public function getServicePrincipalPermissions(array $options = []): GraphResponse
{
$this->requests[] = ['method' => 'getServicePrincipalPermissions', 'options' => $options];
return new GraphResponse(success: true, data: []);
}
public function request(string $method, string $path, array $options = []): GraphResponse
{
$this->requests[] = ['method' => 'request', 'path' => $path, 'options' => $options];
return new GraphResponse(success: true, data: []);
}
}
it('creates backup items for the new 017 policy types', function () {
$tenant = Tenant::factory()->create();
$tenant->makeCurrent();
$user = User::factory()->create();
$this->actingAs($user);
$mam = Policy::factory()->create([
'tenant_id' => $tenant->id,
'external_id' => 'mam-1',
'policy_type' => 'mamAppConfiguration',
'platform' => 'mobile',
]);
$esp = Policy::factory()->create([
'tenant_id' => $tenant->id,
'external_id' => 'esp-1',
'policy_type' => 'endpointSecurityPolicy',
'platform' => 'windows',
]);
$sb = Policy::factory()->create([
'tenant_id' => $tenant->id,
'external_id' => 'sb-1',
'policy_type' => 'securityBaselinePolicy',
'platform' => 'windows',
]);
$this->mock(PolicyCaptureOrchestrator::class, function (MockInterface $mock) use ($tenant) {
$mock->shouldReceive('capture')
->times(3)
->andReturnUsing(function (Policy $policy) use ($tenant) {
$snapshot = match ($policy->policy_type) {
'mamAppConfiguration' => [
'id' => $policy->external_id,
'displayName' => 'MAM App Config',
'@odata.type' => '#microsoft.graph.targetedManagedAppConfiguration',
'roleScopeTagIds' => ['0'],
],
'endpointSecurityPolicy' => [
'id' => $policy->external_id,
'name' => 'Endpoint Security Policy',
'@odata.type' => '#microsoft.graph.deviceManagementConfigurationPolicy',
'technologies' => ['endpointSecurity'],
'roleScopeTagIds' => ['0'],
],
'securityBaselinePolicy' => [
'id' => $policy->external_id,
'name' => 'Security Baseline Policy',
'@odata.type' => '#microsoft.graph.deviceManagementConfigurationPolicy',
'templateReference' => ['templateFamily' => 'securityBaseline'],
'roleScopeTagIds' => ['0'],
],
default => [
'id' => $policy->external_id,
'name' => 'Settings Catalog Policy',
'@odata.type' => '#microsoft.graph.deviceManagementConfigurationPolicy',
'technologies' => ['mdm'],
'roleScopeTagIds' => ['0'],
],
};
$version = PolicyVersion::factory()->create([
'tenant_id' => $tenant->id,
'policy_id' => $policy->id,
'snapshot' => $snapshot,
'assignments' => null,
'scope_tags' => null,
]);
return [
'version' => $version,
'captured' => [
'payload' => $snapshot,
'assignments' => null,
'scope_tags' => null,
'metadata' => [],
'warnings' => [],
],
];
});
});
$service = app(BackupService::class);
$backupSet = $service->createBackupSet(
tenant: $tenant,
policyIds: [$mam->id, $esp->id, $sb->id],
actorEmail: $user->email,
actorName: $user->name,
name: '017 backup',
includeAssignments: false,
includeScopeTags: false,
includeFoundations: false,
);
expect($backupSet->items)->toHaveCount(3);
$types = $backupSet->items->pluck('policy_type')->all();
sort($types);
expect($types)->toBe([
'endpointSecurityPolicy',
'mamAppConfiguration',
'securityBaselinePolicy',
]);
expect(BackupItem::query()->where('backup_set_id', $backupSet->id)->count())
->toBe(3);
});
it('uses configured restore modes in preview for the new 017 policy types', function () {
$this->mock(GraphClientInterface::class);
$tenant = Tenant::factory()->create();
$backupSet = BackupSet::factory()->create([
'tenant_id' => $tenant->id,
'status' => 'completed',
'item_count' => 3,
]);
BackupItem::factory()->create([
'tenant_id' => $tenant->id,
'backup_set_id' => $backupSet->id,
'policy_id' => null,
'policy_identifier' => 'mam-1',
'policy_type' => 'mamAppConfiguration',
'platform' => 'mobile',
'payload' => [
'id' => 'mam-1',
'@odata.type' => '#microsoft.graph.targetedManagedAppConfiguration',
],
]);
BackupItem::factory()->create([
'tenant_id' => $tenant->id,
'backup_set_id' => $backupSet->id,
'policy_id' => null,
'policy_identifier' => 'esp-1',
'policy_type' => 'endpointSecurityPolicy',
'platform' => 'windows',
'payload' => [
'id' => 'esp-1',
'@odata.type' => '#microsoft.graph.deviceManagementConfigurationPolicy',
'technologies' => ['endpointSecurity'],
],
]);
BackupItem::factory()->create([
'tenant_id' => $tenant->id,
'backup_set_id' => $backupSet->id,
'policy_id' => null,
'policy_identifier' => 'sb-1',
'policy_type' => 'securityBaselinePolicy',
'platform' => 'windows',
'payload' => [
'id' => 'sb-1',
'@odata.type' => '#microsoft.graph.deviceManagementConfigurationPolicy',
'templateReference' => ['templateFamily' => 'securityBaseline'],
],
]);
$service = app(RestoreService::class);
$preview = $service->preview($tenant, $backupSet);
$byType = collect($preview)->keyBy('policy_type');
expect($byType['mamAppConfiguration']['restore_mode'])->toBe('enabled');
expect($byType['endpointSecurityPolicy']['restore_mode'])->toBe('preview-only');
expect($byType['securityBaselinePolicy']['restore_mode'])->toBe('preview-only');
});