mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-27 21:52:08 +00:00
fix(installer): reject stale cli node runtimes
This commit is contained in:
@@ -749,7 +749,6 @@ install_node() {
|
||||
local url
|
||||
local tmp
|
||||
local dir
|
||||
local current_major
|
||||
local base_url
|
||||
local tarball
|
||||
local expected_sha
|
||||
@@ -764,12 +763,9 @@ install_node() {
|
||||
return
|
||||
fi
|
||||
|
||||
if [[ -x "$(node_bin)" ]]; then
|
||||
current_major="$("$(node_bin)" -v 2>/dev/null | tr -d 'v' | cut -d'.' -f1 || echo "")"
|
||||
if [[ -n "$current_major" && "$current_major" -ge 22 ]]; then
|
||||
emit_json "{\"event\":\"step\",\"name\":\"node\",\"status\":\"skip\",\"path\":\"${dir//\"/\\\\\\\"}\"}"
|
||||
return
|
||||
fi
|
||||
if linked_node_is_usable; then
|
||||
emit_json "{\"event\":\"step\",\"name\":\"node\",\"status\":\"skip\",\"path\":\"${dir//\"/\\\\\\\"}\"}"
|
||||
return
|
||||
fi
|
||||
|
||||
emit_json "{\"event\":\"step\",\"name\":\"node\",\"status\":\"start\",\"version\":\"${NODE_VERSION}\"}"
|
||||
@@ -803,8 +799,12 @@ install_node() {
|
||||
|
||||
ln -sfn "$dir" "${PREFIX}/tools/node"
|
||||
|
||||
if ! "$(node_bin)" -e "require('node:sqlite')" >/dev/null 2>&1; then
|
||||
fail "Installed Node ${NODE_VERSION} is missing node:sqlite; re-run with --node-version 22.22.0 (or newer)"
|
||||
if ! linked_node_is_usable; then
|
||||
local installed_version
|
||||
local required_version
|
||||
installed_version="$("$(node_bin)" -v 2>/dev/null || echo unknown)"
|
||||
required_version="$(required_node_version)"
|
||||
fail "Installed Node ${NODE_VERSION} must provide Node >= ${required_version} with node:sqlite; found ${installed_version}. Re-run with --node-version 22.22.0 (or newer)"
|
||||
fi
|
||||
emit_json "{\"event\":\"step\",\"name\":\"node\",\"status\":\"ok\",\"version\":\"${NODE_VERSION}\"}"
|
||||
}
|
||||
|
||||
@@ -557,6 +557,173 @@ describe("install-cli.sh", () => {
|
||||
}
|
||||
});
|
||||
|
||||
it("replaces cached generic Node runtimes below the runtime floor", () => {
|
||||
const tmp = mkdtempSync(join(tmpdir(), "openclaw-install-cli-generic-stale-node-"));
|
||||
const prefix = join(tmp, "prefix");
|
||||
const nodePrefixBin = join(prefix, "tools", "node-v22.22.0", "bin");
|
||||
const staleNode = join(nodePrefixBin, "node");
|
||||
const staleNpm = join(nodePrefixBin, "npm");
|
||||
const newNode = join(tmp, "new-node");
|
||||
const newNpm = join(tmp, "new-npm");
|
||||
|
||||
mkdirSync(nodePrefixBin, { recursive: true });
|
||||
writeFileSync(
|
||||
staleNode,
|
||||
[
|
||||
"#!/bin/bash",
|
||||
'if [[ "${1:-}" == "-v" ]]; then',
|
||||
" printf 'v22.18.0\\n'",
|
||||
" exit 0",
|
||||
"fi",
|
||||
'if [[ "${1:-}" == "-e" ]]; then',
|
||||
" exit 0",
|
||||
"fi",
|
||||
"exit 0",
|
||||
"",
|
||||
].join("\n"),
|
||||
);
|
||||
writeFileSync(staleNpm, ["#!/bin/bash", "exit 0", ""].join("\n"));
|
||||
writeFileSync(
|
||||
newNode,
|
||||
[
|
||||
"#!/bin/bash",
|
||||
'if [[ "${1:-}" == "-v" ]]; then',
|
||||
" printf 'v22.22.0\\n'",
|
||||
" exit 0",
|
||||
"fi",
|
||||
'if [[ "${1:-}" == "-e" ]]; then',
|
||||
" exit 0",
|
||||
"fi",
|
||||
"exit 0",
|
||||
"",
|
||||
].join("\n"),
|
||||
);
|
||||
writeFileSync(newNpm, ["#!/bin/bash", "exit 0", ""].join("\n"));
|
||||
chmodSync(staleNode, 0o755);
|
||||
chmodSync(staleNpm, 0o755);
|
||||
chmodSync(newNode, 0o755);
|
||||
chmodSync(newNpm, 0o755);
|
||||
|
||||
try {
|
||||
const result = runInstallCliShell(
|
||||
[
|
||||
"set -euo pipefail",
|
||||
`cd ${JSON.stringify(process.cwd())}`,
|
||||
`source ${JSON.stringify(SCRIPT_PATH)}`,
|
||||
"os_detect() { printf 'linux\\n'; }",
|
||||
"arch_detect() { printf 'x64\\n'; }",
|
||||
"is_musl_linux() { return 1; }",
|
||||
"detect_downloader() { :; }",
|
||||
"require_bin() { :; }",
|
||||
"download_file() {",
|
||||
' case "$1" in',
|
||||
" */SHASUMS256.txt) printf 'fixture-sha node-v22.22.0-linux-x64.tar.gz\\n' > \"$2\" ;;",
|
||||
" *) printf 'node tarball fixture\\n' > \"$2\" ;;",
|
||||
" esac",
|
||||
"}",
|
||||
"sha256_file() { printf 'fixture-sha\\n'; }",
|
||||
"tar() {",
|
||||
" local dest=''",
|
||||
" while [[ $# -gt 0 ]]; do",
|
||||
' if [[ "$1" == \'-C\' ]]; then dest="$2"; shift 2; else shift; fi',
|
||||
" done",
|
||||
' mkdir -p "$dest/bin"',
|
||||
' cp "$NEW_NODE" "$dest/bin/node"',
|
||||
' cp "$NEW_NPM" "$dest/bin/npm"',
|
||||
"}",
|
||||
`PREFIX=${JSON.stringify(prefix)}`,
|
||||
"NODE_VERSION=22.22.0",
|
||||
"NODE_VERSION_REQUESTED=1",
|
||||
"install_node",
|
||||
].join("\n"),
|
||||
{
|
||||
NEW_NODE: newNode,
|
||||
NEW_NPM: newNpm,
|
||||
},
|
||||
);
|
||||
|
||||
expect(result.status).toBe(0);
|
||||
expect(result.stdout).toContain("Installing Node 22.22.0 (user-space)");
|
||||
expect(result.stdout).not.toContain('"status":"skip"');
|
||||
expect(readFileSync(staleNode, "utf8")).toContain("v22.22.0");
|
||||
} finally {
|
||||
rmSync(tmp, { force: true, recursive: true });
|
||||
}
|
||||
});
|
||||
|
||||
it("rejects downloaded generic Node runtimes below the runtime floor", () => {
|
||||
const tmp = mkdtempSync(join(tmpdir(), "openclaw-install-cli-generic-old-node-"));
|
||||
const prefix = join(tmp, "prefix");
|
||||
const newNode = join(tmp, "new-node");
|
||||
const newNpm = join(tmp, "new-npm");
|
||||
|
||||
writeFileSync(
|
||||
newNode,
|
||||
[
|
||||
"#!/bin/bash",
|
||||
'if [[ "${1:-}" == "-v" ]]; then',
|
||||
" printf 'v22.18.0\\n'",
|
||||
" exit 0",
|
||||
"fi",
|
||||
'if [[ "${1:-}" == "-e" ]]; then',
|
||||
" exit 0",
|
||||
"fi",
|
||||
"exit 0",
|
||||
"",
|
||||
].join("\n"),
|
||||
);
|
||||
writeFileSync(newNpm, ["#!/bin/bash", "exit 0", ""].join("\n"));
|
||||
chmodSync(newNode, 0o755);
|
||||
chmodSync(newNpm, 0o755);
|
||||
|
||||
try {
|
||||
const result = runInstallCliShell(
|
||||
[
|
||||
"set -euo pipefail",
|
||||
`cd ${JSON.stringify(process.cwd())}`,
|
||||
`source ${JSON.stringify(SCRIPT_PATH)}`,
|
||||
"os_detect() { printf 'linux\\n'; }",
|
||||
"arch_detect() { printf 'x64\\n'; }",
|
||||
"is_musl_linux() { return 1; }",
|
||||
"detect_downloader() { :; }",
|
||||
"require_bin() { :; }",
|
||||
"download_file() {",
|
||||
' case "$1" in',
|
||||
" */SHASUMS256.txt) printf 'fixture-sha node-v22.18.0-linux-x64.tar.gz\\n' > \"$2\" ;;",
|
||||
" *) printf 'node tarball fixture\\n' > \"$2\" ;;",
|
||||
" esac",
|
||||
"}",
|
||||
"sha256_file() { printf 'fixture-sha\\n'; }",
|
||||
"tar() {",
|
||||
" local dest=''",
|
||||
" while [[ $# -gt 0 ]]; do",
|
||||
' if [[ "$1" == \'-C\' ]]; then dest="$2"; shift 2; else shift; fi',
|
||||
" done",
|
||||
' mkdir -p "$dest/bin"',
|
||||
' cp "$NEW_NODE" "$dest/bin/node"',
|
||||
' cp "$NEW_NPM" "$dest/bin/npm"',
|
||||
"}",
|
||||
`PREFIX=${JSON.stringify(prefix)}`,
|
||||
"NODE_VERSION=22.18.0",
|
||||
"NODE_VERSION_REQUESTED=1",
|
||||
"install_node",
|
||||
].join("\n"),
|
||||
{
|
||||
NEW_NODE: newNode,
|
||||
NEW_NPM: newNpm,
|
||||
},
|
||||
);
|
||||
|
||||
expect(result.status).toBe(1);
|
||||
expect(result.stdout).toContain(
|
||||
"Installed Node 22.18.0 must provide Node >= 22.19.0 with node:sqlite",
|
||||
);
|
||||
expect(result.stdout).toContain("found v22.18.0");
|
||||
} finally {
|
||||
rmSync(tmp, { force: true, recursive: true });
|
||||
}
|
||||
});
|
||||
|
||||
it("clears npm freshness filters for package installs", () => {
|
||||
expect(script).toContain('freshness_flag="--min-release-age=0"');
|
||||
expect(script).toContain('npm_config_has_raw_key "$(npm_bin)" "min-release-age"');
|
||||
|
||||
Reference in New Issue
Block a user