fix: enable shell option for child process execution (#391)
## Changes - Added a `requiresShell` function to detect when a command contains shell operators - In the `exec` function, enabled the `shell: true` option if shell operators are present ## Why This Is Necessary See the discussion in this issue comment: https://github.com/openai/codex/issues/320#issuecomment-2816528014 ## Code Explanation The `requiresShell` function parses the command arguments and checks for any shell‑specific operators. If it finds shell operators, it adds the `shell: true` option when running the command so that it’s executed through a shell interpreter.
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
import type { ExecInput, ExecResult } from "./sandbox/interface.js";
|
import type { ExecInput, ExecResult } from "./sandbox/interface.js";
|
||||||
import type { SpawnOptions } from "child_process";
|
import type { SpawnOptions } from "child_process";
|
||||||
|
import type { ParseEntry } from "shell-quote";
|
||||||
|
|
||||||
import { process_patch } from "./apply-patch.js";
|
import { process_patch } from "./apply-patch.js";
|
||||||
import { SandboxType } from "./sandbox/interface.js";
|
import { SandboxType } from "./sandbox/interface.js";
|
||||||
@@ -8,9 +9,17 @@ import { exec as rawExec } from "./sandbox/raw-exec.js";
|
|||||||
import { formatCommandForDisplay } from "../../format-command.js";
|
import { formatCommandForDisplay } from "../../format-command.js";
|
||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
import os from "os";
|
import os from "os";
|
||||||
|
import { parse } from "shell-quote";
|
||||||
|
|
||||||
const DEFAULT_TIMEOUT_MS = 10_000; // 10 seconds
|
const DEFAULT_TIMEOUT_MS = 10_000; // 10 seconds
|
||||||
|
|
||||||
|
function requiresShell(cmd: Array<string>): boolean {
|
||||||
|
return cmd.some((arg) => {
|
||||||
|
const tokens = parse(arg) as Array<ParseEntry>;
|
||||||
|
return tokens.some((token) => typeof token === "object" && "op" in token);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This function should never return a rejected promise: errors should be
|
* This function should never return a rejected promise: errors should be
|
||||||
* mapped to a non-zero exit code and the error message should be in stderr.
|
* mapped to a non-zero exit code and the error message should be in stderr.
|
||||||
@@ -33,6 +42,7 @@ export function exec(
|
|||||||
|
|
||||||
const opts: SpawnOptions = {
|
const opts: SpawnOptions = {
|
||||||
timeout: timeoutInMillis || DEFAULT_TIMEOUT_MS,
|
timeout: timeoutInMillis || DEFAULT_TIMEOUT_MS,
|
||||||
|
...(requiresShell(cmd) ? { shell: true } : {}),
|
||||||
...(workdir ? { cwd: workdir } : {}),
|
...(workdir ? { cwd: workdir } : {}),
|
||||||
};
|
};
|
||||||
// Merge default writable roots with any user-specified ones.
|
// Merge default writable roots with any user-specified ones.
|
||||||
|
|||||||
Reference in New Issue
Block a user