mirror of
https://github.com/openclaw/openclaw.git
synced 2026-06-06 05:51:15 +08:00
fix(installer): avoid before with npm release-age configs (#85491)
Summary: - The PR updates the Unix installers to avoid emitting npm `--before` when raw npm config contains `min-releas ... records a changelog fix, and widens an internal model-catalog test helper type to accept sync auth checks. - PR surface: Source +1, Tests +421, Docs +1, Other +150. Total +573 across 7 files. - Reproducibility: yes. The linked report at https://github.com/openclaw/openclaw/issues/84743 gives an isolat ... exclusivity, and current main still has the source path that can generate the conflicting `--before` flag. Automerge notes: - PR branch already contained follow-up commit before automerge: fix(installer): avoid before with npm release-age configs - PR branch already contained follow-up commit before automerge: fix(clawsweeper): address review for automerge-openclaw-openclaw-8549… Validation: - ClawSweeper review passed for headfb0762f468. - Required merge gates passed before the squash merge. Prepared head SHA:fb0762f468Review: https://github.com/openclaw/openclaw/pull/85491#issuecomment-4522229812 Co-authored-by: Andy Ye <35905412+TurboTheTurtle@users.noreply.github.com> Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com> Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com> Approved-by: takhoffman Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { spawnSync } from "node:child_process";
|
||||
import { mkdtempSync, mkdirSync, readFileSync, rmSync } from "node:fs";
|
||||
import { chmodSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import { describe, expect, it } from "vitest";
|
||||
@@ -127,10 +127,229 @@ describe("install-cli.sh", () => {
|
||||
|
||||
it("clears npm freshness filters for package installs", () => {
|
||||
expect(script).toContain('freshness_flag="--min-release-age=0"');
|
||||
expect(script).toContain('npm_raw_config_has_key "min-release-age"');
|
||||
expect(script).toContain('freshness_flag="--before=$(date -u');
|
||||
expect(script).toContain("env -u NPM_CONFIG_BEFORE -u npm_config_before");
|
||||
});
|
||||
|
||||
it("does not emit --before when raw user npmrc config contains min-release-age", () => {
|
||||
const tmp = mkdtempSync(join(tmpdir(), "openclaw-install-cli-npmrc-"));
|
||||
const bin = join(tmp, "bin");
|
||||
const npmrc = join(tmp, "user.npmrc");
|
||||
const installArgs = join(tmp, "npm-install-args.txt");
|
||||
const prefix = join(tmp, "prefix");
|
||||
const nodeDir = join(tmp, "node");
|
||||
mkdirSync(bin, { recursive: true });
|
||||
mkdirSync(nodeDir, { recursive: true });
|
||||
writeFileSync(npmrc, "min-release-age=7\n");
|
||||
const fakeNpm = join(bin, "npm");
|
||||
writeFileSync(
|
||||
fakeNpm,
|
||||
[
|
||||
"#!/usr/bin/env bash",
|
||||
'if [[ "$1" == "config" && "$2" == "get" ]]; then',
|
||||
' if [[ "$3" == "min-release-age" ]]; then',
|
||||
" printf 'null\\n'",
|
||||
" exit 0",
|
||||
" fi",
|
||||
' if [[ "$3" == "before" ]]; then',
|
||||
" printf '2026-01-01T00:00:00.000Z\\n'",
|
||||
" exit 0",
|
||||
" fi",
|
||||
"fi",
|
||||
'printf "%s\\n" "$@" > "$NPM_FAKE_INSTALL_ARGS"',
|
||||
"exit 0",
|
||||
"",
|
||||
].join("\n"),
|
||||
);
|
||||
chmodSync(fakeNpm, 0o755);
|
||||
|
||||
try {
|
||||
const result = runInstallCliShell(
|
||||
[
|
||||
"set -euo pipefail",
|
||||
`cd ${JSON.stringify(process.cwd())}`,
|
||||
`source ${JSON.stringify(SCRIPT_PATH)}`,
|
||||
`npm_bin() { printf '%s\\n' ${JSON.stringify(fakeNpm)}; }`,
|
||||
`node_dir() { printf '%s\\n' ${JSON.stringify(nodeDir)}; }`,
|
||||
"emit_json() { :; }",
|
||||
"log() { :; }",
|
||||
`PREFIX=${JSON.stringify(prefix)}`,
|
||||
"SET_NPM_PREFIX=0",
|
||||
"OPENCLAW_VERSION=1.2.3",
|
||||
"install_openclaw",
|
||||
].join("\n"),
|
||||
{
|
||||
NPM_CONFIG_USERCONFIG: npmrc,
|
||||
NPM_FAKE_INSTALL_ARGS: installArgs,
|
||||
PATH: `${bin}:${process.env.PATH}`,
|
||||
},
|
||||
);
|
||||
|
||||
expect(result.status).toBe(0);
|
||||
expect(readFileSync(installArgs, "utf8")).toContain("--min-release-age=0\n");
|
||||
expect(readFileSync(installArgs, "utf8")).not.toContain("--before=");
|
||||
} finally {
|
||||
rmSync(tmp, { force: true, recursive: true });
|
||||
}
|
||||
});
|
||||
|
||||
it("does not emit --before when default global npmrc config contains min-release-age", () => {
|
||||
const tmp = mkdtempSync(join(tmpdir(), "openclaw-install-cli-global-npmrc-"));
|
||||
const bin = join(tmp, "bin");
|
||||
const home = join(tmp, "home");
|
||||
const prefix = join(tmp, "prefix");
|
||||
const npmrc = join(prefix, "etc", "npmrc");
|
||||
const calls = join(tmp, "npm-calls.txt");
|
||||
const installArgs = join(tmp, "npm-install-args.txt");
|
||||
const installPrefix = join(tmp, "install-prefix");
|
||||
const nodeDir = join(tmp, "node");
|
||||
mkdirSync(bin, { recursive: true });
|
||||
mkdirSync(home, { recursive: true });
|
||||
mkdirSync(nodeDir, { recursive: true });
|
||||
mkdirSync(join(prefix, "etc"), { recursive: true });
|
||||
writeFileSync(npmrc, "min-release-age=7\n");
|
||||
const fakeNpm = join(bin, "npm");
|
||||
writeFileSync(
|
||||
fakeNpm,
|
||||
[
|
||||
"#!/usr/bin/env bash",
|
||||
'printf "%s\\n" "$*" >> "$NPM_FAKE_CALLS"',
|
||||
'if [[ "$1" == "config" && "$2" == "get" ]]; then',
|
||||
' if [[ "$3" == "min-release-age" ]]; then',
|
||||
" printf 'null\\n'",
|
||||
" exit 0",
|
||||
" fi",
|
||||
' if [[ "$3" == "globalconfig" ]]; then',
|
||||
' printf "%s\\n" "$NPM_FAKE_GLOBALCONFIG"',
|
||||
" exit 0",
|
||||
" fi",
|
||||
' if [[ "$3" == "before" ]]; then',
|
||||
" printf '2026-01-01T00:00:00.000Z\\n'",
|
||||
" exit 0",
|
||||
" fi",
|
||||
"fi",
|
||||
'printf "%s\\n" "$@" > "$NPM_FAKE_INSTALL_ARGS"',
|
||||
"exit 0",
|
||||
"",
|
||||
].join("\n"),
|
||||
);
|
||||
chmodSync(fakeNpm, 0o755);
|
||||
|
||||
try {
|
||||
const result = runInstallCliShell(
|
||||
[
|
||||
"set -euo pipefail",
|
||||
`cd ${JSON.stringify(process.cwd())}`,
|
||||
`source ${JSON.stringify(SCRIPT_PATH)}`,
|
||||
`npm_bin() { printf '%s\\n' ${JSON.stringify(fakeNpm)}; }`,
|
||||
`node_dir() { printf '%s\\n' ${JSON.stringify(nodeDir)}; }`,
|
||||
"emit_json() { :; }",
|
||||
"log() { :; }",
|
||||
`PREFIX=${JSON.stringify(installPrefix)}`,
|
||||
"SET_NPM_PREFIX=0",
|
||||
"OPENCLAW_VERSION=1.2.3",
|
||||
"install_openclaw",
|
||||
].join("\n"),
|
||||
{
|
||||
HOME: home,
|
||||
NPM_CONFIG_GLOBALCONFIG: undefined,
|
||||
NPM_CONFIG_PREFIX: undefined,
|
||||
npm_config_globalconfig: undefined,
|
||||
npm_config_prefix: undefined,
|
||||
NPM_FAKE_CALLS: calls,
|
||||
NPM_FAKE_GLOBALCONFIG: npmrc,
|
||||
NPM_FAKE_INSTALL_ARGS: installArgs,
|
||||
PATH: `${bin}:${process.env.PATH}`,
|
||||
},
|
||||
);
|
||||
|
||||
expect(result.status).toBe(0);
|
||||
expect(readFileSync(installArgs, "utf8")).toContain("--min-release-age=0\n");
|
||||
expect(readFileSync(installArgs, "utf8")).not.toContain("--before=");
|
||||
expect(readFileSync(calls, "utf8")).not.toContain("config get before");
|
||||
} finally {
|
||||
rmSync(tmp, { force: true, recursive: true });
|
||||
}
|
||||
});
|
||||
|
||||
it("does not emit --before when builtin npmrc config contains min-release-age", () => {
|
||||
const tmp = mkdtempSync(join(tmpdir(), "openclaw-install-cli-builtin-npmrc-"));
|
||||
const bin = join(tmp, "bin");
|
||||
const home = join(tmp, "home");
|
||||
const npmrc = join(tmp, "npmrc");
|
||||
const calls = join(tmp, "npm-calls.txt");
|
||||
const installArgs = join(tmp, "npm-install-args.txt");
|
||||
const installPrefix = join(tmp, "install-prefix");
|
||||
const nodeDir = join(tmp, "node");
|
||||
mkdirSync(bin, { recursive: true });
|
||||
mkdirSync(home, { recursive: true });
|
||||
mkdirSync(nodeDir, { recursive: true });
|
||||
writeFileSync(npmrc, "min-release-age=7\n");
|
||||
const fakeNpm = join(bin, "npm");
|
||||
writeFileSync(
|
||||
fakeNpm,
|
||||
[
|
||||
"#!/usr/bin/env bash",
|
||||
'printf "%s\\n" "$*" >> "$NPM_FAKE_CALLS"',
|
||||
'if [[ "$1" == "config" && "$2" == "get" ]]; then',
|
||||
' if [[ "$3" == "min-release-age" ]]; then',
|
||||
" printf 'null\\n'",
|
||||
" exit 0",
|
||||
" fi",
|
||||
' if [[ "$3" == "globalconfig" ]]; then',
|
||||
' printf "%s\\n" "$NPM_FAKE_GLOBALCONFIG"',
|
||||
" exit 0",
|
||||
" fi",
|
||||
' if [[ "$3" == "before" ]]; then',
|
||||
" printf '2026-01-01T00:00:00.000Z\\n'",
|
||||
" exit 0",
|
||||
" fi",
|
||||
"fi",
|
||||
'printf "%s\\n" "$@" > "$NPM_FAKE_INSTALL_ARGS"',
|
||||
"exit 0",
|
||||
"",
|
||||
].join("\n"),
|
||||
);
|
||||
chmodSync(fakeNpm, 0o755);
|
||||
|
||||
try {
|
||||
const result = runInstallCliShell(
|
||||
[
|
||||
"set -euo pipefail",
|
||||
`cd ${JSON.stringify(process.cwd())}`,
|
||||
`source ${JSON.stringify(SCRIPT_PATH)}`,
|
||||
`npm_bin() { printf '%s\\n' ${JSON.stringify(fakeNpm)}; }`,
|
||||
`node_dir() { printf '%s\\n' ${JSON.stringify(nodeDir)}; }`,
|
||||
"emit_json() { :; }",
|
||||
"log() { :; }",
|
||||
`PREFIX=${JSON.stringify(installPrefix)}`,
|
||||
"SET_NPM_PREFIX=0",
|
||||
"OPENCLAW_VERSION=1.2.3",
|
||||
"install_openclaw",
|
||||
].join("\n"),
|
||||
{
|
||||
HOME: home,
|
||||
NPM_CONFIG_GLOBALCONFIG: undefined,
|
||||
NPM_CONFIG_PREFIX: undefined,
|
||||
npm_config_globalconfig: undefined,
|
||||
npm_config_prefix: undefined,
|
||||
NPM_FAKE_CALLS: calls,
|
||||
NPM_FAKE_GLOBALCONFIG: join(tmp, "missing-global-npmrc"),
|
||||
NPM_FAKE_INSTALL_ARGS: installArgs,
|
||||
PATH: `${bin}:${process.env.PATH}`,
|
||||
},
|
||||
);
|
||||
|
||||
expect(result.status).toBe(0);
|
||||
expect(readFileSync(installArgs, "utf8")).toContain("--min-release-age=0\n");
|
||||
expect(readFileSync(installArgs, "utf8")).not.toContain("--before=");
|
||||
expect(readFileSync(calls, "utf8")).not.toContain("config get before");
|
||||
} finally {
|
||||
rmSync(tmp, { force: true, recursive: true });
|
||||
}
|
||||
});
|
||||
|
||||
it("rejects OpenClaw GitHub source targets for npm installs", () => {
|
||||
const result = runInstallCliShell(`
|
||||
set -euo pipefail
|
||||
|
||||
Reference in New Issue
Block a user