browser()->timeout(60_000); uses(RefreshDatabase::class); function spec402BrowserLoginUrl(User $user, ManagedEnvironment $tenant, string $redirect): string { return route('admin.local.smoke-login', [ 'email' => $user->email, 'tenant' => $tenant->external_id, 'workspace' => $tenant->workspace->slug, 'redirect' => $redirect, ]); } function spec402BrowserPath(string $url): string { $parts = parse_url($url); return ($parts['path'] ?? '/admin').(isset($parts['query']) ? '?'.$parts['query'] : ''); } function spec402BrowserVisibleActionsDisabledScript(array $labels): string { $encodedLabels = json_encode(array_values($labels), JSON_THROW_ON_ERROR); return << { const labels = {$encodedLabels}; const candidates = Array.from(document.querySelectorAll('button, a, [role="button"], [role="menuitem"]')); const visible = (element) => { const style = window.getComputedStyle(element); return style.display !== 'none' && style.visibility !== 'hidden' && ! element.hidden && Boolean(element.offsetWidth || element.offsetHeight || element.getClientRects().length); }; const normalizedText = (element) => [ element.textContent || '', element.getAttribute('aria-label') || '', element.getAttribute('title') || '', ].join(' ').replace(/\\s+/g, ' ').trim(); const disabled = (element) => { const disabledOwner = element.closest('[disabled], [aria-disabled="true"]'); const href = element.tagName === 'A' ? element.getAttribute('href') : null; return Boolean(disabledOwner) || element.disabled === true || element.getAttribute('aria-disabled') === 'true' || (element.tagName === 'A' && (href === null || href === '' || href === '#')); }; return labels.every((label) => candidates.some((element) => ( visible(element) && normalizedText(element).includes(label) && disabled(element) ))); })() JS; } it('Spec402 smokes provider resource authorization boundaries in the browser', function (): void { [$owner, $tenant] = createUserWithTenant(role: 'owner', workspaceRole: 'owner'); $connection = ProviderConnection::factory() ->platform() ->verifiedHealthy() ->create([ 'managed_environment_id' => (int) $tenant->getKey(), 'workspace_id' => (int) $tenant->workspace_id, 'provider' => 'microsoft', 'display_name' => 'Spec 402 Browser Provider', 'is_enabled' => true, ]); $backupSchedule = BackupSchedule::query()->create([ 'managed_environment_id' => (int) $tenant->getKey(), 'name' => 'Spec 402 Browser Backup Schedule', 'is_enabled' => true, 'timezone' => 'UTC', 'frequency' => 'daily', 'time_of_day' => '01:00:00', 'days_of_week' => null, 'policy_types' => ['deviceConfiguration'], 'include_foundations' => true, 'retention_keep_last' => 30, ]); $providerPath = spec402BrowserPath(ProviderConnectionResource::getUrl('view', [ 'record' => $connection, 'environment_id' => (int) $tenant->getKey(), ], panel: 'admin')); $backupPath = spec402BrowserPath(BackupScheduleResource::getUrl('index', panel: 'admin', tenant: $tenant)); visit(spec402BrowserLoginUrl($owner, $tenant, $providerPath)) ->resize(1440, 1000) ->waitForText('Spec 402 Browser Provider') ->assertNoJavaScriptErrors() ->assertNoConsoleLogs(); [$readonly] = createUserWithTenant(tenant: $tenant, role: 'readonly', workspaceRole: 'readonly'); $readonlyPage = visit(spec402BrowserLoginUrl($readonly, $tenant, $backupPath)) ->resize(1440, 1000) ->waitForText($backupSchedule->name) ->assertDontSee('Run now') ->assertNoJavaScriptErrors() ->assertNoConsoleLogs(); expect(\App\Models\OperationRun::query() ->where('managed_environment_id', (int) $tenant->getKey()) ->where('type', 'backup.schedule.execute') ->count())->toBe(0); visit(spec402BrowserLoginUrl($readonly, $tenant, $providerPath)) ->resize(1440, 1000) ->waitForText('Spec 402 Browser Provider') ->assertSee('Run provider verification') ->click('[aria-label="More"]') ->wait(1) ->assertSee('Edit') ->assertSee('Inventory sync') ->assertSee('Compliance snapshot') ->assertScript(spec402BrowserVisibleActionsDisabledScript([ 'Run provider verification', 'Edit', 'Inventory sync', 'Compliance snapshot', ]), true) ->assertNoJavaScriptErrors() ->assertNoConsoleLogs(); [$otherUser, $otherTenant] = createUserWithTenant(role: 'owner', workspaceRole: 'owner'); visit(spec402BrowserLoginUrl($otherUser, $otherTenant, $backupPath)) ->resize(1440, 1000) ->assertScript('document.body.innerText.includes("404") || document.body.innerText.includes("Not Found") || document.body.innerText.includes("No access")', true) ->assertNoJavaScriptErrors() ->assertNoConsoleLogs(); visit('/system') ->resize(1440, 1000) ->assertScript('document.body.innerText.includes("404") || document.body.innerText.includes("Not Found") || document.body.innerText.includes("No access")', true) ->assertNoJavaScriptErrors() ->assertNoConsoleLogs(); });