From 0d6150a687f95353132f2562660e0fdf12e19945 Mon Sep 17 00:00:00 2001 From: Kyle Brown Date: Wed, 12 Aug 2026 15:40:32 +0000 Subject: [PATCH] fix(deep-scan): avoid unspawnable Windows Codex paths --- sdk/typescript/src/runtime.ts | 39 +++++++++++++++++++++++-- sdk/typescript/tests-ts/runtime.test.ts | 30 +++++++++++++++++++ 2 files changed, 66 insertions(+), 3 deletions(-) diff --git a/sdk/typescript/src/runtime.ts b/sdk/typescript/src/runtime.ts index 9226cf47..30279f10 100644 --- a/sdk/typescript/src/runtime.ts +++ b/sdk/typescript/src/runtime.ts @@ -63,6 +63,8 @@ const CREDENTIAL_LOGOUT_MARKER = ".codex-security-logged-out"; const CREDENTIAL_LOCK_POLL_MILLISECONDS = 25; const INCOMPLETE_CREDENTIAL_LOCK_MILLISECONDS = 30_000; const MAX_WINDOWS_CREDENTIAL_ACL_STDERR = 64 * 1024; +const WINDOWS_APPS_PATH = /(^|[\\/])windowsapps([\\/]|$)/iu; +const WINDOWS_DIRECT_EXECUTABLE = /^\.(?:exe|com)$/iu; export interface PluginInstall { pluginRoot: string; @@ -2289,15 +2291,46 @@ export async function resolvePluginPython( export function pluginExecutionEnvironment( python: string, environment: ProcessEnvironment = process.env, + platform: NodeJS.Platform = process.platform, ): ProcessEnvironment { + const configuredCodexPath = configuredCodexCliPath(environment, platform); + const codexPath = + configuredCodexPath !== undefined && + (platform !== "win32" || + (WINDOWS_DIRECT_EXECUTABLE.test(extname(configuredCodexPath)) && + !WINDOWS_APPS_PATH.test(configuredCodexPath))) + ? configuredCodexPath + : resolveCodexCommand().command; + const normalizedEnvironment = + platform === "win32" + ? Object.fromEntries( + Object.entries(environment).filter( + ([name]) => name.toUpperCase() !== "CODEX_CLI_PATH", + ), + ) + : environment; return { - ...environment, + ...normalizedEnvironment, PYTHON: python, - CODEX_CLI_PATH: - environment["CODEX_CLI_PATH"]?.trim() || resolveCodexCommand().command, + CODEX_CLI_PATH: codexPath, }; } +function configuredCodexCliPath( + environment: ProcessEnvironment, + platform: NodeJS.Platform, +): string | undefined { + const exact = environment["CODEX_CLI_PATH"]?.trim(); + if (exact) return exact; + if (platform !== "win32") return undefined; + return Object.entries(environment) + .find( + ([name, value]) => + name.toUpperCase() === "CODEX_CLI_PATH" && value?.trim(), + )?.[1] + ?.trim(); +} + export async function cleanupSdkDirectory(path: string): Promise { await rm(path, { recursive: true, force: true }); } diff --git a/sdk/typescript/tests-ts/runtime.test.ts b/sdk/typescript/tests-ts/runtime.test.ts index a4780903..017e7be3 100644 --- a/sdk/typescript/tests-ts/runtime.test.ts +++ b/sdk/typescript/tests-ts/runtime.test.ts @@ -1715,6 +1715,36 @@ describe("plugin runtime preparation", () => { ).toBe(resolveCodexCommand().command); }); + test("uses only directly spawnable Windows Codex overrides for nested workers", () => { + const configured = String.raw`C:\Users\example\AppData\Local\OpenAI\Codex\bin\0.146.0\codex.exe`; + const bundled = resolveCodexCommand().command; + + expect( + pluginExecutionEnvironment( + String.raw`C:\Python\python.exe`, + { Codex_Cli_Path: ` ${configured} ` }, + "win32", + ), + ).toEqual({ + CODEX_CLI_PATH: configured, + PYTHON: String.raw`C:\Python\python.exe`, + }); + + for (const rejected of [ + String.raw`C:\Users\example\AppData\Roaming\npm\codex`, + String.raw`C:\Users\example\AppData\Roaming\npm\codex.cmd`, + String.raw`C:\Program Files\WindowsApps\OpenAI.Codex_26.727.6591.0_x64__2p2nqsd0c76g0\app\resources\codex.exe`, + ]) { + expect( + pluginExecutionEnvironment( + String.raw`C:\Python\python.exe`, + { CODEX_CLI_PATH: rejected }, + "win32", + )["CODEX_CLI_PATH"], + ).toBe(bundled); + } + }); + test("selects the native Windows Codex executable package", () => { expect(codexPlatformPackage("win32", "x64")).toEqual({ packageName: "@openai/codex-win32-x64",