From 62af2031f68914a3b2982c3e2c175de6f369f668 Mon Sep 17 00:00:00 2001 From: Shirone Date: Tue, 13 Jan 2026 19:33:09 +0100 Subject: [PATCH 1/2] feat: enhance dev server URL handling and improve accessibility - Added URL and URLSearchParams as readonly globals in ESLint configuration. - Updated WorktreeActionsDropdown and WorktreeTab components to include aria-labels for better accessibility. - Implemented error handling for dev server URL opening, ensuring only valid HTTP/HTTPS protocols are used and providing user feedback for errors. These changes improve user experience and accessibility when interacting with the dev server functionality. --- apps/ui/eslint.config.mjs | 2 + .../components/worktree-actions-dropdown.tsx | 8 +++- .../components/worktree-tab.tsx | 37 ++++++++++++------- .../worktree-panel/hooks/use-dev-servers.ts | 33 ++++++++++++++++- 4 files changed, 62 insertions(+), 18 deletions(-) diff --git a/apps/ui/eslint.config.mjs b/apps/ui/eslint.config.mjs index d7bc54d4..6db837e3 100644 --- a/apps/ui/eslint.config.mjs +++ b/apps/ui/eslint.config.mjs @@ -70,6 +70,8 @@ const eslintConfig = defineConfig([ AbortSignal: 'readonly', Audio: 'readonly', ScrollBehavior: 'readonly', + URL: 'readonly', + URLSearchParams: 'readonly', // Timers setTimeout: 'readonly', setInterval: 'readonly', diff --git a/apps/ui/src/components/views/board-view/worktree-panel/components/worktree-actions-dropdown.tsx b/apps/ui/src/components/views/board-view/worktree-panel/components/worktree-actions-dropdown.tsx index c7d8f26b..27cc38d8 100644 --- a/apps/ui/src/components/views/board-view/worktree-panel/components/worktree-actions-dropdown.tsx +++ b/apps/ui/src/components/views/board-view/worktree-panel/components/worktree-actions-dropdown.tsx @@ -143,8 +143,12 @@ export function WorktreeActionsDropdown({ Dev Server Running (:{devServerInfo?.port}) - onOpenDevServerUrl(worktree)} className="text-xs"> - + onOpenDevServerUrl(worktree)} + className="text-xs" + aria-label={`Open dev server on port ${devServerInfo?.port} in browser`} + > + onOpenDevServerUrl(worktree)} - title={`Open dev server (port ${devServerInfo?.port})`} - > - - + + + + + + +

Open dev server (:{devServerInfo?.port})

+
+
+
)} { const serverInfo = runningDevServers.get(getWorktreeKey(worktree)); - if (serverInfo) { - window.open(serverInfo.url, '_blank'); + if (!serverInfo) { + logger.warn('No dev server info found for worktree:', getWorktreeKey(worktree)); + toast.error('Dev server not found', { + description: 'The dev server may have stopped. Try starting it again.', + }); + return; + } + + try { + // Rewrite URL hostname to match the current browser's hostname. + // This ensures dev server URLs work when accessing Automaker from + // remote machines (e.g., 192.168.x.x or hostname.local instead of localhost). + const devServerUrl = new URL(serverInfo.url); + + // Security: Only allow http/https protocols to prevent potential attacks + // via data:, javascript:, file:, or other dangerous URL schemes + if (devServerUrl.protocol !== 'http:' && devServerUrl.protocol !== 'https:') { + logger.error('Invalid dev server URL protocol:', devServerUrl.protocol); + toast.error('Invalid dev server URL', { + description: 'The server returned an unsupported URL protocol.', + }); + return; + } + + devServerUrl.hostname = window.location.hostname; + window.open(devServerUrl.toString(), '_blank'); + } catch (error) { + logger.error('Failed to parse dev server URL:', error); + toast.error('Failed to open dev server', { + description: 'The server URL could not be processed. Please try again.', + }); } }, [runningDevServers, getWorktreeKey] From f4390bc82f598be12277f570a4e0c64d96d341b4 Mon Sep 17 00:00:00 2001 From: Shirone Date: Tue, 13 Jan 2026 19:43:20 +0100 Subject: [PATCH 2/2] security: add noopener,noreferrer to window.open calls Add 'noopener,noreferrer' parameter to all window.open() calls with target='_blank' to prevent tabnabbing attacks. This prevents the newly opened page from accessing window.opener, protecting against potential security vulnerabilities. Affected files: - use-dev-servers.ts: Dev server URL links - worktree-actions-dropdown.tsx: PR URL links - create-pr-dialog.tsx: PR creation and browser fallback links Co-Authored-By: Claude Sonnet 4.5 --- .../views/board-view/dialogs/create-pr-dialog.tsx | 11 +++++++---- .../components/worktree-actions-dropdown.tsx | 2 +- .../worktree-panel/hooks/use-dev-servers.ts | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/apps/ui/src/components/views/board-view/dialogs/create-pr-dialog.tsx b/apps/ui/src/components/views/board-view/dialogs/create-pr-dialog.tsx index a8ba8ee5..3abbb75f 100644 --- a/apps/ui/src/components/views/board-view/dialogs/create-pr-dialog.tsx +++ b/apps/ui/src/components/views/board-view/dialogs/create-pr-dialog.tsx @@ -117,7 +117,7 @@ export function CreatePRDialog({ description: `PR already exists for ${result.result.branch}`, action: { label: 'View PR', - onClick: () => window.open(result.result!.prUrl!, '_blank'), + onClick: () => window.open(result.result!.prUrl!, '_blank', 'noopener,noreferrer'), }, }); } else { @@ -125,7 +125,7 @@ export function CreatePRDialog({ description: `PR created from ${result.result.branch}`, action: { label: 'View PR', - onClick: () => window.open(result.result!.prUrl!, '_blank'), + onClick: () => window.open(result.result!.prUrl!, '_blank', 'noopener,noreferrer'), }, }); } @@ -251,7 +251,10 @@ export function CreatePRDialog({

Your PR is ready for review

- @@ -277,7 +280,7 @@ export function CreatePRDialog({