256 lines
8.0 KiB
PHP
256 lines
8.0 KiB
PHP
<?php
|
|
|
|
use App\Models\AuditLog;
|
|
use App\Models\Tenant;
|
|
use App\Services\AssignmentRestoreService;
|
|
use App\Services\Graph\AssignmentFilterResolver;
|
|
use App\Services\Graph\GraphClientInterface;
|
|
use App\Services\Graph\GraphContractRegistry;
|
|
use App\Services\Graph\GraphLogger;
|
|
use App\Services\Graph\GraphResponse;
|
|
use App\Services\Intune\AuditLogger;
|
|
use Tests\TestCase;
|
|
|
|
uses(TestCase::class);
|
|
|
|
beforeEach(function () {
|
|
config()->set('graph_contracts.types.deviceManagementScript', [
|
|
'assignments_create_path' => '/deviceManagement/deviceManagementScripts/{id}/assign',
|
|
'assignments_create_method' => 'POST',
|
|
'assignments_payload_key' => 'deviceManagementScriptAssignments',
|
|
]);
|
|
config()->set('graph_contracts.types.settingsCatalogPolicy', [
|
|
'assignments_create_path' => '/deviceManagement/configurationPolicies/{id}/assign',
|
|
'assignments_create_method' => 'POST',
|
|
]);
|
|
config()->set('graph_contracts.types.appProtectionPolicy', [
|
|
'assignments_create_path' => '/deviceAppManagement/managedAppPolicies/{id}/assign',
|
|
'assignments_create_method' => 'POST',
|
|
'assignments_payload_key' => 'assignments',
|
|
]);
|
|
|
|
$this->graphClient = Mockery::mock(GraphClientInterface::class);
|
|
$this->auditLogger = Mockery::mock(AuditLogger::class);
|
|
$this->filterResolver = Mockery::mock(AssignmentFilterResolver::class);
|
|
$this->filterResolver->shouldReceive('resolve')->andReturn([])->byDefault();
|
|
|
|
$this->service = new AssignmentRestoreService(
|
|
$this->graphClient,
|
|
app(GraphContractRegistry::class),
|
|
app(GraphLogger::class),
|
|
$this->auditLogger,
|
|
$this->filterResolver,
|
|
);
|
|
});
|
|
|
|
it('uses the contract assignment payload key for assign actions', function () {
|
|
$tenant = Tenant::factory()->make([
|
|
'tenant_id' => 'tenant-123',
|
|
'app_client_id' => null,
|
|
'app_client_secret' => null,
|
|
]);
|
|
$policyId = 'policy-123';
|
|
$assignments = [
|
|
[
|
|
'id' => 'assignment-1',
|
|
'target' => [
|
|
'@odata.type' => '#microsoft.graph.groupAssignmentTarget',
|
|
'groupId' => 'group-1',
|
|
],
|
|
],
|
|
];
|
|
$expectedAssignments = [
|
|
[
|
|
'target' => [
|
|
'@odata.type' => '#microsoft.graph.groupAssignmentTarget',
|
|
'groupId' => 'group-1',
|
|
],
|
|
],
|
|
];
|
|
|
|
$this->graphClient
|
|
->shouldReceive('request')
|
|
->once()
|
|
->with('POST', "/deviceManagement/deviceManagementScripts/{$policyId}/assign", Mockery::on(
|
|
fn (array $options) => ($options['json']['deviceManagementScriptAssignments'] ?? null) === $expectedAssignments
|
|
))
|
|
->andReturn(new GraphResponse(success: true, data: []));
|
|
|
|
$this->auditLogger
|
|
->shouldReceive('log')
|
|
->once()
|
|
->andReturn(new AuditLog);
|
|
|
|
$result = $this->service->restore(
|
|
$tenant,
|
|
'deviceManagementScript',
|
|
$policyId,
|
|
$assignments,
|
|
[]
|
|
);
|
|
|
|
expect($result['summary']['success'])->toBe(1);
|
|
expect($result['summary']['failed'])->toBe(0);
|
|
expect($result['summary']['skipped'])->toBe(0);
|
|
});
|
|
|
|
it('uses derived assign endpoints for app protection policies', function () {
|
|
$tenant = Tenant::factory()->make([
|
|
'tenant_id' => 'tenant-123',
|
|
'app_client_id' => null,
|
|
'app_client_secret' => null,
|
|
]);
|
|
$policyId = 'policy-123';
|
|
$assignments = [
|
|
[
|
|
'id' => 'assignment-1',
|
|
'target' => [
|
|
'@odata.type' => '#microsoft.graph.groupAssignmentTarget',
|
|
'groupId' => 'group-1',
|
|
],
|
|
],
|
|
];
|
|
|
|
$this->graphClient
|
|
->shouldReceive('request')
|
|
->once()
|
|
->with('POST', "/deviceAppManagement/androidManagedAppProtections/{$policyId}/assign", Mockery::on(
|
|
fn (array $options) => isset($options['json']['assignments'])
|
|
))
|
|
->andReturn(new GraphResponse(success: true, data: []));
|
|
|
|
$this->auditLogger
|
|
->shouldReceive('log')
|
|
->once()
|
|
->andReturn(new AuditLog);
|
|
|
|
$result = $this->service->restore(
|
|
$tenant,
|
|
'appProtectionPolicy',
|
|
$policyId,
|
|
$assignments,
|
|
[],
|
|
[],
|
|
null,
|
|
null,
|
|
null,
|
|
'#microsoft.graph.androidManagedAppProtection',
|
|
);
|
|
|
|
expect($result['summary']['success'])->toBe(1);
|
|
expect($result['summary']['failed'])->toBe(0);
|
|
expect($result['summary']['skipped'])->toBe(0);
|
|
});
|
|
|
|
it('maps assignment filter ids stored at the root of assignments', function () {
|
|
$tenant = Tenant::factory()->make([
|
|
'tenant_id' => 'tenant-123',
|
|
'app_client_id' => null,
|
|
'app_client_secret' => null,
|
|
]);
|
|
$policyId = 'policy-789';
|
|
$assignments = [
|
|
[
|
|
'id' => 'assignment-1',
|
|
'deviceAndAppManagementAssignmentFilterId' => 'filter-source',
|
|
'deviceAndAppManagementAssignmentFilterType' => 'include',
|
|
'target' => [
|
|
'@odata.type' => '#microsoft.graph.groupAssignmentTarget',
|
|
'groupId' => 'group-1',
|
|
],
|
|
],
|
|
];
|
|
$expectedAssignments = [
|
|
[
|
|
'deviceAndAppManagementAssignmentFilterId' => 'filter-target',
|
|
'deviceAndAppManagementAssignmentFilterType' => 'include',
|
|
'target' => [
|
|
'@odata.type' => '#microsoft.graph.groupAssignmentTarget',
|
|
'groupId' => 'group-1',
|
|
],
|
|
],
|
|
];
|
|
|
|
$this->graphClient
|
|
->shouldReceive('request')
|
|
->once()
|
|
->with('POST', "/deviceManagement/configurationPolicies/{$policyId}/assign", Mockery::on(
|
|
fn (array $options) => ($options['json']['assignments'] ?? null) === $expectedAssignments
|
|
))
|
|
->andReturn(new GraphResponse(success: true, data: []));
|
|
|
|
$this->auditLogger
|
|
->shouldReceive('log')
|
|
->once()
|
|
->andReturn(new AuditLog);
|
|
|
|
$result = $this->service->restore(
|
|
$tenant,
|
|
'settingsCatalogPolicy',
|
|
$policyId,
|
|
$assignments,
|
|
[],
|
|
[
|
|
'assignmentFilter' => [
|
|
'filter-source' => 'filter-target',
|
|
],
|
|
]
|
|
);
|
|
|
|
expect($result['summary']['success'])->toBe(1);
|
|
expect($result['summary']['failed'])->toBe(0);
|
|
expect($result['summary']['skipped'])->toBe(0);
|
|
});
|
|
|
|
it('keeps assignment filters when mapping is missing but filter exists in target', function () {
|
|
$tenant = Tenant::factory()->make([
|
|
'tenant_id' => 'tenant-123',
|
|
'app_client_id' => null,
|
|
'app_client_secret' => null,
|
|
]);
|
|
$policyId = 'policy-999';
|
|
$assignments = [
|
|
[
|
|
'id' => 'assignment-1',
|
|
'deviceAndAppManagementAssignmentFilterId' => 'filter-1',
|
|
'deviceAndAppManagementAssignmentFilterType' => 'include',
|
|
'target' => [
|
|
'@odata.type' => '#microsoft.graph.groupAssignmentTarget',
|
|
'groupId' => 'group-1',
|
|
],
|
|
],
|
|
];
|
|
|
|
$this->filterResolver
|
|
->shouldReceive('resolve')
|
|
->once()
|
|
->with(['filter-1'], $tenant)
|
|
->andReturn([['id' => 'filter-1', 'displayName' => 'Test']]);
|
|
|
|
$this->graphClient
|
|
->shouldReceive('request')
|
|
->once()
|
|
->with('POST', "/deviceManagement/configurationPolicies/{$policyId}/assign", Mockery::on(
|
|
fn (array $options) => ($options['json']['assignments'][0]['deviceAndAppManagementAssignmentFilterId'] ?? null) === 'filter-1'
|
|
))
|
|
->andReturn(new GraphResponse(success: true, data: []));
|
|
|
|
$this->auditLogger
|
|
->shouldReceive('log')
|
|
->once()
|
|
->andReturn(new AuditLog);
|
|
|
|
$result = $this->service->restore(
|
|
$tenant,
|
|
'settingsCatalogPolicy',
|
|
$policyId,
|
|
$assignments,
|
|
[],
|
|
[]
|
|
);
|
|
|
|
expect($result['summary']['success'])->toBe(1);
|
|
expect($result['summary']['failed'])->toBe(0);
|
|
expect($result['summary']['skipped'])->toBe(0);
|
|
});
|