Skip to content

Commit 6da2d6a

Browse files
committed
fix(crabbox): bootstrap absolute macOS env pnpm
1 parent 2b05bd7 commit 6da2d6a

2 files changed

Lines changed: 110 additions & 11 deletions

File tree

scripts/crabbox-wrapper.mjs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -932,6 +932,7 @@ function stripShellExecutionPrefixes(wordsInput, options = {}) {
932932
function stripEnvCommandOptions(words, { canShimIgnoreEnvironment = true } = {}) {
933933
const originalWords = [...words];
934934
const envCommand = words.shift() ?? "";
935+
const canShimThisEnv = canShimIgnoreEnvironment && isSupportedSystemEnvCommand(envCommand);
935936
let ignoresEnvironment = false;
936937
for (;;) {
937938
const word = words[0] ?? "";
@@ -976,7 +977,7 @@ function stripEnvCommandOptions(words, { canShimIgnoreEnvironment = true } = {})
976977
return words.length > 0;
977978
}
978979
if (word === "-i" || word === "--ignore-environment") {
979-
if (!canShimIgnoreEnvironment || envCommand.includes("/")) {
980+
if (!canShimThisEnv) {
980981
words.splice(0, words.length, ...originalWords);
981982
return false;
982983
}
@@ -997,7 +998,7 @@ function stripEnvCommandOptions(words, { canShimIgnoreEnvironment = true } = {})
997998
}
998999
if (word.startsWith("-") && word !== "-") {
9991000
if (word.includes("i")) {
1000-
if (!canShimIgnoreEnvironment || envCommand.includes("/")) {
1001+
if (!canShimThisEnv) {
10011002
words.splice(0, words.length, ...originalWords);
10021003
return false;
10031004
}
@@ -1006,14 +1007,18 @@ function stripEnvCommandOptions(words, { canShimIgnoreEnvironment = true } = {})
10061007
words.shift();
10071008
continue;
10081009
}
1009-
if (ignoresEnvironment && (!canShimIgnoreEnvironment || envCommand.includes("/"))) {
1010+
if (ignoresEnvironment && !canShimThisEnv) {
10101011
words.splice(0, words.length, ...originalWords);
10111012
return false;
10121013
}
10131014
return true;
10141015
}
10151016
}
10161017

1018+
function isSupportedSystemEnvCommand(command) {
1019+
return command === "env" || command === "/usr/bin/env";
1020+
}
1021+
10171022
function shellWordBasename(word) {
10181023
return (word ?? "").split("/").pop() ?? "";
10191024
}
@@ -1738,11 +1743,7 @@ function remoteAwsMacosJsBootstrap({ packageManager = false } = {}) {
17381743
}
17391744

17401745
function scopedAwsMacosEnvCommand(commandArgs) {
1741-
if (
1742-
commandArgs.length <= 1 ||
1743-
shellWordBasename(commandArgs[0]) !== "env" ||
1744-
commandArgs[0].includes("/")
1745-
) {
1746+
if (commandArgs.length <= 1 || !isSupportedSystemEnvCommand(commandArgs[0])) {
17461747
return null;
17471748
}
17481749

test/scripts/crabbox-wrapper.test.ts

Lines changed: 101 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -826,7 +826,7 @@ describe.concurrent("scripts/crabbox-wrapper", () => {
826826
expect(remoteCommand).toContain("openclaw_crabbox_bootstrap_macos_js");
827827
expect(remoteCommand).toContain('corepack enable --install-directory "$PNPM_HOME"');
828828
expect(remoteCommand).toContain("pnpm --version >&2");
829-
expectGroupedShellCommand(remoteCommand, "/usr/bin/env pnpm --version");
829+
expectGroupedShellCommand(remoteCommand, "openclaw_crabbox_env pnpm --version");
830830
});
831831

832832
it("bootstraps Corepack for raw AWS macOS env option pnpm commands", () => {
@@ -895,7 +895,7 @@ describe.concurrent("scripts/crabbox-wrapper", () => {
895895
);
896896
});
897897

898-
it("does not bootstrap absolute env ignore-environment commands it cannot preserve", () => {
898+
it("bootstraps Corepack for raw AWS macOS absolute env ignore-environment commands", () => {
899899
const result = runWrapper(
900900
"provider: hetzner, aws, local-container, blacksmith-testbox, or cloudflare\n",
901901
[
@@ -913,6 +913,62 @@ describe.concurrent("scripts/crabbox-wrapper", () => {
913913
],
914914
);
915915

916+
const output = parseFakeCrabboxOutput(result);
917+
const remoteCommand = normalizeShellLineEndings(output.args.at(-1) ?? "");
918+
expect(result.status).toBe(0);
919+
expect(output.args).toContain("--shell");
920+
expect(remoteCommand).toContain("openclaw_crabbox_bootstrap_macos_js");
921+
expect(remoteCommand).toContain("pnpm --version >&2");
922+
expectGroupedShellCommand(
923+
remoteCommand,
924+
"openclaw_crabbox_env -i PATH=/usr/bin:/bin pnpm --version",
925+
);
926+
});
927+
928+
it("injects the bootstrapped PATH for raw AWS macOS absolute env -i commands", () => {
929+
const result = runWrapper(
930+
"provider: hetzner, aws, local-container, blacksmith-testbox, or cloudflare\n",
931+
[
932+
"run",
933+
"--provider",
934+
"aws",
935+
"--target",
936+
"macos",
937+
"--",
938+
"/usr/bin/env",
939+
"-i",
940+
"pnpm",
941+
"--version",
942+
],
943+
);
944+
945+
const output = parseFakeCrabboxOutput(result);
946+
const remoteCommand = normalizeShellLineEndings(output.args.at(-1) ?? "");
947+
expect(result.status).toBe(0);
948+
expect(remoteCommand).toContain("openclaw_crabbox_bootstrap_macos_js");
949+
expect(remoteCommand).toContain(
950+
'if [ "$openclaw_env_ignore" = "1" ] && [ "$openclaw_env_path_seen" = "0" ]; then openclaw_env_args+=("PATH=$PATH"); fi;',
951+
);
952+
expectGroupedShellCommand(remoteCommand, "openclaw_crabbox_env -i pnpm --version");
953+
});
954+
955+
it("does not rewrite custom env executables for raw AWS macOS ignore-environment commands", () => {
956+
const result = runWrapper(
957+
"provider: hetzner, aws, local-container, blacksmith-testbox, or cloudflare\n",
958+
[
959+
"run",
960+
"--provider",
961+
"aws",
962+
"--target",
963+
"macos",
964+
"--",
965+
"./tools/env",
966+
"-i",
967+
"pnpm",
968+
"--version",
969+
],
970+
);
971+
916972
const output = parseFakeCrabboxOutput(result);
917973
const remoteCommand = normalizeShellLineEndings(output.args.at(-1) ?? "");
918974
expect(result.status).toBe(0);
@@ -1027,7 +1083,7 @@ describe.concurrent("scripts/crabbox-wrapper", () => {
10271083
expect(remoteCommand.indexOf("-S|--split-string|-S*|--split-string=*)")).toBeLessThan(
10281084
remoteCommand.indexOf("-[!-]*i*)"),
10291085
);
1030-
expectGroupedShellCommand(remoteCommand, "/usr/bin/env -S 'pnpm --version'");
1086+
expectGroupedShellCommand(remoteCommand, "openclaw_crabbox_env -S 'pnpm --version'");
10311087
});
10321088

10331089
it("bootstraps Corepack for AWS macOS node changed-gate commands", () => {
@@ -2324,6 +2380,48 @@ describe.concurrent("scripts/crabbox-wrapper", () => {
23242380
);
23252381
});
23262382

2383+
it("preserves sparse changed-gate Git bootstrap for direct absolute env -i commands", () => {
2384+
const result = runWrapper(
2385+
"provider: hetzner, aws, local-container, blacksmith-testbox, or cloudflare\n",
2386+
["run", "--provider", "aws", "--", "/usr/bin/env", "-i", "pnpm", "check:changed"],
2387+
{
2388+
gitResponses: {
2389+
[GIT_CONFIG_SPARSE_KEY]: { stdout: "true\n" },
2390+
[GIT_STATUS_PORCELAIN_KEY]: { stdout: "" },
2391+
[GIT_MERGE_BASE_MAIN_HEAD_KEY]: { stdout: "abc123\n" },
2392+
},
2393+
},
2394+
);
2395+
2396+
const output = parseFakeCrabboxOutput(result);
2397+
const remoteCommand = normalizeShellLineEndings(output.args.at(-1) ?? "");
2398+
expect(result.status).toBe(0);
2399+
expect(output.args).toContain("--shell");
2400+
expect(remoteCommand).toContain("git init -q");
2401+
expect(remoteCommand).toMatch(
2402+
/&& \/usr\/bin\/env -i OPENCLAW_CHECK_CHANGED_REMOTE_CHILD=1 OPENCLAW_CHANGED_LANES_RAW_SYNC=1 CI=1 pnpm check:changed$/u,
2403+
);
2404+
});
2405+
2406+
it("does not mark custom env executables outside the sanitized env", () => {
2407+
const result = runWrapper(
2408+
"provider: hetzner, aws, local-container, blacksmith-testbox, or cloudflare\n",
2409+
["run", "--provider", "aws", "--", "./tools/env", "-i", "pnpm", "check:changed"],
2410+
{
2411+
gitResponses: {
2412+
[GIT_CONFIG_SPARSE_KEY]: { stdout: "true\n" },
2413+
[GIT_STATUS_PORCELAIN_KEY]: { stdout: "" },
2414+
[GIT_MERGE_BASE_MAIN_HEAD_KEY]: { stdout: "abc123\n" },
2415+
},
2416+
},
2417+
);
2418+
2419+
const output = parseFakeCrabboxOutput(result);
2420+
expect(result.status).toBe(0);
2421+
expect(output.args.join("\0")).not.toContain("OPENCLAW_CHECK_CHANGED_REMOTE_CHILD=1");
2422+
expect(output.args.join("\0")).not.toContain("git init -q");
2423+
});
2424+
23272425
it("does not mark assignment-prefixed env -i changed gates outside the sanitized env", () => {
23282426
const result = runWrapper(
23292427
"provider: hetzner, aws, local-container, blacksmith-testbox, or cloudflare\n",

0 commit comments

Comments
 (0)