mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 09:10:45 +00:00
fix: harden parallels update smoke
This commit is contained in:
@@ -48,7 +48,7 @@ BUILD_LOCK_DIR="${TMPDIR:-/tmp}/openclaw-parallels-build.lock"
|
||||
TIMEOUT_INSTALL_SITE_S=420
|
||||
TIMEOUT_INSTALL_TGZ_S=420
|
||||
TIMEOUT_INSTALL_REGISTRY_S=420
|
||||
TIMEOUT_UPDATE_DEV_S="${OPENCLAW_PARALLELS_MACOS_UPDATE_DEV_TIMEOUT_S:-600}"
|
||||
TIMEOUT_UPDATE_DEV_S="${OPENCLAW_PARALLELS_MACOS_UPDATE_DEV_TIMEOUT_S:-1200}"
|
||||
TIMEOUT_VERIFY_S=60
|
||||
TIMEOUT_ONBOARD_S=180
|
||||
TIMEOUT_GATEWAY_S=180
|
||||
@@ -796,6 +796,31 @@ guest_current_user_tail_file() {
|
||||
guest_current_user_exec /usr/bin/tail -n "$lines" "$file_path"
|
||||
}
|
||||
|
||||
guest_current_user_kill_process_tree() {
|
||||
local pid="$1"
|
||||
[[ "$pid" =~ ^[0-9]+$ ]] || return 0
|
||||
guest_current_user_sh "$(cat <<EOF
|
||||
kill_tree() {
|
||||
local target="\$1" child
|
||||
for child in \$(/usr/bin/pgrep -P "\$target" 2>/dev/null || true); do
|
||||
kill_tree "\$child"
|
||||
done
|
||||
/bin/kill -TERM "\$target" 2>/dev/null || true
|
||||
}
|
||||
kill_tree $(shell_quote "$pid")
|
||||
/bin/sleep 2
|
||||
kill_tree_force() {
|
||||
local target="\$1" child
|
||||
for child in \$(/usr/bin/pgrep -P "\$target" 2>/dev/null || true); do
|
||||
kill_tree_force "\$child"
|
||||
done
|
||||
/bin/kill -KILL "\$target" 2>/dev/null || true
|
||||
}
|
||||
kill_tree_force $(shell_quote "$pid")
|
||||
EOF
|
||||
)" >/dev/null 2>&1 || true
|
||||
}
|
||||
|
||||
latest_guest_npm_debug_log_path() {
|
||||
local guest_home="$1"
|
||||
guest_current_user_sh "$(cat <<EOF
|
||||
@@ -880,11 +905,12 @@ run_logged_guest_current_user_sh() {
|
||||
local timeout_s="$4"
|
||||
local runner_path="$5"
|
||||
local deadline rc done_rc runner_body write_runner_cmd
|
||||
local guest_home guest_log_state_path latest_npm_log_path latest_npm_log_state_path npm_state_path
|
||||
local guest_home guest_log_state_path latest_npm_log_path latest_npm_log_state_path npm_state_path runner_pid_path runner_pid
|
||||
rc=""
|
||||
done_rc=""
|
||||
latest_npm_log_path=""
|
||||
guest_current_user_exec /bin/rm -f "$log_path" "$done_path" "$runner_path"
|
||||
runner_pid_path="$done_path.pid"
|
||||
guest_current_user_exec /bin/rm -f "$log_path" "$done_path" "$runner_path" "$runner_pid_path"
|
||||
runner_body="$(cat <<EOF
|
||||
status=0
|
||||
(
|
||||
@@ -906,7 +932,7 @@ EOF
|
||||
write_runner_cmd+="$runner_body"$'\n'
|
||||
write_runner_cmd+="__OPENCLAW_RUNNER__"$'\n'
|
||||
write_runner_cmd+="/bin/chmod +x $(shell_quote "$runner_path")"$'\n'
|
||||
write_runner_cmd+="(/bin/bash $(shell_quote "$runner_path") > $(shell_quote "$log_path") 2>&1 < /dev/null &) >/dev/null 2>&1"
|
||||
write_runner_cmd+="(/bin/bash $(shell_quote "$runner_path") > $(shell_quote "$log_path") 2>&1 < /dev/null & printf '%s\n' \"\$!\" > $(shell_quote "$runner_pid_path")) >/dev/null 2>&1"
|
||||
guest_current_user_sh "$write_runner_cmd"
|
||||
guest_home="$(resolve_guest_current_user_home)"
|
||||
guest_log_state_path="$(mktemp "${TMPDIR:-/tmp}/openclaw-guest-log-state.XXXXXX")"
|
||||
@@ -936,7 +962,7 @@ print(matches[-1])
|
||||
PY
|
||||
)" || rc=""
|
||||
if [[ "$rc" =~ ^-?[0-9]+$ ]]; then
|
||||
guest_current_user_exec /bin/rm -f "$done_path" "$runner_path" >/dev/null 2>&1 || true
|
||||
guest_current_user_exec /bin/rm -f "$done_path" "$runner_path" "$runner_pid_path" >/dev/null 2>&1 || true
|
||||
stream_guest_file_delta "$log_path" "$guest_log_state_path" ""
|
||||
if [[ -n "$latest_npm_log_path" ]]; then
|
||||
stream_guest_file_delta "$latest_npm_log_path" "$latest_npm_log_state_path" "npm-debug: "
|
||||
@@ -957,7 +983,7 @@ PY
|
||||
done_rc="$(guest_current_user_exec /bin/cat "$done_path" 2>/dev/null | tr -d '\r\n' || true)"
|
||||
if [[ "$done_rc" =~ ^-?[0-9]+$ ]]; then
|
||||
rc="$done_rc"
|
||||
guest_current_user_exec /bin/rm -f "$done_path" "$runner_path" >/dev/null 2>&1 || true
|
||||
guest_current_user_exec /bin/rm -f "$done_path" "$runner_path" "$runner_pid_path" >/dev/null 2>&1 || true
|
||||
stream_guest_file_delta "$log_path" "$guest_log_state_path" ""
|
||||
if [[ -n "$latest_npm_log_path" ]]; then
|
||||
stream_guest_file_delta "$latest_npm_log_path" "$latest_npm_log_state_path" "npm-debug: "
|
||||
@@ -968,7 +994,7 @@ PY
|
||||
fi
|
||||
rc="$(guest_runner_rc_from_log "$log_path" 2>/dev/null || true)"
|
||||
if [[ "$rc" =~ ^-?[0-9]+$ ]]; then
|
||||
guest_current_user_exec /bin/rm -f "$done_path" "$runner_path" >/dev/null 2>&1 || true
|
||||
guest_current_user_exec /bin/rm -f "$done_path" "$runner_path" "$runner_pid_path" >/dev/null 2>&1 || true
|
||||
stream_guest_file_delta "$log_path" "$guest_log_state_path" ""
|
||||
if [[ -n "$latest_npm_log_path" ]]; then
|
||||
stream_guest_file_delta "$latest_npm_log_path" "$latest_npm_log_state_path" "npm-debug: "
|
||||
@@ -979,6 +1005,12 @@ PY
|
||||
fi
|
||||
sleep 2
|
||||
done
|
||||
runner_pid="$(guest_current_user_exec /bin/cat "$runner_pid_path" 2>/dev/null | tr -d '\r\n' || true)"
|
||||
if [[ "$runner_pid" =~ ^[0-9]+$ ]]; then
|
||||
warn "terminating timed-out guest runner pid $runner_pid"
|
||||
guest_current_user_kill_process_tree "$runner_pid"
|
||||
fi
|
||||
guest_current_user_exec /bin/rm -f "$done_path" "$runner_path" "$runner_pid_path" >/dev/null 2>&1 || true
|
||||
rm -f "$guest_log_state_path" "$latest_npm_log_state_path" "$npm_state_path"
|
||||
warn "guest script timed out after ${timeout_s}s"
|
||||
guest_current_user_tail_file "$log_path" 120 >&2 || true
|
||||
|
||||
@@ -18,6 +18,7 @@ describe("package dist inventory", () => {
|
||||
|
||||
await expect(writePackageDistInventory(packageRoot)).resolves.toEqual([
|
||||
"dist/current-BR6xv1a1.js",
|
||||
"dist/extensions/qa-channel/runtime-api.js",
|
||||
]);
|
||||
await expect(collectPackageDistInventoryErrors(packageRoot)).resolves.toEqual([]);
|
||||
|
||||
@@ -134,7 +135,9 @@ describe("package dist inventory", () => {
|
||||
);
|
||||
await fs.writeFile(omittedMap, "{}", "utf8");
|
||||
|
||||
await expect(writePackageDistInventory(packageRoot)).resolves.toEqual([]);
|
||||
await expect(writePackageDistInventory(packageRoot)).resolves.toEqual([
|
||||
"dist/extensions/qa-channel/runtime-api.js",
|
||||
]);
|
||||
});
|
||||
});
|
||||
it("fails closed when the inventory is missing", async () => {
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import fs from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import { NPM_UPDATE_COMPAT_SIDECAR_PATHS } from "./npm-update-compat-sidecars.js";
|
||||
|
||||
export const PACKAGE_DIST_INVENTORY_RELATIVE_PATH = "dist/postinstall-inventory.json";
|
||||
const LEGACY_VERIFIER_COMPAT_INVENTORY_PATHS = ["dist/extensions/qa-channel/runtime-api.js"];
|
||||
const LEGACY_QA_LAB_DIR = ["qa", "lab"].join("-");
|
||||
const OMITTED_QA_EXTENSION_PREFIXES = [
|
||||
"dist/extensions/qa-channel/",
|
||||
@@ -46,6 +48,9 @@ function isPackagedDistPath(relativePath: string): boolean {
|
||||
if (relativePath === "dist/plugin-sdk/.tsbuildinfo") {
|
||||
return false;
|
||||
}
|
||||
if (LEGACY_VERIFIER_COMPAT_INVENTORY_PATHS.includes(relativePath)) {
|
||||
return true;
|
||||
}
|
||||
if (
|
||||
OMITTED_PRIVATE_QA_PLUGIN_SDK_PREFIXES.some((prefix) => relativePath.startsWith(prefix)) ||
|
||||
OMITTED_PRIVATE_QA_PLUGIN_SDK_FILES.has(relativePath) ||
|
||||
@@ -106,7 +111,12 @@ export async function collectPackageDistInventory(packageRoot: string): Promise<
|
||||
}
|
||||
|
||||
export async function writePackageDistInventory(packageRoot: string): Promise<string[]> {
|
||||
const inventory = await collectPackageDistInventory(packageRoot);
|
||||
const inventory = [
|
||||
...new Set([
|
||||
...(await collectPackageDistInventory(packageRoot)),
|
||||
...LEGACY_VERIFIER_COMPAT_INVENTORY_PATHS,
|
||||
]),
|
||||
].toSorted((left, right) => left.localeCompare(right));
|
||||
const inventoryPath = path.join(packageRoot, PACKAGE_DIST_INVENTORY_RELATIVE_PATH);
|
||||
await fs.mkdir(path.dirname(inventoryPath), { recursive: true });
|
||||
await fs.writeFile(inventoryPath, `${JSON.stringify(inventory, null, 2)}\n`, "utf8");
|
||||
@@ -151,6 +161,9 @@ export async function collectPackageDistInventoryErrors(packageRoot: string): Pr
|
||||
|
||||
for (const relativePath of expectedFiles) {
|
||||
if (!actualSet.has(relativePath)) {
|
||||
if (NPM_UPDATE_COMPAT_SIDECAR_PATHS.has(relativePath)) {
|
||||
continue;
|
||||
}
|
||||
errors.push(`missing packaged dist file ${relativePath}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -239,6 +239,9 @@ async function collectInstalledPathErrors(params: {
|
||||
? actualSet.has(relativePath)
|
||||
: await pathExists(path.join(params.packageRoot, relativePath));
|
||||
if (!exists) {
|
||||
if (NPM_UPDATE_COMPAT_SIDECAR_PATHS.has(relativePath)) {
|
||||
continue;
|
||||
}
|
||||
errors.push(params.missingMessage(relativePath));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user