openclaw/src/cli/gateway-cli/run.option-collisions.test.ts
Gustavo Madeira Santana c5698caca3
Security: default gateway auth bootstrap and explicit mode none (#20686)
Merged via /review-pr -> /prepare-pr -> /merge-pr.

Prepared head SHA: be1b73182cdca9c2331e2113bd1a08b977181974
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
2026-02-19 02:35:50 -05:00

154 lines
4.5 KiB
TypeScript

import { Command } from "commander";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { createCliRuntimeCapture } from "../test-runtime-capture.js";
const startGatewayServer = vi.fn(async (_port: number, _opts?: unknown) => ({
close: vi.fn(async () => {}),
}));
const setGatewayWsLogStyle = vi.fn((_style: string) => undefined);
const setVerbose = vi.fn((_enabled: boolean) => undefined);
const forceFreePortAndWait = vi.fn(async (_port: number, _opts: unknown) => ({
killed: [],
waitedMs: 0,
escalatedToSigkill: false,
}));
const ensureDevGatewayConfig = vi.fn(async (_opts?: unknown) => {});
const runGatewayLoop = vi.fn(async ({ start }: { start: () => Promise<unknown> }) => {
await start();
});
const { defaultRuntime, resetRuntimeCapture } = createCliRuntimeCapture();
vi.mock("../../config/config.js", () => ({
getConfigPath: () => "/tmp/openclaw-test-missing-config.json",
loadConfig: () => ({}),
readConfigFileSnapshot: async () => ({ exists: false }),
resolveStateDir: () => "/tmp",
resolveGatewayPort: () => 18789,
}));
vi.mock("../../gateway/auth.js", () => ({
resolveGatewayAuth: (params: { authConfig?: { token?: string }; env?: NodeJS.ProcessEnv }) => ({
mode: "token",
token: params.authConfig?.token ?? params.env?.OPENCLAW_GATEWAY_TOKEN,
password: undefined,
allowTailscale: false,
}),
}));
vi.mock("../../gateway/server.js", () => ({
startGatewayServer: (port: number, opts?: unknown) => startGatewayServer(port, opts),
}));
vi.mock("../../gateway/ws-logging.js", () => ({
setGatewayWsLogStyle: (style: string) => setGatewayWsLogStyle(style),
}));
vi.mock("../../globals.js", () => ({
setVerbose: (enabled: boolean) => setVerbose(enabled),
}));
vi.mock("../../infra/gateway-lock.js", () => ({
GatewayLockError: class GatewayLockError extends Error {},
}));
vi.mock("../../infra/ports.js", () => ({
formatPortDiagnostics: () => [],
inspectPortUsage: async () => ({ status: "free" }),
}));
vi.mock("../../logging/console.js", () => ({
setConsoleSubsystemFilter: () => undefined,
setConsoleTimestampPrefix: () => undefined,
}));
vi.mock("../../logging/subsystem.js", () => ({
createSubsystemLogger: () => ({
info: () => undefined,
warn: () => undefined,
error: () => undefined,
}),
}));
vi.mock("../../runtime.js", () => ({
defaultRuntime,
}));
vi.mock("../command-format.js", () => ({
formatCliCommand: (cmd: string) => cmd,
}));
vi.mock("../ports.js", () => ({
forceFreePortAndWait: (port: number, opts: unknown) => forceFreePortAndWait(port, opts),
}));
vi.mock("./dev.js", () => ({
ensureDevGatewayConfig: (opts?: unknown) => ensureDevGatewayConfig(opts),
}));
vi.mock("./run-loop.js", () => ({
runGatewayLoop: (params: { start: () => Promise<unknown> }) => runGatewayLoop(params),
}));
describe("gateway run option collisions", () => {
beforeEach(() => {
resetRuntimeCapture();
startGatewayServer.mockClear();
setGatewayWsLogStyle.mockClear();
setVerbose.mockClear();
forceFreePortAndWait.mockClear();
ensureDevGatewayConfig.mockClear();
runGatewayLoop.mockClear();
});
it("forwards parent-captured options to `gateway run` subcommand", async () => {
const { addGatewayRunCommand } = await import("./run.js");
const program = new Command();
const gateway = addGatewayRunCommand(program.command("gateway"));
addGatewayRunCommand(gateway.command("run"));
await program.parseAsync(
[
"gateway",
"run",
"--token",
"tok_run",
"--allow-unconfigured",
"--ws-log",
"full",
"--force",
],
{ from: "user" },
);
expect(forceFreePortAndWait).toHaveBeenCalledWith(18789, expect.anything());
expect(setGatewayWsLogStyle).toHaveBeenCalledWith("full");
expect(startGatewayServer).toHaveBeenCalledWith(
18789,
expect.objectContaining({
auth: expect.objectContaining({
token: "tok_run",
}),
}),
);
});
it("starts gateway when token mode has no configured token (startup bootstrap path)", async () => {
const { addGatewayRunCommand } = await import("./run.js");
const program = new Command();
const gateway = addGatewayRunCommand(program.command("gateway"));
addGatewayRunCommand(gateway.command("run"));
await program.parseAsync(["gateway", "run", "--allow-unconfigured"], {
from: "user",
});
expect(startGatewayServer).toHaveBeenCalledWith(
18789,
expect.objectContaining({
bind: "loopback",
}),
);
});
});