TenantAtlas/apps/platform/tests/Feature/Architecture/ScopedUiActionContextContractTest.php
Ahmed Darrazi 9e435ea91f
Some checks failed
PR Fast Feedback / fast-feedback (pull_request) Failing after 1m2s
feat: implement explicit UiActionContext contract
2026-06-07 13:12:02 +02:00

125 lines
5.1 KiB
PHP

<?php
declare(strict_types=1);
function scopedUiActionContextContractChecks(): array
{
return [
'inventory sync header action' => [
'file' => 'app/Filament/Resources/InventoryItemResource/Pages/ListInventoryItems.php',
'action' => 'run_inventory_sync',
],
'policy sync action factory' => [
'file' => 'app/Filament/Resources/PolicyResource.php',
'action' => 'sync',
'anchor' => 'public static function makeSyncAction',
],
'directory group sync header action' => [
'file' => 'app/Filament/Resources/EntraGroupResource/Pages/ListEntraGroups.php',
'action' => 'sync_groups',
],
'evidence snapshot header action' => [
'file' => 'app/Filament/Resources/EvidenceSnapshotResource/Pages/ListEvidenceSnapshots.php',
'action' => 'create_snapshot',
],
'evidence snapshot empty-state action' => [
'file' => 'app/Filament/Resources/EvidenceSnapshotResource.php',
'action' => 'create_first_snapshot',
],
'review pack generation action factory' => [
'file' => 'app/Filament/Resources/ReviewPackResource.php',
'action' => 'generate_pack',
'anchor' => 'public static function generatePackAction',
],
'environment review creation action factory' => [
'file' => 'app/Filament/Resources/EnvironmentReviewResource.php',
'action' => 'create_review',
'anchor' => 'public static function makeCreateReviewAction',
],
'environment diagnostics bootstrap action' => [
'file' => 'app/Filament/Pages/EnvironmentDiagnostics.php',
'action' => 'bootstrapOwner',
],
'environment diagnostics merge action' => [
'file' => 'app/Filament/Pages/EnvironmentDiagnostics.php',
'action' => 'mergeDuplicateMemberships',
],
'restore run create action factory' => [
'file' => 'app/Filament/Resources/RestoreRunResource.php',
'action' => 'New restore run',
'anchor' => 'public static function makeCreateAction',
],
'environment dashboard support request action' => [
'file' => 'app/Filament/Pages/EnvironmentDashboard.php',
'action' => 'requestSupport',
'anchor' => 'private function requestSupportAction',
],
'environment dashboard support diagnostics action' => [
'file' => 'app/Filament/Pages/EnvironmentDashboard.php',
'action' => 'openSupportDiagnostics',
'anchor' => 'private function openSupportDiagnosticsAction',
],
];
}
it('requires explicit UiActionContext for representative risky scoped no-record actions', function (array $check): void {
$path = base_path($check['file']);
$source = file_get_contents($path);
expect($source)->not->toBeFalse();
$source = (string) $source;
$anchor = $check['anchor'] ?? "Action::make('{$check['action']}'";
$position = strpos($source, $anchor);
expect($position)
->not->toBeFalse("Could not find {$check['action']} in {$check['file']}.");
$slice = substr($source, max(0, (int) $position - 500), 10000);
expect($slice)
->toContain('UiEnforcement::forScopedAction')
->and($source)
->toContain('UiActionContext');
})->with(fn (): array => collect(scopedUiActionContextContractChecks())
->mapWithKeys(static fn (array $check, string $name): array => [$name => [$check]])
->all());
it('does not reintroduce the guarded no-record scoped action names through UiEnforcement::forAction', function (): void {
$checks = scopedUiActionContextContractChecks();
$guardedFiles = collect($checks)->pluck('file')->unique()->values()->all();
$guardedActionNames = collect($checks)
->pluck('action')
->reject(static fn (string $action): bool => $action === 'sync' || $action === 'New restore run')
->map(static fn (string $action): string => preg_quote($action, '/'))
->implode('|');
$violations = [];
foreach ($guardedFiles as $relativePath) {
$path = base_path($relativePath);
$source = file_get_contents($path);
if (! is_string($source) || ! str_contains($source, 'UiEnforcement::forAction')) {
continue;
}
$patterns = [
'/UiEnforcement::forAction\s*\(.{0,1200}Action::make\(\s*[\'"](?:'.$guardedActionNames.')[\'"]/s',
'/public static function makeSyncAction.{0,1400}UiEnforcement::forAction/s',
'/public static function makeCreateAction.{0,1400}UiEnforcement::forAction/s',
];
foreach ($patterns as $pattern) {
if (preg_match($pattern, $source, $match, PREG_OFFSET_CAPTURE) !== 1) {
continue;
}
$line = substr_count(substr($source, 0, (int) $match[0][1]), "\n") + 1;
$violations[] = "{$relativePath}:{$line} use UiEnforcement::forScopedAction(..., UiActionContext resolver) for risky no-record scoped actions.";
}
}
expect($violations)->toBeEmpty(implode("\n", $violations));
});