Implemented the first version of provider readiness resolution guidance. Added the ProviderReadinessResolutionAdapter, provider readiness guidance card, and updated EnvironmentRequiredPermissions, ProviderConnectionResource, and ListProviderConnections/ViewProviderConnection. Added tests and updated the design coverage matrix. Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #424
182 lines
8.3 KiB
PHP
182 lines
8.3 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Models\OperationRun;
|
|
use App\Models\ProviderConnection;
|
|
use App\Services\Intune\ManagedEnvironmentRequiredPermissionsViewModelBuilder;
|
|
use App\Support\ManagedEnvironmentLinks;
|
|
use App\Support\OperationRunLinks;
|
|
use App\Support\Providers\ProviderConsentStatus;
|
|
use App\Support\Providers\ProviderVerificationStatus;
|
|
use App\Support\ResolutionGuidance\Adapters\ProviderReadinessResolutionAdapter;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
|
|
use function Pest\Laravel\mock;
|
|
|
|
uses(RefreshDatabase::class);
|
|
|
|
beforeEach(function (): void {
|
|
config()->set('graph.client_id', 'spec353-platform-client');
|
|
config()->set('graph.client_secret', 'spec353-platform-secret');
|
|
config()->set('graph.managed_environment_id', 'organizations');
|
|
});
|
|
|
|
function mockSpec353PermissionOverview(array $overview = []): void
|
|
{
|
|
mock(ManagedEnvironmentRequiredPermissionsViewModelBuilder::class, function ($mock) use ($overview): void {
|
|
$mock->shouldReceive('build')->andReturn([
|
|
'overview' => array_replace_recursive([
|
|
'counts' => [
|
|
'missing_application' => 0,
|
|
'missing_delegated' => 0,
|
|
'present' => 12,
|
|
'error' => 0,
|
|
],
|
|
'freshness' => [
|
|
'last_refreshed_at' => now()->toIso8601String(),
|
|
'is_stale' => false,
|
|
],
|
|
], $overview),
|
|
]);
|
|
});
|
|
}
|
|
|
|
it('returns connection-missing guidance when no default provider connection exists', function (): void {
|
|
[, $environment] = createUserWithTenant(role: 'owner', workspaceRole: 'owner', ensureDefaultMicrosoftProviderConnection: false);
|
|
|
|
mockSpec353PermissionOverview();
|
|
|
|
$case = app(ProviderReadinessResolutionAdapter::class)
|
|
->forEnvironment($environment, ProviderReadinessResolutionAdapter::SURFACE_PROVIDER_CONNECTIONS_INDEX);
|
|
|
|
expect($case['key'])->toBe('provider_readiness.connection_missing')
|
|
->and(data_get($case, 'primary_action.url'))->toBe(ManagedEnvironmentLinks::providerConnectionsUrl($environment))
|
|
->and((string) data_get($case, 'status'))->toBe(__('localization.provider_guidance.status_blocked'));
|
|
});
|
|
|
|
it('distinguishes admin-consent blockers from missing-permission blockers', function (): void {
|
|
[, $environment] = createUserWithTenant(role: 'owner', workspaceRole: 'owner', ensureDefaultMicrosoftProviderConnection: false);
|
|
|
|
$connection = ProviderConnection::factory()->platform()->create([
|
|
'managed_environment_id' => (int) $environment->getKey(),
|
|
'workspace_id' => (int) $environment->workspace_id,
|
|
'is_default' => true,
|
|
'consent_status' => ProviderConsentStatus::Required->value,
|
|
'verification_status' => ProviderVerificationStatus::Unknown->value,
|
|
]);
|
|
|
|
mockSpec353PermissionOverview([
|
|
'counts' => [
|
|
'missing_application' => 3,
|
|
],
|
|
]);
|
|
|
|
$case = app(ProviderReadinessResolutionAdapter::class)
|
|
->forConnection($environment, $connection, ProviderReadinessResolutionAdapter::SURFACE_PROVIDER_CONNECTIONS_VIEW);
|
|
|
|
expect($case['key'])->toBe('provider_readiness.admin_consent_required')
|
|
->and((string) data_get($case, 'primary_action.label'))->toBe(__('localization.provider_guidance.action_open_admin_consent'))
|
|
->and((string) data_get($case, 'reason'))->toBe(__('localization.provider_guidance.admin_consent_required_reason'));
|
|
});
|
|
|
|
it('returns required-permissions guidance when application permissions are missing', function (): void {
|
|
[, $environment] = createUserWithTenant(role: 'owner', workspaceRole: 'owner', ensureDefaultMicrosoftProviderConnection: false);
|
|
|
|
$connection = ProviderConnection::factory()->platform()->consentGranted()->verifiedHealthy()->create([
|
|
'managed_environment_id' => (int) $environment->getKey(),
|
|
'workspace_id' => (int) $environment->workspace_id,
|
|
'is_default' => true,
|
|
]);
|
|
|
|
mockSpec353PermissionOverview([
|
|
'counts' => [
|
|
'missing_application' => 2,
|
|
'present' => 10,
|
|
],
|
|
]);
|
|
|
|
$case = app(ProviderReadinessResolutionAdapter::class)
|
|
->forConnection($environment, $connection, ProviderReadinessResolutionAdapter::SURFACE_PROVIDER_CONNECTIONS_VIEW);
|
|
|
|
expect($case['key'])->toBe('provider_readiness.required_permissions_missing')
|
|
->and((string) data_get($case, 'primary_action.label'))->toBe(__('localization.provider_guidance.action_open_required_permissions'))
|
|
->and((string) data_get($case, 'reason'))->toBe(__('localization.provider_guidance.required_application_permissions_reason'));
|
|
});
|
|
|
|
it('returns verification-required guidance when verification has not run yet', function (): void {
|
|
[, $environment] = createUserWithTenant(role: 'owner', workspaceRole: 'owner', ensureDefaultMicrosoftProviderConnection: false);
|
|
|
|
$connection = ProviderConnection::factory()->platform()->consentGranted()->create([
|
|
'managed_environment_id' => (int) $environment->getKey(),
|
|
'workspace_id' => (int) $environment->workspace_id,
|
|
'is_default' => true,
|
|
'verification_status' => ProviderVerificationStatus::Unknown->value,
|
|
'last_health_check_at' => null,
|
|
]);
|
|
|
|
mockSpec353PermissionOverview([
|
|
'freshness' => [
|
|
'last_refreshed_at' => null,
|
|
'is_stale' => true,
|
|
],
|
|
]);
|
|
|
|
$case = app(ProviderReadinessResolutionAdapter::class)
|
|
->forConnection($environment, $connection, ProviderReadinessResolutionAdapter::SURFACE_REQUIRED_PERMISSIONS);
|
|
|
|
expect($case['key'])->toBe('provider_readiness.verification_required')
|
|
->and((string) data_get($case, 'primary_action.action_name'))->toBe('runProviderVerification')
|
|
->and((string) data_get($case, 'primary_action.label'))->toBe(__('localization.provider_guidance.action_run_provider_verification'));
|
|
});
|
|
|
|
it('returns verification-failed guidance with an operation link when a failed run exists', function (): void {
|
|
[, $environment] = createUserWithTenant(role: 'owner', workspaceRole: 'owner', ensureDefaultMicrosoftProviderConnection: false);
|
|
|
|
$connection = ProviderConnection::factory()->platform()->consentGranted()->create([
|
|
'managed_environment_id' => (int) $environment->getKey(),
|
|
'workspace_id' => (int) $environment->workspace_id,
|
|
'is_default' => true,
|
|
'verification_status' => ProviderVerificationStatus::Error->value,
|
|
'last_error_message' => 'Graph verification failed for this connection.',
|
|
]);
|
|
|
|
$run = OperationRun::factory()->create([
|
|
'workspace_id' => (int) $environment->workspace_id,
|
|
'managed_environment_id' => (int) $environment->getKey(),
|
|
'type' => 'provider.connection.check',
|
|
'context' => [
|
|
'provider_connection_id' => (int) $connection->getKey(),
|
|
],
|
|
]);
|
|
|
|
mockSpec353PermissionOverview();
|
|
|
|
$case = app(ProviderReadinessResolutionAdapter::class)
|
|
->forConnection($environment, $connection, ProviderReadinessResolutionAdapter::SURFACE_PROVIDER_CONNECTIONS_VIEW);
|
|
|
|
expect($case['key'])->toBe('provider_readiness.verification_failed')
|
|
->and((string) data_get($case, 'primary_action.url'))->toBe(OperationRunLinks::view($run, $environment))
|
|
->and((string) data_get($case, 'reason'))->toContain('Graph verification failed');
|
|
});
|
|
|
|
it('returns a ready case when provider signals are satisfied', function (): void {
|
|
[, $environment] = createUserWithTenant(role: 'owner', workspaceRole: 'owner', ensureDefaultMicrosoftProviderConnection: false);
|
|
|
|
$connection = ProviderConnection::factory()->platform()->verifiedHealthy()->create([
|
|
'managed_environment_id' => (int) $environment->getKey(),
|
|
'workspace_id' => (int) $environment->workspace_id,
|
|
'is_default' => true,
|
|
'last_health_check_at' => now(),
|
|
]);
|
|
|
|
mockSpec353PermissionOverview();
|
|
|
|
$case = app(ProviderReadinessResolutionAdapter::class)
|
|
->forConnection($environment, $connection, ProviderReadinessResolutionAdapter::SURFACE_PROVIDER_CONNECTIONS_VIEW);
|
|
|
|
expect($case['key'])->toBe('provider_readiness.ready')
|
|
->and((string) data_get($case, 'primary_action.url'))->toBe(ManagedEnvironmentLinks::viewUrl($environment))
|
|
->and((string) data_get($case, 'status'))->toBe(__('localization.provider_guidance.status_ready'));
|
|
});
|