TenantAtlas/apps/platform/tests/Unit/Providers/Spec394ProviderReadinessResolverTest.php
Ahmed Darrazi 1245af12af
Some checks failed
PR Fast Feedback / fast-feedback (pull_request) Failing after 1m25s
feat: improve provider readiness semantics and freshness guidance
2026-06-21 19:18:00 +02:00

158 lines
6.5 KiB
PHP

<?php
declare(strict_types=1);
use App\Models\ManagedEnvironment;
use App\Models\ManagedEnvironmentPermission;
use App\Models\ProviderConnection;
use App\Services\Graph\GraphClientInterface;
use App\Services\Graph\GraphResponse;
use App\Services\Intune\ManagedEnvironmentPermissionService;
use App\Support\Providers\Readiness\ProviderReadinessResolver;
use App\Support\Providers\Readiness\ProviderReadinessState;
use Illuminate\Foundation\Testing\RefreshDatabase;
uses(RefreshDatabase::class);
function spec394ConfigureRequiredPermission(): void
{
config()->set('intune_permissions.permissions', [[
'key' => 'DeviceManagementApps.Read.All',
'type' => 'application',
'description' => 'Read Intune apps',
'features' => ['backup'],
]]);
config()->set('entra_permissions.permissions', []);
}
function spec394HealthyConnection(ManagedEnvironment $environment, array $attributes = []): ProviderConnection
{
return ProviderConnection::factory()
->platform()
->verifiedHealthy()
->create(array_replace([
'managed_environment_id' => (int) $environment->getKey(),
'workspace_id' => (int) $environment->workspace_id,
'provider' => 'microsoft',
'is_default' => true,
], $attributes));
}
function spec394PermissionEvidence(ManagedEnvironment $environment, ProviderConnection $connection, array $attributes = []): ManagedEnvironmentPermission
{
return ManagedEnvironmentPermission::query()->create(array_replace([
'managed_environment_id' => (int) $environment->getKey(),
'workspace_id' => (int) $environment->workspace_id,
'permission_key' => 'DeviceManagementApps.Read.All',
'status' => 'granted',
'details' => [
'source' => 'graph_api',
'provider_connection_id' => (int) $connection->getKey(),
'managed_environment_id' => (int) $environment->getKey(),
'workspace_id' => (int) $environment->workspace_id,
'provider' => 'microsoft',
],
'last_checked_at' => now(),
], $attributes));
}
it('marks a provider ready only when granted evidence matches the current provider connection', function (): void {
spec394ConfigureRequiredPermission();
[$user, $environment] = createUserWithTenant(role: 'owner');
$connection = spec394HealthyConnection($environment);
spec394PermissionEvidence($environment, $connection);
$result = app(ProviderReadinessResolver::class)->forConnection($connection, $user);
expect($result->state)->toBe(ProviderReadinessState::Ready)
->and($result->counts['granted'])->toBe(1)
->and($result->counts['required'])->toBe(1)
->and($result->permissionRows[0]['is_effective'])->toBeTrue();
});
it('does not treat legacy unscoped permission rows as granted readiness evidence', function (): void {
spec394ConfigureRequiredPermission();
[$user, $environment] = createUserWithTenant(role: 'owner');
$connection = spec394HealthyConnection($environment);
spec394PermissionEvidence($environment, $connection, [
'details' => ['source' => 'legacy-fixture'],
]);
$result = app(ProviderReadinessResolver::class)->forConnection($connection, $user);
expect($result->state)->toBe(ProviderReadinessState::Unknown)
->and($result->counts['granted'])->toBe(0)
->and($result->counts['unknown'])->toBe(1)
->and($result->permissionRows[0]['reason_code'])->toBe('provider_permission_evidence_scope_mismatch');
});
it('does not treat provider-connection-only permission rows as scoped readiness evidence', function (): void {
spec394ConfigureRequiredPermission();
[$user, $environment] = createUserWithTenant(role: 'owner');
$connection = spec394HealthyConnection($environment);
spec394PermissionEvidence($environment, $connection, [
'details' => [
'source' => 'partial-provider-evidence',
'provider_connection_id' => (int) $connection->getKey(),
],
]);
$result = app(ProviderReadinessResolver::class)->forConnection($connection, $user);
expect($result->state)->toBe(ProviderReadinessState::Unknown)
->and($result->counts['granted'])->toBe(0)
->and($result->counts['unknown'])->toBe(1)
->and($result->permissionRows[0]['reason_code'])->toBe('provider_permission_evidence_scope_mismatch');
});
it('expires matched grants when the provider verification is stale', function (): void {
spec394ConfigureRequiredPermission();
[$user, $environment] = createUserWithTenant(role: 'owner');
$connection = spec394HealthyConnection($environment, [
'last_health_check_at' => now()->subDays(31),
]);
spec394PermissionEvidence($environment, $connection);
$result = app(ProviderReadinessResolver::class)->forConnection($connection, $user);
expect($result->state)->toBe(ProviderReadinessState::Expired)
->and($result->counts['expired'])->toBe(1)
->and($result->counts['granted'])->toBe(0);
});
it('persists provider connection metadata when live permission checks refresh stored evidence', function (): void {
spec394ConfigureRequiredPermission();
[, $environment] = createUserWithTenant(role: 'owner');
$connection = spec394HealthyConnection($environment);
$graph = Mockery::mock(GraphClientInterface::class);
$graph->shouldReceive('getServicePrincipalPermissions')
->once()
->andReturn(new GraphResponse(true, data: [
'permissions' => ['DeviceManagementApps.Read.All'],
]));
app()->instance(GraphClientInterface::class, $graph);
app(ManagedEnvironmentPermissionService::class)->compare(
$environment,
persist: true,
liveCheck: true,
useConfiguredStub: false,
graphOptions: ['client_id' => 'app-client-id'],
providerConnection: $connection,
);
$stored = ManagedEnvironmentPermission::query()
->where('managed_environment_id', (int) $environment->getKey())
->where('permission_key', 'DeviceManagementApps.Read.All')
->first();
expect($stored)->not->toBeNull()
->and($stored->details['provider_connection_id'] ?? null)->toBe((int) $connection->getKey())
->and($stored->details['workspace_id'] ?? null)->toBe((int) $environment->workspace_id)
->and($stored->details['managed_environment_id'] ?? null)->toBe((int) $environment->getKey())
->and($stored->details['provider'] ?? null)->toBe('microsoft')
->and($stored->details['app_id'] ?? null)->toBe('app-client-id');
});