fix(crabbox): bootstrap absolute macOS env pnpm

This commit is contained in:
Vincent Koc
2026-06-16 04:58:47 +02:00
parent 2b05bd7b0d
commit 6da2d6ac5a
2 changed files with 110 additions and 11 deletions

View File

@@ -932,6 +932,7 @@ function stripShellExecutionPrefixes(wordsInput, options = {}) {
function stripEnvCommandOptions(words, { canShimIgnoreEnvironment = true } = {}) {
const originalWords = [...words];
const envCommand = words.shift() ?? "";
const canShimThisEnv = canShimIgnoreEnvironment && isSupportedSystemEnvCommand(envCommand);
let ignoresEnvironment = false;
for (;;) {
const word = words[0] ?? "";
@@ -976,7 +977,7 @@ function stripEnvCommandOptions(words, { canShimIgnoreEnvironment = true } = {})
return words.length > 0;
}
if (word === "-i" || word === "--ignore-environment") {
if (!canShimIgnoreEnvironment || envCommand.includes("/")) {
if (!canShimThisEnv) {
words.splice(0, words.length, ...originalWords);
return false;
}
@@ -997,7 +998,7 @@ function stripEnvCommandOptions(words, { canShimIgnoreEnvironment = true } = {})
}
if (word.startsWith("-") && word !== "-") {
if (word.includes("i")) {
if (!canShimIgnoreEnvironment || envCommand.includes("/")) {
if (!canShimThisEnv) {
words.splice(0, words.length, ...originalWords);
return false;
}
@@ -1006,7 +1007,7 @@ function stripEnvCommandOptions(words, { canShimIgnoreEnvironment = true } = {})
words.shift();
continue;
}
if (ignoresEnvironment && (!canShimIgnoreEnvironment || envCommand.includes("/"))) {
if (ignoresEnvironment && !canShimThisEnv) {
words.splice(0, words.length, ...originalWords);
return false;
}
@@ -1014,6 +1015,10 @@ function stripEnvCommandOptions(words, { canShimIgnoreEnvironment = true } = {})
}
}
function isSupportedSystemEnvCommand(command) {
return command === "env" || command === "/usr/bin/env";
}
function shellWordBasename(word) {
return (word ?? "").split("/").pop() ?? "";
}
@@ -1738,11 +1743,7 @@ function remoteAwsMacosJsBootstrap({ packageManager = false } = {}) {
}
function scopedAwsMacosEnvCommand(commandArgs) {
if (
commandArgs.length <= 1 ||
shellWordBasename(commandArgs[0]) !== "env" ||
commandArgs[0].includes("/")
) {
if (commandArgs.length <= 1 || !isSupportedSystemEnvCommand(commandArgs[0])) {
return null;
}

View File

@@ -826,7 +826,7 @@ describe.concurrent("scripts/crabbox-wrapper", () => {
expect(remoteCommand).toContain("openclaw_crabbox_bootstrap_macos_js");
expect(remoteCommand).toContain('corepack enable --install-directory "$PNPM_HOME"');
expect(remoteCommand).toContain("pnpm --version >&2");
expectGroupedShellCommand(remoteCommand, "/usr/bin/env pnpm --version");
expectGroupedShellCommand(remoteCommand, "openclaw_crabbox_env pnpm --version");
});
it("bootstraps Corepack for raw AWS macOS env option pnpm commands", () => {
@@ -895,7 +895,7 @@ describe.concurrent("scripts/crabbox-wrapper", () => {
);
});
it("does not bootstrap absolute env ignore-environment commands it cannot preserve", () => {
it("bootstraps Corepack for raw AWS macOS absolute env ignore-environment commands", () => {
const result = runWrapper(
"provider: hetzner, aws, local-container, blacksmith-testbox, or cloudflare\n",
[
@@ -913,6 +913,62 @@ describe.concurrent("scripts/crabbox-wrapper", () => {
],
);
const output = parseFakeCrabboxOutput(result);
const remoteCommand = normalizeShellLineEndings(output.args.at(-1) ?? "");
expect(result.status).toBe(0);
expect(output.args).toContain("--shell");
expect(remoteCommand).toContain("openclaw_crabbox_bootstrap_macos_js");
expect(remoteCommand).toContain("pnpm --version >&2");
expectGroupedShellCommand(
remoteCommand,
"openclaw_crabbox_env -i PATH=/usr/bin:/bin pnpm --version",
);
});
it("injects the bootstrapped PATH for raw AWS macOS absolute env -i commands", () => {
const result = runWrapper(
"provider: hetzner, aws, local-container, blacksmith-testbox, or cloudflare\n",
[
"run",
"--provider",
"aws",
"--target",
"macos",
"--",
"/usr/bin/env",
"-i",
"pnpm",
"--version",
],
);
const output = parseFakeCrabboxOutput(result);
const remoteCommand = normalizeShellLineEndings(output.args.at(-1) ?? "");
expect(result.status).toBe(0);
expect(remoteCommand).toContain("openclaw_crabbox_bootstrap_macos_js");
expect(remoteCommand).toContain(
'if [ "$openclaw_env_ignore" = "1" ] && [ "$openclaw_env_path_seen" = "0" ]; then openclaw_env_args+=("PATH=$PATH"); fi;',
);
expectGroupedShellCommand(remoteCommand, "openclaw_crabbox_env -i pnpm --version");
});
it("does not rewrite custom env executables for raw AWS macOS ignore-environment commands", () => {
const result = runWrapper(
"provider: hetzner, aws, local-container, blacksmith-testbox, or cloudflare\n",
[
"run",
"--provider",
"aws",
"--target",
"macos",
"--",
"./tools/env",
"-i",
"pnpm",
"--version",
],
);
const output = parseFakeCrabboxOutput(result);
const remoteCommand = normalizeShellLineEndings(output.args.at(-1) ?? "");
expect(result.status).toBe(0);
@@ -1027,7 +1083,7 @@ describe.concurrent("scripts/crabbox-wrapper", () => {
expect(remoteCommand.indexOf("-S|--split-string|-S*|--split-string=*)")).toBeLessThan(
remoteCommand.indexOf("-[!-]*i*)"),
);
expectGroupedShellCommand(remoteCommand, "/usr/bin/env -S 'pnpm --version'");
expectGroupedShellCommand(remoteCommand, "openclaw_crabbox_env -S 'pnpm --version'");
});
it("bootstraps Corepack for AWS macOS node changed-gate commands", () => {
@@ -2324,6 +2380,48 @@ describe.concurrent("scripts/crabbox-wrapper", () => {
);
});
it("preserves sparse changed-gate Git bootstrap for direct absolute env -i commands", () => {
const result = runWrapper(
"provider: hetzner, aws, local-container, blacksmith-testbox, or cloudflare\n",
["run", "--provider", "aws", "--", "/usr/bin/env", "-i", "pnpm", "check:changed"],
{
gitResponses: {
[GIT_CONFIG_SPARSE_KEY]: { stdout: "true\n" },
[GIT_STATUS_PORCELAIN_KEY]: { stdout: "" },
[GIT_MERGE_BASE_MAIN_HEAD_KEY]: { stdout: "abc123\n" },
},
},
);
const output = parseFakeCrabboxOutput(result);
const remoteCommand = normalizeShellLineEndings(output.args.at(-1) ?? "");
expect(result.status).toBe(0);
expect(output.args).toContain("--shell");
expect(remoteCommand).toContain("git init -q");
expect(remoteCommand).toMatch(
/&& \/usr\/bin\/env -i OPENCLAW_CHECK_CHANGED_REMOTE_CHILD=1 OPENCLAW_CHANGED_LANES_RAW_SYNC=1 CI=1 pnpm check:changed$/u,
);
});
it("does not mark custom env executables outside the sanitized env", () => {
const result = runWrapper(
"provider: hetzner, aws, local-container, blacksmith-testbox, or cloudflare\n",
["run", "--provider", "aws", "--", "./tools/env", "-i", "pnpm", "check:changed"],
{
gitResponses: {
[GIT_CONFIG_SPARSE_KEY]: { stdout: "true\n" },
[GIT_STATUS_PORCELAIN_KEY]: { stdout: "" },
[GIT_MERGE_BASE_MAIN_HEAD_KEY]: { stdout: "abc123\n" },
},
},
);
const output = parseFakeCrabboxOutput(result);
expect(result.status).toBe(0);
expect(output.args.join("\0")).not.toContain("OPENCLAW_CHECK_CHANGED_REMOTE_CHILD=1");
expect(output.args.join("\0")).not.toContain("git init -q");
});
it("does not mark assignment-prefixed env -i changed gates outside the sanitized env", () => {
const result = runWrapper(
"provider: hetzner, aws, local-container, blacksmith-testbox, or cloudflare\n",