TenantAtlas/apps/platform/tests/Feature/Guards/OperationRunLinkContractGuardTest.php
ahmido 3ec582a182 feat: retire legacy tenant route surfaces (#352)
## Summary
- retire legacy `/admin/t` and active `/admin/tenants` product surfaces in favor of canonical workspace-scoped managed-environment routes
- centralize runtime URL generation through `ManagedEnvironmentLinks` and update intended URL handling to reject legacy tenant paths
- remove dormant tenant panel runtime, rename test helpers to the admin environment context, and add guard coverage for route/helper regressions

## Validation
- targeted Feature guard, workspace, provider connection, required permissions, and Filament test lanes run under Sail
- browser smoke coverage run for provider connection and workspace RBAC environment access flows
- formatting and diff checks completed with Pint and `git diff --check`

## Notes
- Filament remains on v5 with Livewire v4
- provider registration stays in `apps/platform/bootstrap/providers.php`
- retired tenant resource global search is disabled and destructive action confirmation rules remain unchanged

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #352
2026-05-12 23:35:03 +00:00

154 lines
6.0 KiB
PHP

<?php
declare(strict_types=1);
use Tests\Support\OpsUx\SourceFileScanner;
use App\Support\OperationRunLinks;
/**
* @return array<string, string>
*/
function operationRunLinkContractIncludePaths(): array
{
$root = SourceFileScanner::projectRoot();
return [
'tenant_recent_operations_summary' => $root.'/app/Filament/Widgets/Tenant/RecentOperationsSummary.php',
'inventory_coverage' => $root.'/app/Filament/Pages/InventoryCoverage.php',
'inventory_item_resource' => $root.'/app/Filament/Resources/InventoryItemResource.php',
'review_pack_resource' => $root.'/app/Filament/Resources/ReviewPackResource.php',
'tenantless_operation_run_viewer' => $root.'/app/Filament/Pages/Operations/TenantlessOperationRunViewer.php',
'related_navigation_resolver' => $root.'/app/Support/Navigation/RelatedNavigationResolver.php',
'system_directory_tenant' => $root.'/app/Filament/System/Pages/Directory/ViewTenant.php',
'system_directory_workspace' => $root.'/app/Filament/System/Pages/Directory/ViewWorkspace.php',
'system_ops_runs' => $root.'/app/Filament/System/Pages/Ops/Runs.php',
'system_ops_view_run' => $root.'/app/Filament/System/Pages/Ops/ViewRun.php',
'admin_panel_provider' => $root.'/app/Providers/Filament/AdminPanelProvider.php',
'ensure_filament_tenant_selected' => $root.'/app/Support/Middleware/EnsureFilamentTenantSelected.php',
'clear_tenant_context_controller' => $root.'/app/Http/Controllers/ClearTenantContextController.php',
'operation_run_url_delegate' => $root.'/app/Support/OpsUx/OperationRunUrl.php',
];
}
/**
* @return array<string, string>
*/
function operationRunLinkContractAllowlist(): array
{
return [];
}
/**
* @param array<string, string> $paths
* @param array<string, string> $allowlist
* @return list<array{file: string, line: int, snippet: string, expectedHelper: string, reason: string}>
*/
function operationRunLinkContractViolations(array $paths, array $allowlist = []): array
{
$patterns = [
[
'pattern' => '/route\(\s*[\'"]admin\.operations\.index[\'"]/',
'expectedHelper' => 'OperationRunLinks::index(...)',
'reason' => 'Raw admin operations collection route assembly bypasses the canonical admin link helper.',
],
[
'pattern' => '/route\(\s*[\'"]admin\.operations\.view[\'"]/',
'expectedHelper' => 'OperationRunLinks::view(...) or OperationRunLinks::tenantlessView(...)',
'reason' => 'Raw admin operation detail route assembly bypasses the canonical admin link helper.',
],
[
'pattern' => '/[\'"]\/system\/ops\/runs(?:\/[^\'"]*)?[\'"]/',
'expectedHelper' => 'SystemOperationRunLinks::index() or SystemOperationRunLinks::view(...)',
'reason' => 'Direct system operations path assembly bypasses the canonical system link helper.',
],
[
'pattern' => '/\b(?:Runs|ViewRun)::getUrl\(/',
'expectedHelper' => 'SystemOperationRunLinks::index() or SystemOperationRunLinks::view(...)',
'reason' => 'Direct system operations page URL generation belongs behind the canonical system link helper.',
],
];
$violations = [];
foreach ($paths as $path) {
if (array_key_exists($path, $allowlist)) {
continue;
}
$source = SourceFileScanner::read($path);
$lines = preg_split('/\R/', $source) ?: [];
foreach ($lines as $index => $line) {
foreach ($patterns as $pattern) {
if (preg_match($pattern['pattern'], $line) !== 1) {
continue;
}
$violations[] = [
'file' => SourceFileScanner::relativePath($path),
'line' => $index + 1,
'snippet' => SourceFileScanner::snippet($source, $index + 1),
'expectedHelper' => $pattern['expectedHelper'],
'reason' => $pattern['reason'],
];
}
}
}
return $violations;
}
it('keeps covered operation run link producers on canonical helper families', function (): void {
$paths = operationRunLinkContractIncludePaths();
$allowlist = operationRunLinkContractAllowlist();
$violations = operationRunLinkContractViolations($paths, $allowlist);
expect($violations)->toBeEmpty();
})->group('surface-guard');
it('keeps the operation run link exception boundary explicit and infrastructure-owned', function (): void {
$allowlist = operationRunLinkContractAllowlist();
expect($allowlist)->toBeEmpty();
})->group('surface-guard');
it('reports actionable file and snippet output for a representative raw bypass', function (): void {
$probePath = storage_path('framework/testing/OperationRunLinkContractProbe.php');
if (! is_dir(dirname($probePath))) {
mkdir(dirname($probePath), 0777, true);
}
file_put_contents($probePath, <<<'PHP'
<?php
return route('admin.operations.view', ['run' => 123]);
PHP);
try {
$violations = operationRunLinkContractViolations([
'probe' => $probePath,
]);
} finally {
@unlink($probePath);
}
expect($violations)->toHaveCount(1)
->and($violations[0]['file'])->toContain('OperationRunLinkContractProbe.php')
->and($violations[0]['line'])->toBe(3)
->and($violations[0]['snippet'])->toContain("route('admin.operations.view'")
->and($violations[0]['expectedHelper'])->toContain('OperationRunLinks::view')
->and($violations[0]['reason'])->toContain('bypasses the canonical admin link helper');
})->group('surface-guard');
it('canonicalizes operation type query parameters for operation collection links', function (): void {
[$workspace] = localizationWorkspaceMember();
$url = OperationRunLinks::index(operationType: 'inventory_sync');
expect($url)->toContain('inventory.sync')
->toContain('/admin/workspaces/'.$workspace->getRouteKey().'/operations')
->not->toContain('inventory_sync');
})->group('surface-guard');