Files
Moltbot/src/agents/bash-tools.build-docker-exec-args.test.ts
Alessandro Rodi f257818ea5 fix(sandbox): prevent Windows PATH from poisoning docker exec (#13873)
* fix(sandbox): prevent Windows PATH from poisoning docker exec shell lookup

On Windows hosts, `buildDockerExecArgs` passes the host PATH env var
(containing Windows paths like `C:\Windows\System32`) to `docker exec -e
PATH=...`. Docker uses this PATH to resolve the executable argument
(`sh`), which fails because Windows paths don't exist in the Linux
container — producing `exec: "sh": executable file not found in $PATH`.

Two changes:
- Skip PATH in the `-e` env loop (it's already handled separately via
  OPENCLAW_PREPEND_PATH + shell export)
- Use absolute `/bin/sh` instead of bare `sh` to eliminate PATH
  dependency entirely

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* style: add braces around continue to satisfy linter

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(test): update assertion to match /bin/sh in buildDockerExecArgs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 16:17:33 -06:00

94 lines
2.7 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { buildDockerExecArgs } from "./bash-tools.shared.js";
describe("buildDockerExecArgs", () => {
it("prepends custom PATH after login shell sourcing to preserve both custom and system tools", () => {
const args = buildDockerExecArgs({
containerName: "test-container",
command: "echo hello",
env: {
PATH: "/custom/bin:/usr/local/bin:/usr/bin",
HOME: "/home/user",
},
tty: false,
});
const commandArg = args[args.length - 1];
expect(args).toContain("OPENCLAW_PREPEND_PATH=/custom/bin:/usr/local/bin:/usr/bin");
expect(commandArg).toContain('export PATH="${OPENCLAW_PREPEND_PATH}:$PATH"');
expect(commandArg).toContain("echo hello");
expect(commandArg).toBe(
'export PATH="${OPENCLAW_PREPEND_PATH}:$PATH"; unset OPENCLAW_PREPEND_PATH; echo hello',
);
});
it("does not interpolate PATH into the shell command", () => {
const injectedPath = "$(touch /tmp/openclaw-path-injection)";
const args = buildDockerExecArgs({
containerName: "test-container",
command: "echo hello",
env: {
PATH: injectedPath,
HOME: "/home/user",
},
tty: false,
});
const commandArg = args[args.length - 1];
expect(args).toContain(`OPENCLAW_PREPEND_PATH=${injectedPath}`);
expect(commandArg).not.toContain(injectedPath);
expect(commandArg).toContain("OPENCLAW_PREPEND_PATH");
});
it("does not add PATH export when PATH is not in env", () => {
const args = buildDockerExecArgs({
containerName: "test-container",
command: "echo hello",
env: {
HOME: "/home/user",
},
tty: false,
});
const commandArg = args[args.length - 1];
expect(commandArg).toBe("echo hello");
expect(commandArg).not.toContain("export PATH");
});
it("includes workdir flag when specified", () => {
const args = buildDockerExecArgs({
containerName: "test-container",
command: "pwd",
workdir: "/workspace",
env: { HOME: "/home/user" },
tty: false,
});
expect(args).toContain("-w");
expect(args).toContain("/workspace");
});
it("uses login shell for consistent environment", () => {
const args = buildDockerExecArgs({
containerName: "test-container",
command: "echo test",
env: { HOME: "/home/user" },
tty: false,
});
expect(args).toContain("/bin/sh");
expect(args).toContain("-lc");
});
it("includes tty flag when requested", () => {
const args = buildDockerExecArgs({
containerName: "test-container",
command: "bash",
env: { HOME: "/home/user" },
tty: true,
});
expect(args).toContain("-t");
});
});