From 9893eaefbcdfbfe1bc73c6f835100e1f6bdbe651 Mon Sep 17 00:00:00 2001 From: Neil <4138956+nwparker@users.noreply.github.com> Date: Wed, 2 Sep 2026 01:05:51 -0700 Subject: [PATCH] fix(ssh): cite the real command-line budget and reuse the cmd.exe ceiling --- src/main/providers/windows-shell-args.ts | 3 ++- src/main/ssh/ssh-remote-powershell.ts | 8 +++++--- .../ssh-remote-windows-command-line-limit.test.ts | 8 ++++---- src/shared/windows-command-line-budget.ts | 12 ------------ 4 files changed, 11 insertions(+), 20 deletions(-) diff --git a/src/main/providers/windows-shell-args.ts b/src/main/providers/windows-shell-args.ts index 4f984559a63..49db267432b 100644 --- a/src/main/providers/windows-shell-args.ts +++ b/src/main/providers/windows-shell-args.ts @@ -14,7 +14,8 @@ import { } from '../powershell-osc133-bootstrap' import { quoteStartupArg } from '../../shared/tui-agent-startup-shell' -const CMD_EXE_COMMAND_LINE_MAX_CHARS = 8191 +/** cmd.exe's own documented ceiling; callers that go through sshd budget below it. */ +export const CMD_EXE_COMMAND_LINE_MAX_CHARS = 8191 const STARTUP_COMMAND_TEXT_MAX_CHARS = 6000 const POWERSHELL_ENCODED_COMMAND_ARG_MAX_CHARS = 28_000 const CMD_UTF8_SETUP_COMMAND = 'chcp 65001 > nul' diff --git a/src/main/ssh/ssh-remote-powershell.ts b/src/main/ssh/ssh-remote-powershell.ts index abd79e946a2..8c94fd3c483 100644 --- a/src/main/ssh/ssh-remote-powershell.ts +++ b/src/main/ssh/ssh-remote-powershell.ts @@ -1,12 +1,14 @@ import { gunzipSync, gzipSync } from 'node:zlib' import { encodePowerShellCommand } from '../../shared/powershell-command-encoding' -import { CMD_EXE_MAX_COMMAND_LINE_CHARS } from '../../shared/windows-command-line-budget' +import { CMD_EXE_COMMAND_LINE_MAX_CHARS } from '../providers/windows-shell-args' export { quotePowerShellLiteral as powerShellLiteral, quotePowerShellNativeArgument as powerShellNativeArg } from '../../shared/powershell-native-argument' -// Margin for the `/c` wrapper sshd puts around the command before cmd.exe counts it. +// Why cmd.exe and not the 32767 CreateProcess cap: Windows OpenSSH runs every exec request +// through sshd's DefaultShell, cmd.exe on a stock install. Budget under cmd.exe's own ceiling +// to leave room for the `/c` wrapper sshd adds before cmd.exe counts the line. const WINDOWS_REMOTE_COMMAND_LINE_BUDGET_CHARS = 8_000 export function powerShellCommand(script: string): string { @@ -19,7 +21,7 @@ export function powerShellCommand(script: string): string { const compressed = encodedPowerShellCommand(selfExtractingPowerShellScript(script)) if (compressed.length > WINDOWS_REMOTE_COMMAND_LINE_BUDGET_CHARS) { throw new Error( - `Remote Windows command needs ${compressed.length} characters; sshd's cmd.exe refuses more than ${CMD_EXE_MAX_COMMAND_LINE_CHARS}.` + `Remote Windows command needs ${compressed.length} characters; Orca budgets ${WINDOWS_REMOTE_COMMAND_LINE_BUDGET_CHARS} for a line sshd hands to cmd.exe, which itself refuses more than ${CMD_EXE_COMMAND_LINE_MAX_CHARS}.` ) } return compressed diff --git a/src/main/ssh/ssh-remote-windows-command-line-limit.test.ts b/src/main/ssh/ssh-remote-windows-command-line-limit.test.ts index b5bf94119e5..c104078238e 100644 --- a/src/main/ssh/ssh-remote-windows-command-line-limit.test.ts +++ b/src/main/ssh/ssh-remote-windows-command-line-limit.test.ts @@ -1,6 +1,6 @@ import { gunzipSync } from 'node:zlib' import { describe, expect, it } from 'vitest' -import { CMD_EXE_MAX_COMMAND_LINE_CHARS } from '../../shared/windows-command-line-budget' +import { CMD_EXE_COMMAND_LINE_MAX_CHARS } from '../providers/windows-shell-args' import { getRemoteHostPlatform } from './ssh-remote-platform' import { tryStealInstallLockCommand } from './ssh-relay-install-lock-commands' import { decodeRemotePowerShellScript, powerShellCommand } from './ssh-remote-powershell' @@ -40,7 +40,7 @@ describe('Windows remote command line limit', () => { tryStealInstallLockCommand(windows, 'C:\\Users\\orca\\.orca-remote\\relay', 1_200) ] ])('keeps the %s command inside what sshd\u2019s cmd.exe accepts', (_name, command) => { - expect(command.length).toBeLessThanOrEqual(CMD_EXE_MAX_COMMAND_LINE_CHARS) + expect(command.length).toBeLessThanOrEqual(CMD_EXE_COMMAND_LINE_MAX_CHARS) }) it('leaves a command that already fits byte-identical', () => { @@ -54,7 +54,7 @@ describe('Windows remote command line limit', () => { (_unused, index) => `Write-Output ${index}; $slot = 'C:\\Users\\orca\\stage-${index}'` ).join('\n') const command = powerShellCommand(script) - expect(command.length).toBeLessThanOrEqual(CMD_EXE_MAX_COMMAND_LINE_CHARS) + expect(command.length).toBeLessThanOrEqual(CMD_EXE_COMMAND_LINE_MAX_CHARS) expect(decodeRemotePowerShellScript(command)).toBe(script) const bootstrap = Buffer.from( command.match(/-EncodedCommand\s+([A-Za-z0-9+/=]+)$/u)?.[1] ?? '', @@ -72,7 +72,7 @@ describe('Windows remote command line limit', () => { return String.fromCharCode(97 + (seed % 26)) }).join('') expect(() => powerShellCommand(`Write-Output '${incompressible}'`)).toThrow( - /sshd's cmd\.exe refuses more than 8191/u + /Orca budgets 8000 for a line sshd hands to cmd\.exe/u ) }) }) diff --git a/src/shared/windows-command-line-budget.ts b/src/shared/windows-command-line-budget.ts index 74ab0bc78f8..77074e3f531 100644 --- a/src/shared/windows-command-line-budget.ts +++ b/src/shared/windows-command-line-budget.ts @@ -14,18 +14,6 @@ */ export const MAX_COMMAND_LINE_CHARS = 30_000 -/** - * The much smaller cap that applies once cmd.exe is in the chain. - * - * cmd.exe refuses a longer line outright — exit 1 and a localized "The command - * line is too long" — and it is in the chain more often than it looks: Windows - * OpenSSH runs every exec request through sshd's `DefaultShell`, which is - * cmd.exe on a stock install. So a command Orca sends to a Windows SSH host is - * charged this budget, not the 32767 one, and `-EncodedCommand` spends 2.67 - * characters per script character on the way there. - */ -export const CMD_EXE_MAX_COMMAND_LINE_CHARS = 8_191 - /** * What `CreateProcess` will count. *