TenantAtlas/apps/platform/tests/Feature/Guards/ProviderDispatchGateCoverageTest.php
Ahmed Darrazi 34230be79d
Some checks failed
PR Fast Feedback / fast-feedback (pull_request) Failing after 4m21s
feat: unify provider-backed action dispatch gating
2026-04-20 08:47:08 +02:00

158 lines
6.3 KiB
PHP

<?php
declare(strict_types=1);
use Tests\Support\OpsUx\SourceFileScanner;
function providerDispatchGateSlice(string $source, string $startAnchor, ?string $endAnchor = null): string
{
$start = strpos($source, $startAnchor);
expect($start)->not->toBeFalse();
$start = is_int($start) ? $start : 0;
if ($endAnchor === null) {
return substr($source, $start);
}
$end = strpos($source, $endAnchor, $start + strlen($startAnchor));
expect($end)->not->toBeFalse();
$end = is_int($end) ? $end : strlen($source);
return substr($source, $start, $end - $start);
}
it('keeps first-slice route-bounded provider starts on canonical gate-owned entry points', function (): void {
$root = SourceFileScanner::projectRoot();
$checks = [
[
'file' => $root.'/app/Services/Verification/StartVerification.php',
'start' => 'public function providerConnectionCheckForTenant(',
'end' => 'public function providerConnectionCheckUsingConnection(',
'required' => [
'return $this->providers->start(',
"operationType: 'provider.connection.check'",
"'required_capability' => Capabilities::PROVIDER_RUN",
],
'forbidden' => ['ensureRun(', 'dispatchOrFail('],
],
[
'file' => $root.'/app/Services/Verification/StartVerification.php',
'start' => 'public function providerConnectionCheckUsingConnection(',
'end' => 'private function dispatchConnectionHealthCheck(',
'required' => [
'$result = $this->providers->start(',
"operationType: 'provider.connection.check'",
'ProviderVerificationStatus::Pending',
],
'forbidden' => ['ensureRun(', 'dispatchOrFail('],
],
[
'file' => $root.'/app/Services/Directory/EntraGroupSyncService.php',
'start' => 'public function startManualSync(',
'end' => 'public function sync(',
'required' => [
'return $this->providerStarts->start(',
"operationType: 'entra_group_sync'",
'EntraGroupSyncJob::dispatch(',
'->afterCommit()',
],
'forbidden' => ['ensureRun(', 'dispatchOrFail('],
],
[
'file' => $root.'/app/Services/Directory/RoleDefinitionsSyncService.php',
'start' => 'public function startManualSync(',
'end' => 'public function sync(',
'required' => [
'return $this->providerStarts->start(',
"operationType: 'directory_role_definitions.sync'",
'SyncRoleDefinitionsJob::dispatch(',
'->afterCommit()',
],
'forbidden' => ['ensureRun(', 'dispatchOrFail('],
],
[
'file' => $root.'/app/Filament/Resources/RestoreRunResource.php',
'start' => 'private static function startQueuedRestoreExecution(',
'end' => 'private static function detailPreviewState(',
'required' => [
'app(ProviderOperationStartGate::class)->start(',
"operationType: 'restore.execute'",
'ExecuteRestoreRunJob::dispatch(',
'->afterCommit()',
],
'forbidden' => ['ensureRun(', 'dispatchOrFail('],
],
[
'file' => $root.'/app/Filament/Resources/EntraGroupResource/Pages/ListEntraGroups.php',
'start' => "Action::make('sync_groups')",
'end' => '->requireCapability(Capabilities::TENANT_SYNC)',
'required' => [
'$syncService->startManualSync($tenant, $user)',
'ProviderOperationStartResultPresenter::class',
],
'forbidden' => ['ensureRun(', 'dispatchOrFail('],
],
[
'file' => $root.'/app/Filament/Resources/TenantResource.php',
'start' => 'public static function syncRoleDefinitionsAction(): Actions\\Action',
'end' => null,
'required' => [
'$result = $syncService->startManualSync($record, $user);',
'ProviderOperationStartResultPresenter::class',
],
'forbidden' => ['ensureRun(', 'dispatchOrFail('],
],
[
'file' => $root.'/app/Filament/Resources/ProviderConnectionResource.php',
'start' => 'private static function handleCheckConnectionAction(',
'end' => 'private static function handleProviderOperationAction(',
'required' => [
'$verification->providerConnectionCheck(',
'ProviderOperationStartResultPresenter::class',
'OperationRunLinks::view($result->run, $tenant)',
],
'forbidden' => ['ensureRun(', 'dispatchOrFail('],
],
[
'file' => $root.'/app/Filament/Resources/ProviderConnectionResource.php',
'start' => 'private static function handleProviderOperationAction(',
'end' => 'public static function getEloquentQuery(): Builder',
'required' => [
'$result = $gate->start(',
'ProviderOperationStartResultPresenter::class',
'OperationRunLinks::view($result->run, $tenant)',
],
'forbidden' => ['ensureRun(', 'dispatchOrFail('],
],
[
'file' => $root.'/app/Filament/Pages/Workspaces/ManagedTenantOnboardingWizard.php',
'start' => 'public function startBootstrap(array $operationTypes): void',
'end' => 'private function dispatchBootstrapJob(',
'required' => [
'app(ProviderOperationStartGate::class)->start(',
'ProviderOperationStartResultPresenter::class',
"'bootstrap_operation_types'",
],
'forbidden' => ['ensureRun(', 'dispatchOrFail('],
],
];
foreach ($checks as $check) {
$source = SourceFileScanner::read($check['file']);
$slice = providerDispatchGateSlice($source, $check['start'], $check['end']);
foreach ($check['required'] as $needle) {
expect($slice)->toContain($needle);
}
foreach ($check['forbidden'] as $needle) {
expect($slice)->not->toContain($needle);
}
}
})->group('surface-guard');