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:
Shuto Otaki
2025-04-19 14:42:19 +09:00
committed by GitHub
parent ca7ab76569
commit b46b596e5f

View File

@@ -1,5 +1,6 @@
import type { ExecInput, ExecResult } from "./sandbox/interface.js";
import type { SpawnOptions } from "child_process";
import type { ParseEntry } from "shell-quote";
import { process_patch } from "./apply-patch.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 fs from "fs";
import os from "os";
import { parse } from "shell-quote";
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
* 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 = {
timeout: timeoutInMillis || DEFAULT_TIMEOUT_MS,
...(requiresShell(cmd) ? { shell: true } : {}),
...(workdir ? { cwd: workdir } : {}),
};
// Merge default writable roots with any user-specified ones.