fix(linux): respect CLI flag value boundaries

This commit is contained in:
Neil
2026-09-01 14:07:50 -07:00
parent 4552fccb82
commit de4ad981ae
3 changed files with 78 additions and 8 deletions
@@ -126,6 +126,31 @@ describe('CLI launch redirect: command form', () => {
])
})
it.each(['--user-data-dir', '--proxy-server', '--unknown-desktop-switch'])(
'does not treat a value of %s as a CLI early-exit flag',
(flag) => {
expect(
getCliLaunchArgs([linux.execPath, flag, 'help'], linux.cliEntryPath, linuxOptions)
).toBeNull()
}
)
it('does not treat a serve option value as a help request', () => {
expect(
getCliLaunchArgs(
[linux.execPath, 'serve', '--project-root', 'help'],
linux.cliEntryPath,
linuxOptions
)
).toBeNull()
})
it('does not reinterpret help after the argument terminator', () => {
expect(
getCliLaunchArgs([linux.execPath, 'serve', '--', '--help'], linux.cliEntryPath, linuxOptions)
).toBeNull()
})
it('leaves a plain desktop launch alone', () => {
expect(getCliLaunchArgs([linux.execPath], linux.cliEntryPath, linuxOptions)).toBeNull()
expect(
+51 -7
View File
@@ -1,8 +1,9 @@
import { existsSync } from 'node:fs'
import { posix, win32 } from 'node:path'
import { runProcessSync } from '../../shared/child-process/run-process'
import { CLI_GLOBAL_VALUE_FLAGS, findCliCommandIndex } from '../../shared/cli-argument-boundary'
import { CLI_BOOLEAN_FLAGS, findCliCommandIndex } from '../../shared/cli-argument-boundary'
import { CLI_COMMAND_NAMES } from './cli-command-names'
import { VALUE_TAKING_FLAGS } from './serve-mode-argv'
export type CliLaunchRedirectResult = { redirected: false } | { redirected: true; status: number }
@@ -20,6 +21,7 @@ export type CliLaunchRedirectOptions = {
const CLI_EARLY_EXIT_FLAGS = new Set(['--help', '-h', 'help', '--version', '-v'])
const DESKTOP_FLAGS = new Set(['--no-sandbox', '--disable-gpu'])
const CLI_LAUNCH_VALUE_FLAG_NAMES = [...VALUE_TAKING_FLAGS].map((flag) => flag.slice(2))
// Fence recursion if a wrapper drops ELECTRON_RUN_AS_NODE again.
const REDIRECT_ATTEMPT_ENV = 'ORCA_CLI_LAUNCH_REDIRECTED'
@@ -114,17 +116,59 @@ function getCommandLaunchArgs(
return null
}
const commandPaths = options.commandNames.map((name) => [name])
const commandIndex = findCliCommandIndex(args, commandPaths, CLI_GLOBAL_VALUE_FLAGS)
const commandIndex = findCliCommandIndex(args, commandPaths, CLI_LAUNCH_VALUE_FLAG_NAMES)
const cliArgs = args.filter(
(arg, index) => (commandIndex !== -1 && index > commandIndex) || !DESKTOP_FLAGS.has(arg)
)
if (cliArgs.some((arg) => CLI_EARLY_EXIT_FLAGS.has(arg))) {
return cliArgs
}
const command = commandIndex === -1 ? null : args[commandIndex]
// Keep direct serve in-process so signals reach its full child tree.
return command && command !== 'serve' ? cliArgs : null
if (command && command !== 'serve') {
return cliArgs
}
return hasCliEarlyExitArg(args, commandIndex) ? cliArgs : null
}
function hasCliEarlyExitArg(args: readonly string[], commandIndex: number): boolean {
let index = 0
let positionalCount = 0
while (index < args.length) {
const token = args[index]!
if (token === '--') {
return false
}
if (
CLI_EARLY_EXIT_FLAGS.has(token) &&
(token !== 'help' || positionalCount === 0 || commandIndex !== -1)
) {
return true
}
if (!token.startsWith('-')) {
if (token === 'help' && (positionalCount === 0 || commandIndex !== -1)) {
return true
}
positionalCount += 1
}
index += 1
if (takesLaunchValue(token, args[index])) {
index += 1
}
}
return false
}
function takesLaunchValue(token: string, next: string | undefined): boolean {
if (
!next ||
next.startsWith('-') ||
!token.startsWith('-') ||
token.includes('=') ||
CLI_EARLY_EXIT_FLAGS.has(token) ||
DESKTOP_FLAGS.has(token)
) {
return false
}
const flagName = token.startsWith('--') ? token.slice(2) : token.replace(/^-+/, '')
return !CLI_BOOLEAN_FLAGS.has(flagName)
}
function buildPackagedCliEntryPath(platform: NodeJS.Platform, resourcesPath: string): string {
+2 -1
View File
@@ -26,12 +26,13 @@ const CLI_TO_SERVE_VALUE_FLAG = new Map([
* Residual class: a flag outside this list whose space-separated value is literally `serve` would
* read as the subcommand. Chromium switches are `--flag=value` only, so no real launch does that.
*/
const VALUE_TAKING_FLAGS = new Set([
export const VALUE_TAKING_FLAGS = new Set([
...CLI_TO_SERVE_VALUE_FLAG.keys(),
'--serve-port',
'--serve-pairing-address',
'--serve-project-root',
'--user-data-dir',
'--proxy-server',
'--environment',
'--pairing-code'
])