fix(cli): block gateway-owned package updates (#75819)

Merged via squash.

Prepared head SHA: acdf73e6d0
Co-authored-by: ai-hpc <183861985+ai-hpc@users.noreply.github.com>
Co-authored-by: hxy91819 <8814856+hxy91819@users.noreply.github.com>
Reviewed-by: @hxy91819
This commit is contained in:
NVIDIAN
2026-05-02 20:40:36 -07:00
committed by GitHub
parent 55c738ad4b
commit c81c0171cd
4 changed files with 69 additions and 1 deletions

View File

@@ -24,6 +24,7 @@ import { resolveGatewayRestartLogPath } from "../../daemon/restart-logs.js";
import { readGatewayServiceState, resolveGatewayService } from "../../daemon/service.js";
import { createLowDiskSpaceWarning } from "../../infra/disk-space.js";
import { runGlobalPackageUpdateSteps } from "../../infra/package-update-steps.js";
import { getSelfAndAncestorPidsSync } from "../../infra/restart-stale-pids.js";
import { nodeVersionSatisfiesEngine } from "../../infra/runtime-guard.js";
import {
channelToNpmTag,
@@ -236,9 +237,30 @@ type PrePackageServiceStop = {
inspected: boolean;
runtimeInspected: boolean;
running: boolean;
blockMessage?: string;
serviceEnv?: NodeJS.ProcessEnv;
};
function formatGatewayAncestryBlockMessage(pid: number): string {
return `openclaw update detected it is running inside the gateway process tree.
Gateway PID ${pid} is an ancestor of this process, so this updater cannot safely stop or restart the gateway that owns it.
Run \`${replaceCliName(formatCliCommand("openclaw update"), CLI_NAME)}\` from a shell outside the gateway service, or stop the gateway service first and then update.`;
}
function isGatewayAncestorPid(pid: unknown): pid is number {
return typeof pid === "number" && pid > 0 && getSelfAndAncestorPidsSync().has(pid);
}
function gatewayAncestryBlockMessage(pid: unknown): string | undefined {
return isGatewayAncestorPid(pid) ? formatGatewayAncestryBlockMessage(pid) : undefined;
}
function gatewayRuntimeAncestryBlockMessage(
runtime: { pid?: unknown } | null | undefined,
): string | undefined {
return gatewayAncestryBlockMessage(runtime?.pid);
}
async function maybeStopManagedServiceBeforePackageUpdate(params: {
shouldRestart: boolean;
jsonMode: boolean;
@@ -301,6 +323,18 @@ async function maybeStopManagedServiceBeforePackageUpdate(params: {
};
}
const blockMessage = gatewayRuntimeAncestryBlockMessage(serviceState.runtime);
if (blockMessage) {
return {
stopped: false,
inspected: true,
runtimeInspected: true,
running: true,
blockMessage,
serviceEnv: serviceState.env,
};
}
if (!params.jsonMode) {
defaultRuntime.log(theme.muted("Stopping managed gateway service before package update..."));
}
@@ -1817,6 +1851,13 @@ export async function updateCommand(opts: UpdateCommandOptions): Promise<void> {
return;
}
if (prePackageServiceStop?.blockMessage) {
stop();
defaultRuntime.error(prePackageServiceStop.blockMessage);
defaultRuntime.exit(1);
return;
}
if (shouldBlockPackageUpdateFromGatewayServiceEnv({ prePackageServiceStop })) {
stop();
defaultRuntime.error(