mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-29 16:05:13 +00:00
fix(cli): reject invalid node run port (#84307)
Co-authored-by: Gio Della-Libera <giodl@microsoft.com>
This commit is contained in:
@@ -1,8 +1,16 @@
|
||||
import { Command } from "commander";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { registerNodeCli } from "./register.js";
|
||||
|
||||
type LoadNodeHostConfig = typeof import("../../node-host/config.js").loadNodeHostConfig;
|
||||
|
||||
const daemonMocks = vi.hoisted(() => ({
|
||||
defaultRuntime: {
|
||||
error: vi.fn(),
|
||||
exit: vi.fn(),
|
||||
},
|
||||
loadNodeHostConfig: vi.fn<LoadNodeHostConfig>(async () => null),
|
||||
runNodeHost: vi.fn(),
|
||||
runNodeDaemonInstall: vi.fn(),
|
||||
runNodeDaemonRestart: vi.fn(),
|
||||
runNodeDaemonStart: vi.fn(),
|
||||
@@ -14,11 +22,15 @@ const daemonMocks = vi.hoisted(() => ({
|
||||
vi.mock("./daemon.js", () => daemonMocks);
|
||||
|
||||
vi.mock("../../node-host/config.js", () => ({
|
||||
loadNodeHostConfig: vi.fn(async () => null),
|
||||
loadNodeHostConfig: daemonMocks.loadNodeHostConfig,
|
||||
}));
|
||||
|
||||
vi.mock("../../node-host/runner.js", () => ({
|
||||
runNodeHost: vi.fn(),
|
||||
runNodeHost: daemonMocks.runNodeHost,
|
||||
}));
|
||||
|
||||
vi.mock("../../runtime.js", () => ({
|
||||
defaultRuntime: daemonMocks.defaultRuntime,
|
||||
}));
|
||||
|
||||
function createProgram(): Command {
|
||||
@@ -33,6 +45,20 @@ function createProgram(): Command {
|
||||
}
|
||||
|
||||
describe("registerNodeCli", () => {
|
||||
beforeEach(() => {
|
||||
daemonMocks.defaultRuntime.error.mockClear();
|
||||
daemonMocks.defaultRuntime.exit.mockClear();
|
||||
daemonMocks.loadNodeHostConfig.mockClear();
|
||||
daemonMocks.loadNodeHostConfig.mockResolvedValue(null);
|
||||
daemonMocks.runNodeHost.mockClear();
|
||||
daemonMocks.runNodeDaemonInstall.mockClear();
|
||||
daemonMocks.runNodeDaemonRestart.mockClear();
|
||||
daemonMocks.runNodeDaemonStart.mockClear();
|
||||
daemonMocks.runNodeDaemonStatus.mockClear();
|
||||
daemonMocks.runNodeDaemonStop.mockClear();
|
||||
daemonMocks.runNodeDaemonUninstall.mockClear();
|
||||
});
|
||||
|
||||
it("registers node start for the macOS app node service manager", async () => {
|
||||
const program = createProgram();
|
||||
|
||||
@@ -40,4 +66,41 @@ describe("registerNodeCli", () => {
|
||||
|
||||
expect(daemonMocks.runNodeDaemonStart.mock.calls[0]?.[0]?.json).toBe(true);
|
||||
});
|
||||
|
||||
it("rejects an explicit invalid node run port", async () => {
|
||||
const program = createProgram();
|
||||
|
||||
await program.parseAsync(["node", "run", "--port", "abc"], { from: "user" });
|
||||
|
||||
expect(daemonMocks.runNodeHost).not.toHaveBeenCalled();
|
||||
expect(daemonMocks.defaultRuntime.error).toHaveBeenCalledWith(
|
||||
expect.stringContaining("Invalid --port"),
|
||||
);
|
||||
expect(daemonMocks.defaultRuntime.exit).toHaveBeenCalledWith(1);
|
||||
});
|
||||
|
||||
it("uses an explicit valid node run port", async () => {
|
||||
const program = createProgram();
|
||||
|
||||
await program.parseAsync(["node", "run", "--port", "19000"], { from: "user" });
|
||||
|
||||
expect(daemonMocks.runNodeHost).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ gatewayPort: 19000 }),
|
||||
);
|
||||
});
|
||||
|
||||
it("falls back to configured node run port when --port is omitted", async () => {
|
||||
daemonMocks.loadNodeHostConfig.mockResolvedValue({
|
||||
version: 1,
|
||||
nodeId: "node-existing",
|
||||
gateway: { host: "10.0.0.2", port: 19001 },
|
||||
});
|
||||
const program = createProgram();
|
||||
|
||||
await program.parseAsync(["node", "run"], { from: "user" });
|
||||
|
||||
expect(daemonMocks.runNodeHost).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ gatewayHost: "10.0.0.2", gatewayPort: 19001 }),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import type { Command } from "commander";
|
||||
import { loadNodeHostConfig } from "../../node-host/config.js";
|
||||
import { runNodeHost } from "../../node-host/runner.js";
|
||||
import { defaultRuntime } from "../../runtime.js";
|
||||
import { normalizeOptionalString } from "../../shared/string-coerce.js";
|
||||
import { formatDocsLink } from "../../terminal/links.js";
|
||||
import { theme } from "../../terminal/theme.js";
|
||||
import { parsePort } from "../daemon-cli/shared.js";
|
||||
import { formatInvalidPortOption } from "../error-format.js";
|
||||
import { formatHelpExamples } from "../help-format.js";
|
||||
import {
|
||||
runNodeDaemonInstall,
|
||||
@@ -15,9 +17,11 @@ import {
|
||||
runNodeDaemonUninstall,
|
||||
} from "./daemon.js";
|
||||
|
||||
function parsePortWithFallback(value: unknown, fallback: number): number {
|
||||
const parsed = parsePort(value);
|
||||
return parsed ?? fallback;
|
||||
function parsePortOption(value: unknown, fallback: number): number | null {
|
||||
if (value === undefined) {
|
||||
return fallback;
|
||||
}
|
||||
return parsePort(value);
|
||||
}
|
||||
|
||||
export function registerNodeCli(program: Command) {
|
||||
@@ -54,7 +58,12 @@ export function registerNodeCli(program: Command) {
|
||||
normalizeOptionalString(opts.host as string | undefined) ||
|
||||
existing?.gateway?.host ||
|
||||
"127.0.0.1";
|
||||
const port = parsePortWithFallback(opts.port, existing?.gateway?.port ?? 18789);
|
||||
const port = parsePortOption(opts.port, existing?.gateway?.port ?? 18789);
|
||||
if (port === null) {
|
||||
defaultRuntime.error(formatInvalidPortOption("--port"));
|
||||
defaultRuntime.exit(1);
|
||||
return;
|
||||
}
|
||||
await runNodeHost({
|
||||
gatewayHost: host,
|
||||
gatewayPort: port,
|
||||
|
||||
Reference in New Issue
Block a user