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
161 lines
5.3 KiB
PHP
161 lines
5.3 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
uses(Tests\TestCase::class);
|
|
|
|
use App\Services\Graph\GraphContractRegistry;
|
|
use App\Services\Graph\GraphLogger;
|
|
use App\Services\Graph\MicrosoftGraphClient;
|
|
use Illuminate\Http\Client\Request;
|
|
use Illuminate\Support\Facades\Http;
|
|
|
|
it('includes contract select fields when listing policies', function () {
|
|
Http::fake([
|
|
'graph.microsoft.com/*' => Http::response(['value' => []], 200),
|
|
]);
|
|
|
|
$logger = mock(GraphLogger::class);
|
|
$logger->shouldReceive('logRequest')->zeroOrMoreTimes()->andReturnNull();
|
|
$logger->shouldReceive('logResponse')->zeroOrMoreTimes()->andReturnNull();
|
|
|
|
$client = new MicrosoftGraphClient(
|
|
logger: $logger,
|
|
contracts: app(GraphContractRegistry::class),
|
|
);
|
|
|
|
$client->listPolicies('endpointSecurityPolicy', [
|
|
'access_token' => 'test-token',
|
|
]);
|
|
|
|
$client->listPolicies('securityBaselinePolicy', [
|
|
'access_token' => 'test-token',
|
|
]);
|
|
|
|
$client->listPolicies('settingsCatalogPolicy', [
|
|
'access_token' => 'test-token',
|
|
]);
|
|
|
|
Http::assertSent(function (Request $request) {
|
|
$url = $request->url();
|
|
|
|
if (! str_contains($url, '/deviceManagement/configurationPolicies')) {
|
|
return false;
|
|
}
|
|
|
|
parse_str((string) parse_url($url, PHP_URL_QUERY), $query);
|
|
|
|
expect($query)->toHaveKey('$select');
|
|
|
|
$select = (string) $query['$select'];
|
|
|
|
expect($select)->toContain('technologies')
|
|
->and($select)->toContain('templateReference')
|
|
->and($select)->toContain('name')
|
|
->and($select)->not->toContain('@odata.type');
|
|
|
|
expect($select)->not->toContain('displayName');
|
|
expect($select)->not->toContain('version');
|
|
|
|
return true;
|
|
});
|
|
});
|
|
|
|
it('retries list policies without $select on select/expand parsing errors', function () {
|
|
Http::fake([
|
|
'graph.microsoft.com/*' => Http::sequence()
|
|
->push([
|
|
'error' => [
|
|
'code' => 'BadRequest',
|
|
'message' => "Parsing OData Select and Expand failed: Could not find a property named 'version' on type 'microsoft.graph.deviceManagementConfigurationPolicy'.",
|
|
],
|
|
], 400)
|
|
->push([
|
|
'error' => [
|
|
'code' => 'BadRequest',
|
|
'message' => "Parsing OData Select and Expand failed: Could not find a property named 'version' on type 'microsoft.graph.deviceManagementConfigurationPolicy'.",
|
|
],
|
|
], 400)
|
|
->push(['value' => [['id' => 'policy-1', 'name' => 'Policy One']]], 200),
|
|
]);
|
|
|
|
$logger = mock(GraphLogger::class);
|
|
$logger->shouldReceive('logRequest')->zeroOrMoreTimes()->andReturnNull();
|
|
$logger->shouldReceive('logResponse')->zeroOrMoreTimes()->andReturnNull();
|
|
|
|
$client = new MicrosoftGraphClient(
|
|
logger: $logger,
|
|
contracts: app(GraphContractRegistry::class),
|
|
);
|
|
|
|
$response = $client->listPolicies('settingsCatalogPolicy', [
|
|
'access_token' => 'test-token',
|
|
]);
|
|
|
|
expect($response->successful())->toBeTrue();
|
|
expect($response->data)->toHaveCount(1);
|
|
expect($response->warnings)->toContain('Capability fallback applied: removed $select for compatibility.');
|
|
|
|
$recorded = Http::recorded();
|
|
|
|
expect($recorded)->toHaveCount(3);
|
|
|
|
[$firstRequest] = $recorded[0];
|
|
[$secondRequest] = $recorded[1];
|
|
[$thirdRequest] = $recorded[2];
|
|
|
|
parse_str((string) parse_url($firstRequest->url(), PHP_URL_QUERY), $firstQuery);
|
|
parse_str((string) parse_url($secondRequest->url(), PHP_URL_QUERY), $secondQuery);
|
|
parse_str((string) parse_url($thirdRequest->url(), PHP_URL_QUERY), $thirdQuery);
|
|
|
|
expect($firstQuery)->toHaveKey('$select');
|
|
expect($secondQuery)->toHaveKey('$select');
|
|
expect($thirdQuery)->not->toHaveKey('$select');
|
|
});
|
|
|
|
it('paginates list policies when nextLink is present', function () {
|
|
$nextLink = 'https://graph.microsoft.com/beta/deviceManagement/configurationPolicies?$skiptoken=page2';
|
|
|
|
Http::fake([
|
|
'graph.microsoft.com/*' => Http::sequence()
|
|
->push([
|
|
'value' => [
|
|
['id' => 'policy-1', 'name' => 'Policy One'],
|
|
],
|
|
'@odata.nextLink' => $nextLink,
|
|
], 200)
|
|
->push([
|
|
'value' => [
|
|
['id' => 'policy-2', 'name' => 'Policy Two'],
|
|
],
|
|
], 200),
|
|
]);
|
|
|
|
$logger = mock(GraphLogger::class);
|
|
$logger->shouldReceive('logRequest')->zeroOrMoreTimes()->andReturnNull();
|
|
$logger->shouldReceive('logResponse')->zeroOrMoreTimes()->andReturnNull();
|
|
|
|
$client = new MicrosoftGraphClient(
|
|
logger: $logger,
|
|
contracts: app(GraphContractRegistry::class),
|
|
);
|
|
|
|
$response = $client->listPolicies('settingsCatalogPolicy', [
|
|
'access_token' => 'test-token',
|
|
]);
|
|
|
|
expect($response->successful())->toBeTrue();
|
|
expect($response->data)->toHaveCount(2);
|
|
expect(collect($response->data)->pluck('id')->all())->toMatchArray(['policy-1', 'policy-2']);
|
|
|
|
$recorded = Http::recorded();
|
|
|
|
expect($recorded)->toHaveCount(2);
|
|
|
|
[$firstRequest] = $recorded[0];
|
|
[$secondRequest] = $recorded[1];
|
|
|
|
expect($firstRequest->url())->toContain('/deviceManagement/configurationPolicies');
|
|
expect($secondRequest->url())->toBe($nextLink);
|
|
});
|