fix(update): require integer timeout values (#83310)

* fix(update): require integer timeout values

* fix(update): reject blank timeout values
This commit is contained in:
Gio Della-Libera
2026-05-17 18:47:59 -07:00
committed by GitHub
parent 4b4048fd22
commit 8855a4aa58
2 changed files with 46 additions and 4 deletions

View File

@@ -1,5 +1,6 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import { createGlobalCommandRunner } from "./shared.js";
import { defaultRuntime } from "../../runtime.js";
import { createGlobalCommandRunner, parseTimeoutMsOrExit } from "./shared.js";
const runCommandWithTimeout = vi.hoisted(() => vi.fn());
@@ -48,4 +49,41 @@ describe("createGlobalCommandRunner", () => {
code: 17,
});
});
it("requires timeout values to be complete positive integer seconds", () => {
const error = vi.spyOn(defaultRuntime, "error").mockImplementation(() => undefined);
const exit = vi.spyOn(defaultRuntime, "exit").mockImplementation(() => undefined as never);
try {
expect(parseTimeoutMsOrExit("1.5")).toBeNull();
expect(parseTimeoutMsOrExit("10abc")).toBeNull();
expect(parseTimeoutMsOrExit("0")).toBeNull();
expect(parseTimeoutMsOrExit("-1")).toBeNull();
expect(parseTimeoutMsOrExit(" ")).toBeNull();
expect(error).toHaveBeenCalledTimes(5);
expect(error).toHaveBeenCalledWith("--timeout must be a positive integer (seconds)");
expect(exit).toHaveBeenCalledTimes(5);
expect(exit).toHaveBeenCalledWith(1);
} finally {
error.mockRestore();
exit.mockRestore();
}
});
it("parses complete positive integer timeout values as milliseconds", () => {
const error = vi.spyOn(defaultRuntime, "error").mockImplementation(() => undefined);
const exit = vi.spyOn(defaultRuntime, "exit").mockImplementation(() => undefined as never);
try {
expect(parseTimeoutMsOrExit(" 10 ")).toBe(10_000);
expect(parseTimeoutMsOrExit("001")).toBe(1_000);
expect(parseTimeoutMsOrExit()).toBeUndefined();
expect(error).not.toHaveBeenCalled();
expect(exit).not.toHaveBeenCalled();
} finally {
error.mockRestore();
exit.mockRestore();
}
});
});

View File

@@ -54,13 +54,17 @@ export type UpdateWizardOptions = {
const INVALID_TIMEOUT_ERROR = "--timeout must be a positive integer (seconds)";
export function parseTimeoutMsOrExit(timeout?: string): number | undefined | null {
const timeoutMs = timeout ? Number.parseInt(timeout, 10) * 1000 : undefined;
if (timeoutMs !== undefined && (Number.isNaN(timeoutMs) || timeoutMs <= 0)) {
if (timeout === undefined) {
return undefined;
}
const trimmed = timeout.trim();
const seconds = Number(trimmed);
if (!/^\d+$/u.test(trimmed) || !Number.isSafeInteger(seconds) || seconds <= 0) {
defaultRuntime.error(INVALID_TIMEOUT_ERROR);
defaultRuntime.exit(1);
return null;
}
return timeoutMs;
return seconds * 1000;
}
const OPENCLAW_REPO_URL = "https://github.com/openclaw/openclaw.git";