TenantAtlas/tests/Feature/EntraAdminRoles/AdminRolesReportViewerTest.php
Ahmed Darrazi 6b381e9517 feat: spec 105 — Entra Admin Roles scan, reports, findings, widget + summary UX improvement
- Entra admin roles scan job (ScanEntraAdminRolesJob)
- Report service with fingerprint deduplication
- Finding generator with high-privilege role catalog
- Admin roles summary widget on tenant view page
- Alert integration for entra.admin_roles findings
- Graph contracts for roleDefinitions + roleAssignments
- Entra permissions registry (config/entra_permissions.php)
- StoredReport fingerprint migration
- OperationCatalog label + duration for entra.admin_roles.scan
- SummaryCountsNormalizer: filter zeros, humanize keys globally
- 11 new test files (71+ tests, 286+ assertions)
- Spec + tasks + checklist updates
2026-02-22 03:35:46 +01:00

141 lines
5.1 KiB
PHP

<?php
declare(strict_types=1);
use App\Models\StoredReport;
use App\Models\Tenant;
use Illuminate\Foundation\Testing\RefreshDatabase;
uses(RefreshDatabase::class);
// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------
function createEntraReport(Tenant $tenant, array $summaryOverrides = [], ?string $fingerprint = null): StoredReport
{
$totals = array_merge([
'roles_total' => 8,
'assignments_total' => 12,
'high_privilege_assignments' => 5,
], $summaryOverrides);
return StoredReport::query()->create([
'workspace_id' => (int) $tenant->workspace_id,
'tenant_id' => (int) $tenant->getKey(),
'report_type' => StoredReport::REPORT_TYPE_ENTRA_ADMIN_ROLES,
'fingerprint' => $fingerprint ?? hash('sha256', (string) now()->timestamp.random_int(0, 99999)),
'payload' => [
'provider_key' => 'microsoft',
'domain' => 'entra.admin_roles',
'measured_at' => now()->toIso8601String(),
'role_definitions' => [],
'role_assignments' => [],
'totals' => $totals,
'high_privilege' => [
[
'role_display_name' => 'Global Administrator',
'role_template_id' => '62e90394-69f5-4237-9190-012177145e10',
'principal_id' => 'user-ga-1',
'principal_display_name' => 'Admin User',
'assignment_scope' => '/',
'severity' => 'critical',
],
],
],
]);
}
// ---------------------------------------------------------------------------
// StoredReport query by report type
// ---------------------------------------------------------------------------
it('returns stored reports with report_type entra.admin_roles', function (): void {
[$user, $tenant] = createUserWithTenant(role: 'owner');
$report = createEntraReport($tenant);
// Also create a report of a different type to ensure filtering works
StoredReport::query()->create([
'workspace_id' => (int) $tenant->workspace_id,
'tenant_id' => (int) $tenant->getKey(),
'report_type' => 'permission_posture',
'fingerprint' => hash('sha256', 'other-report'),
'payload' => ['summary' => ['score' => 85]],
]);
$results = StoredReport::query()
->where('tenant_id', (int) $tenant->getKey())
->where('report_type', StoredReport::REPORT_TYPE_ENTRA_ADMIN_ROLES)
->get();
expect($results)
->toHaveCount(1)
->and((int) $results->first()->getKey())->toBe((int) $report->getKey());
});
// ---------------------------------------------------------------------------
// Report payload contains summary and high-privilege assignments table
// ---------------------------------------------------------------------------
it('report payload contains summary totals and high-privilege assignments', function (): void {
[$user, $tenant] = createUserWithTenant(role: 'owner');
$report = createEntraReport($tenant, [
'roles_total' => 10,
'assignments_total' => 20,
'high_privilege_assignments' => 8,
]);
$report->refresh();
$payload = $report->payload;
expect($payload)
->toBeArray()
->toHaveKey('totals')
->toHaveKey('high_privilege');
$totals = $payload['totals'];
expect($totals)
->toHaveKey('roles_total', 10)
->toHaveKey('assignments_total', 20)
->toHaveKey('high_privilege_assignments', 8);
$assignments = $payload['high_privilege'];
expect($assignments)
->toBeArray()
->toHaveCount(1);
expect($assignments[0])
->toHaveKey('role_display_name', 'Global Administrator')
->toHaveKey('severity', 'critical')
->toHaveKey('principal_display_name', 'Admin User');
});
// ---------------------------------------------------------------------------
// Multiple reports ordered by creation date descending
// ---------------------------------------------------------------------------
it('orders multiple reports by creation date descending', function (): void {
[$user, $tenant] = createUserWithTenant(role: 'owner');
$older = createEntraReport($tenant, ['high_privilege_assignments' => 3], 'fp-older');
$older->forceFill(['created_at' => now()->subHours(2)])->save();
$newer = createEntraReport($tenant, ['high_privilege_assignments' => 7], 'fp-newer');
$newer->forceFill(['created_at' => now()->subHour()])->save();
$latest = createEntraReport($tenant, ['high_privilege_assignments' => 1], 'fp-latest');
$results = StoredReport::query()
->where('tenant_id', (int) $tenant->getKey())
->where('report_type', StoredReport::REPORT_TYPE_ENTRA_ADMIN_ROLES)
->orderByDesc('created_at')
->get();
expect($results)->toHaveCount(3);
expect((int) $results[0]->getKey())->toBe((int) $latest->getKey());
expect((int) $results[1]->getKey())->toBe((int) $newer->getKey());
expect((int) $results[2]->getKey())->toBe((int) $older->getKey());
});