






















@@ -29,6 +29,7 @@ const runRestartScript = vi.fn();
2929const mockedRunDaemonInstall = vi.fn();
3030const serviceReadCommand = vi.fn();
3131const serviceReadRuntime = vi.fn();
32+const mockGetSelfAndAncestorPidsSync = vi.fn(() => new Set<number>([process.pid]));
3233const inspectPortUsage = vi.fn();
3334const classifyPortListener = vi.fn();
3435const formatPortDiagnostics = vi.fn();
@@ -128,6 +129,10 @@ vi.mock("../infra/runtime-guard.js", () => ({
128129},
129130}));
130131132+vi.mock("../infra/restart-stale-pids.js", () => ({
133+getSelfAndAncestorPidsSync: () => mockGetSelfAndAncestorPidsSync(),
134+}));
135+131136vi.mock("node:child_process", async () => {
132137const actual = await vi.importActual<typeof import("node:child_process")>("node:child_process");
133138return {
@@ -498,6 +503,7 @@ describe("update-cli", () => {
498503pid: 4242,
499504state: "running",
500505});
506+mockGetSelfAndAncestorPidsSync.mockReturnValue(new Set<number>([process.pid]));
501507prepareRestartScript.mockResolvedValue("/tmp/openclaw-restart-test.sh");
502508runRestartScript.mockResolvedValue(undefined);
503509inspectPortUsage.mockResolvedValue({
@@ -1425,6 +1431,26 @@ describe("update-cli", () => {
14251431);
14261432});
142714331434+it("refuses package updates from inside the active gateway process tree", async () => {
1435+mockPackageInstallStatus(createCaseDir("openclaw-update"));
1436+serviceLoaded.mockResolvedValue(true);
1437+mockGetSelfAndAncestorPidsSync.mockReturnValue(new Set<number>([process.pid, 4242]));
1438+1439+await updateCommand({ yes: true });
1440+1441+const errors = vi.mocked(defaultRuntime.error).mock.calls.map((call) => String(call[0]));
1442+expect(errors.join("\n")).toContain(
1443+"openclaw update detected it is running inside the gateway process tree.",
1444+);
1445+expect(errors.join("\n")).toContain("Gateway PID 4242 is an ancestor");
1446+expect(defaultRuntime.exit).toHaveBeenCalledWith(1);
1447+expect(serviceStop).not.toHaveBeenCalled();
1448+expect(runCommandWithTimeout).not.toHaveBeenCalledWith(
1449+["npm", "i", "-g", "openclaw@latest", "--no-fund", "--no-audit", "--loglevel=error"],
1450+expect.any(Object),
1451+);
1452+});
1453+14281454it("blocks package updates when the target requires a newer Node runtime", async () => {
14291455mockPackageInstallStatus(createCaseDir("openclaw-update"));
14301456vi.mocked(fetchNpmPackageTargetStatus).mockResolvedValue({
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。