158 lines
6.5 KiB
PHP
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');
|
|
});
|