mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-12 21:53:00 -06:00
fix(install): reject PATH runtimes with broken npm (#107825)
* fix(install): reject runtimes with broken npm * test(installer): use real Node for npm selection --------- Co-authored-by: Peter Steinberger <steipete@gmail.com>
This commit is contained in:
@@ -447,6 +447,7 @@ link_node_runtime_paths() {
|
||||
}
|
||||
|
||||
linked_node_is_usable() {
|
||||
local candidate_bin
|
||||
local current_version
|
||||
local required_version
|
||||
|
||||
@@ -462,6 +463,10 @@ linked_node_is_usable() {
|
||||
if ! semver_at_least "$current_version" "$required_version"; then
|
||||
return 1
|
||||
fi
|
||||
candidate_bin="$(node_dir)/bin"
|
||||
if ! PATH="${candidate_bin}:${PATH}" "$(npm_bin)" --version >/dev/null 2>&1; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
"$(node_bin)" -e '
|
||||
const { DatabaseSync } = require("node:sqlite");
|
||||
|
||||
@@ -641,6 +641,81 @@ describe("install-cli.sh", () => {
|
||||
}
|
||||
});
|
||||
|
||||
it("skips PATH Node runtimes whose npm command cannot start", () => {
|
||||
const tmp = mkdtempSync(join(tmpdir(), "openclaw-install-cli-broken-npm-"));
|
||||
const badBin = join(tmp, "bad-bin");
|
||||
const goodBin = join(tmp, "good-bin");
|
||||
const prefix = join(tmp, "prefix");
|
||||
const badNpmLog = join(tmp, "bad-npm.log");
|
||||
const goodNpmLog = join(tmp, "good-npm.log");
|
||||
const goodNodeLog = join(tmp, "good-node.log");
|
||||
const badNode = join(badBin, "node");
|
||||
const badNpm = join(badBin, "npm");
|
||||
const goodNode = join(goodBin, "node");
|
||||
const goodNpm = join(goodBin, "npm");
|
||||
|
||||
mkdirSync(badBin, { recursive: true });
|
||||
mkdirSync(goodBin, { recursive: true });
|
||||
symlinkSync(process.execPath, badNode);
|
||||
writeFileSync(
|
||||
goodNode,
|
||||
[
|
||||
"#!/bin/bash",
|
||||
'printf "%s\\n" "$*" >> "$GOOD_NODE_LOG"',
|
||||
`exec ${JSON.stringify(process.execPath)} "$@"`,
|
||||
"",
|
||||
].join("\n"),
|
||||
);
|
||||
writeFileSync(
|
||||
badNpm,
|
||||
["#!/bin/bash", 'printf "%s\\n" "$*" >> "$BAD_NPM_LOG"', "exit 42", ""].join("\n"),
|
||||
);
|
||||
writeFileSync(
|
||||
goodNpm,
|
||||
[
|
||||
"#!/usr/bin/env node",
|
||||
'require("node:fs").appendFileSync(',
|
||||
" process.env.GOOD_NPM_LOG,",
|
||||
' `${process.argv.slice(2).join(" ")}\\n`,',
|
||||
");",
|
||||
"",
|
||||
].join("\n"),
|
||||
);
|
||||
chmodSync(badNpm, 0o755);
|
||||
chmodSync(goodNode, 0o755);
|
||||
chmodSync(goodNpm, 0o755);
|
||||
|
||||
try {
|
||||
const result = runInstallCliShell(
|
||||
[
|
||||
"set -euo pipefail",
|
||||
`cd ${JSON.stringify(process.cwd())}`,
|
||||
`source ${JSON.stringify(SCRIPT_PATH)}`,
|
||||
`export PATH=${JSON.stringify(`${badBin}:${goodBin}:${process.env.PATH ?? ""}`)}`,
|
||||
`PREFIX=${JSON.stringify(prefix)}`,
|
||||
"try_link_usable_node_runtime_from_path",
|
||||
].join("\n"),
|
||||
{
|
||||
BAD_NPM_LOG: badNpmLog,
|
||||
GOOD_NPM_LOG: goodNpmLog,
|
||||
GOOD_NODE_LOG: goodNodeLog,
|
||||
},
|
||||
);
|
||||
|
||||
expect(result.status).toBe(0);
|
||||
const nodeLink = join(prefix, "tools", "node-v24.15.0", "bin", "node");
|
||||
const npmLink = join(prefix, "tools", "node-v24.15.0", "bin", "npm");
|
||||
expect(readFileSync(badNpmLog, "utf8")).toBe("--version\n");
|
||||
expect(readFileSync(goodNpmLog, "utf8")).toBe("--version\n");
|
||||
expect(readFileSync(goodNodeLog, "utf8")).toContain("npm --version");
|
||||
expect(lstatSync(nodeLink).isSymbolicLink()).toBe(true);
|
||||
expect(readlinkSync(nodeLink)).toBe(goodNode);
|
||||
expect(readlinkSync(npmLink)).toBe(goodNpm);
|
||||
} finally {
|
||||
rmSync(tmp, { force: true, recursive: true });
|
||||
}
|
||||
});
|
||||
|
||||
it("rejects Alpine/musl Node packages below the requested runtime floor", () => {
|
||||
const tmp = mkdtempSync(join(tmpdir(), "openclaw-install-cli-alpine-old-node-"));
|
||||
const bin = join(tmp, "bin");
|
||||
|
||||
Reference in New Issue
Block a user