mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-19 06:37:28 +00:00
refactor(cli): dedupe gateway run mode parsing
This commit is contained in:
@@ -118,6 +118,17 @@ describe("gateway run option collisions", () => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function expectAuthOverrideMode(mode: string) {
|
||||||
|
expect(startGatewayServer).toHaveBeenCalledWith(
|
||||||
|
18789,
|
||||||
|
expect.objectContaining({
|
||||||
|
auth: expect.objectContaining({
|
||||||
|
mode,
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
it("forwards parent-captured options to `gateway run` subcommand", async () => {
|
it("forwards parent-captured options to `gateway run` subcommand", async () => {
|
||||||
await runGatewayCli([
|
await runGatewayCli([
|
||||||
"gateway",
|
"gateway",
|
||||||
@@ -156,27 +167,13 @@ describe("gateway run option collisions", () => {
|
|||||||
it("accepts --auth none override", async () => {
|
it("accepts --auth none override", async () => {
|
||||||
await runGatewayCli(["gateway", "run", "--auth", "none", "--allow-unconfigured"]);
|
await runGatewayCli(["gateway", "run", "--auth", "none", "--allow-unconfigured"]);
|
||||||
|
|
||||||
expect(startGatewayServer).toHaveBeenCalledWith(
|
expectAuthOverrideMode("none");
|
||||||
18789,
|
|
||||||
expect.objectContaining({
|
|
||||||
auth: expect.objectContaining({
|
|
||||||
mode: "none",
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("accepts --auth trusted-proxy override", async () => {
|
it("accepts --auth trusted-proxy override", async () => {
|
||||||
await runGatewayCli(["gateway", "run", "--auth", "trusted-proxy", "--allow-unconfigured"]);
|
await runGatewayCli(["gateway", "run", "--auth", "trusted-proxy", "--allow-unconfigured"]);
|
||||||
|
|
||||||
expect(startGatewayServer).toHaveBeenCalledWith(
|
expectAuthOverrideMode("trusted-proxy");
|
||||||
18789,
|
|
||||||
expect.objectContaining({
|
|
||||||
auth: expect.objectContaining({
|
|
||||||
mode: "trusted-proxy",
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("prints all supported modes on invalid --auth value", async () => {
|
it("prints all supported modes on invalid --auth value", async () => {
|
||||||
|
|||||||
@@ -77,6 +77,42 @@ const GATEWAY_RUN_BOOLEAN_KEYS = [
|
|||||||
"rawStream",
|
"rawStream",
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
|
const GATEWAY_AUTH_MODES: readonly GatewayAuthMode[] = [
|
||||||
|
"none",
|
||||||
|
"token",
|
||||||
|
"password",
|
||||||
|
"trusted-proxy",
|
||||||
|
];
|
||||||
|
const GATEWAY_TAILSCALE_MODES: readonly GatewayTailscaleMode[] = ["off", "serve", "funnel"];
|
||||||
|
|
||||||
|
function parseEnumOption<T extends string>(
|
||||||
|
raw: string | undefined,
|
||||||
|
allowed: readonly T[],
|
||||||
|
): T | null {
|
||||||
|
if (!raw) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return (allowed as readonly string[]).includes(raw) ? (raw as T) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatModeChoices<T extends string>(modes: readonly T[]): string {
|
||||||
|
return modes.map((mode) => `"${mode}"`).join("|");
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatModeErrorList<T extends string>(modes: readonly T[]): string {
|
||||||
|
const quoted = modes.map((mode) => `"${mode}"`);
|
||||||
|
if (quoted.length === 0) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
if (quoted.length === 1) {
|
||||||
|
return quoted[0];
|
||||||
|
}
|
||||||
|
if (quoted.length === 2) {
|
||||||
|
return `${quoted[0]} or ${quoted[1]}`;
|
||||||
|
}
|
||||||
|
return `${quoted.slice(0, -1).join(", ")}, or ${quoted[quoted.length - 1]}`;
|
||||||
|
}
|
||||||
|
|
||||||
function resolveGatewayRunOptions(opts: GatewayRunOpts, command?: Command): GatewayRunOpts {
|
function resolveGatewayRunOptions(opts: GatewayRunOpts, command?: Command): GatewayRunOpts {
|
||||||
const resolved: GatewayRunOpts = { ...opts };
|
const resolved: GatewayRunOpts = { ...opts };
|
||||||
|
|
||||||
@@ -185,25 +221,18 @@ async function runGatewayCommand(opts: GatewayRunOpts) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
const authModeRaw = toOptionString(opts.auth);
|
const authModeRaw = toOptionString(opts.auth);
|
||||||
const authMode: GatewayAuthMode | null =
|
const authMode = parseEnumOption(authModeRaw, GATEWAY_AUTH_MODES);
|
||||||
authModeRaw === "none" ||
|
|
||||||
authModeRaw === "token" ||
|
|
||||||
authModeRaw === "password" ||
|
|
||||||
authModeRaw === "trusted-proxy"
|
|
||||||
? authModeRaw
|
|
||||||
: null;
|
|
||||||
if (authModeRaw && !authMode) {
|
if (authModeRaw && !authMode) {
|
||||||
defaultRuntime.error('Invalid --auth (use "none", "token", "password", or "trusted-proxy")');
|
defaultRuntime.error(`Invalid --auth (use ${formatModeErrorList(GATEWAY_AUTH_MODES)})`);
|
||||||
defaultRuntime.exit(1);
|
defaultRuntime.exit(1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const tailscaleRaw = toOptionString(opts.tailscale);
|
const tailscaleRaw = toOptionString(opts.tailscale);
|
||||||
const tailscaleMode: GatewayTailscaleMode | null =
|
const tailscaleMode = parseEnumOption(tailscaleRaw, GATEWAY_TAILSCALE_MODES);
|
||||||
tailscaleRaw === "off" || tailscaleRaw === "serve" || tailscaleRaw === "funnel"
|
|
||||||
? tailscaleRaw
|
|
||||||
: null;
|
|
||||||
if (tailscaleRaw && !tailscaleMode) {
|
if (tailscaleRaw && !tailscaleMode) {
|
||||||
defaultRuntime.error('Invalid --tailscale (use "off", "serve", or "funnel")');
|
defaultRuntime.error(
|
||||||
|
`Invalid --tailscale (use ${formatModeErrorList(GATEWAY_TAILSCALE_MODES)})`,
|
||||||
|
);
|
||||||
defaultRuntime.exit(1);
|
defaultRuntime.exit(1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -369,9 +398,12 @@ export function addGatewayRunCommand(cmd: Command): Command {
|
|||||||
"--token <token>",
|
"--token <token>",
|
||||||
"Shared token required in connect.params.auth.token (default: OPENCLAW_GATEWAY_TOKEN env if set)",
|
"Shared token required in connect.params.auth.token (default: OPENCLAW_GATEWAY_TOKEN env if set)",
|
||||||
)
|
)
|
||||||
.option("--auth <mode>", 'Gateway auth mode ("none"|"token"|"password"|"trusted-proxy")')
|
.option("--auth <mode>", `Gateway auth mode (${formatModeChoices(GATEWAY_AUTH_MODES)})`)
|
||||||
.option("--password <password>", "Password for auth mode=password")
|
.option("--password <password>", "Password for auth mode=password")
|
||||||
.option("--tailscale <mode>", 'Tailscale exposure mode ("off"|"serve"|"funnel")')
|
.option(
|
||||||
|
"--tailscale <mode>",
|
||||||
|
`Tailscale exposure mode (${formatModeChoices(GATEWAY_TAILSCALE_MODES)})`,
|
||||||
|
)
|
||||||
.option(
|
.option(
|
||||||
"--tailscale-reset-on-exit",
|
"--tailscale-reset-on-exit",
|
||||||
"Reset Tailscale serve/funnel configuration on shutdown",
|
"Reset Tailscale serve/funnel configuration on shutdown",
|
||||||
|
|||||||
Reference in New Issue
Block a user