TenantAtlas/apps/platform/tests/Feature/Guards/OperationRunLinkContractGuardTest.php
ahmido 2bf53f6337
Some checks failed
Main Confidence / confidence (push) Failing after 44s
Enforce operation run link contract (#268)
## Summary
- enforce shared operation run link generation across admin and system surfaces
- add guard coverage to block new raw operation route bypasses outside explicit exceptions
- harden Filament theme asset resolution so stale or wrong-stack hot files fall back to built assets

## Testing
- export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent
- export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/OpsUx/CanonicalViewRunLinksTest.php tests/Feature/Monitoring/OperationsDashboardDrillthroughTest.php tests/Feature/Filament/RecentOperationsSummaryWidgetTest.php tests/Feature/Filament/InventoryCoverageRunContinuityTest.php tests/Feature/ReviewPack/ReviewPackResourceTest.php tests/Feature/144/CanonicalOperationViewerDeepLinkTrustTest.php tests/Feature/078/RelatedLinksOnDetailTest.php tests/Feature/RunAuthorizationTenantIsolationTest.php tests/Feature/System/Spec195/SystemDirectoryResidualSurfaceTest.php tests/Feature/System/Spec113/AuthorizationSemanticsTest.php tests/Feature/Guards/OperationRunLinkContractGuardTest.php tests/Unit/Filament/PanelThemeAssetTest.php

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #268
2026-04-23 13:09:53 +00:00

161 lines
6.8 KiB
PHP

<?php
declare(strict_types=1);
use Tests\Support\OpsUx\SourceFileScanner;
/**
* @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',
'tenant_panel_provider' => $root.'/app/Providers/Filament/TenantPanelProvider.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
{
$paths = operationRunLinkContractIncludePaths();
return [
$paths['admin_panel_provider'] => 'Admin panel navigation is bootstrapping infrastructure and intentionally links to the canonical collection route before request-scoped navigation context exists.',
$paths['tenant_panel_provider'] => 'Tenant panel navigation is bootstrapping infrastructure and intentionally links to the canonical collection route before tenant-specific helper context is owned by the source surface.',
$paths['ensure_filament_tenant_selected'] => 'Tenant-selection middleware owns redirect/navigation fallback infrastructure and must not fabricate source-surface navigation context.',
$paths['clear_tenant_context_controller'] => 'Clear-tenant redirects preserve an explicit redirect contract and cannot depend on UI helper context.',
];
}
/**
* @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(array_keys($allowlist))->toHaveCount(4);
foreach ($allowlist as $reason) {
expect($reason)
->not->toBe('')
->not->toContain('convenience');
}
foreach (array_keys($allowlist) as $path) {
expect(SourceFileScanner::read($path))->toContain("route('admin.operations.index')");
}
})->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');