fix(install): validate install smoke timing env

This commit is contained in:
Vincent Koc
2026-06-18 22:57:15 +02:00
parent a93fc87e2c
commit bfb47a03b3
2 changed files with 51 additions and 5 deletions
+31 -3
View File
@@ -1,6 +1,34 @@
#!/usr/bin/env bash
set -euo pipefail
read_positive_int_env() {
local name="${1:?missing environment variable name}"
local fallback="${2:?missing fallback value}"
local value="${!name-}"
if [[ -z "${!name+x}" ]]; then
value="$fallback"
fi
if [[ ! "$value" =~ ^[0-9]+$ ]] || (( 10#$value < 1 )); then
echo "invalid $name: $value" >&2
return 2
fi
printf "%s\n" "$((10#$value))"
}
read_nonnegative_int_env() {
local name="${1:?missing environment variable name}"
local fallback="${2:?missing fallback value}"
local value="${!name-}"
if [[ -z "${!name+x}" ]]; then
value="$fallback"
fi
if [[ ! "$value" =~ ^[0-9]+$ ]]; then
echo "invalid $name: $value" >&2
return 2
fi
printf "%s\n" "$((10#$value))"
}
INSTALL_URL="${OPENCLAW_INSTALL_URL:-https://openclaw.bot/install.sh}"
SMOKE_MODE="${OPENCLAW_INSTALL_SMOKE_MODE:-install}"
SMOKE_PREVIOUS_VERSION="${OPENCLAW_INSTALL_SMOKE_PREVIOUS:-}"
@@ -18,8 +46,8 @@ FRESHNESS_VERSION="${OPENCLAW_INSTALL_FRESHNESS_VERSION:-latest}"
# npm min-release-age is days; 10000 keeps the control failure independent of normal release cadence.
FRESHNESS_MIN_RELEASE_AGE="${OPENCLAW_INSTALL_FRESHNESS_MIN_RELEASE_AGE:-10000}"
FRESHNESS_NPM_VERSION="${OPENCLAW_INSTALL_FRESHNESS_NPM_VERSION:-11.14.1}"
HEARTBEAT_INTERVAL="${OPENCLAW_INSTALL_SMOKE_HEARTBEAT_INTERVAL:-60}"
INSTALL_COMMAND_TIMEOUT="${OPENCLAW_INSTALL_SMOKE_COMMAND_TIMEOUT:-900}"
HEARTBEAT_INTERVAL="$(read_nonnegative_int_env OPENCLAW_INSTALL_SMOKE_HEARTBEAT_INTERVAL 60)"
INSTALL_COMMAND_TIMEOUT="$(read_positive_int_env OPENCLAW_INSTALL_SMOKE_COMMAND_TIMEOUT 900)"
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
# shellcheck source=../install-sh-common/cli-verify.sh
@@ -75,7 +103,7 @@ run_with_heartbeat() {
local label="$1"
shift
local interval="$HEARTBEAT_INTERVAL"
if ! [[ "$interval" =~ ^[0-9]+$ ]] || [[ "$interval" == "0" ]]; then
if [[ "$interval" == "0" ]]; then
"$@"
return
fi
+20 -2
View File
@@ -473,11 +473,12 @@ describe("install-sh smoke runner", () => {
const script = readFileSync(SMOKE_RUNNER_PATH, "utf8");
expect(script).toContain(
'HEARTBEAT_INTERVAL="${OPENCLAW_INSTALL_SMOKE_HEARTBEAT_INTERVAL:-60}"',
'HEARTBEAT_INTERVAL="$(read_nonnegative_int_env OPENCLAW_INSTALL_SMOKE_HEARTBEAT_INTERVAL 60)"',
);
expect(script).toContain(
'INSTALL_COMMAND_TIMEOUT="${OPENCLAW_INSTALL_SMOKE_COMMAND_TIMEOUT:-900}"',
'INSTALL_COMMAND_TIMEOUT="$(read_positive_int_env OPENCLAW_INSTALL_SMOKE_COMMAND_TIMEOUT 900)"',
);
expect(script).toContain('if [[ "$interval" == "0" ]]; then');
expect(script).toContain("run_with_heartbeat");
expect(script).toContain("npm_install_global");
expect(script).toContain('timeout --kill-after=30s "${INSTALL_COMMAND_TIMEOUT}s"');
@@ -491,6 +492,23 @@ describe("install-sh smoke runner", () => {
expect(script).toContain("unterminated update JSON object");
});
it.each([
["command timeout", "OPENCLAW_INSTALL_SMOKE_COMMAND_TIMEOUT", "900s"],
["heartbeat interval", "OPENCLAW_INSTALL_SMOKE_HEARTBEAT_INTERVAL", "60s"],
])("rejects invalid install smoke %s before running npm", (_label, envName, value) => {
const result = spawnSync("bash", [SMOKE_RUNNER_PATH], {
encoding: "utf8",
env: {
...process.env,
[envName]: value,
},
});
expect(result.status).toBe(2);
expect(result.stderr).toContain(`invalid ${envName}: ${value}`);
expect(result.stderr).not.toContain("unsupported OPENCLAW_INSTALL_SMOKE_MODE");
});
it("covers plain npm global installs and npm-driven updates", () => {
const script = readFileSync(SCRIPT_PATH, "utf8");
const runner = readFileSync(SMOKE_RUNNER_PATH, "utf8");