diff --git a/src/cli/attach-cli.action.test.ts b/src/cli/attach-cli.action.test.ts index c60c923080f7..18a1da7a6694 100644 --- a/src/cli/attach-cli.action.test.ts +++ b/src/cli/attach-cli.action.test.ts @@ -117,6 +117,13 @@ describe("openclaw attach (action)", () => { expect(gatewayCalls.find((c) => c.method === "attach.grant")).toBeUndefined(); }); + it.each(["0x10", "1.5", "1e3"])("rejects malformed --ttl %s before minting", async (ttl) => { + await runAttach("--ttl", ttl, "--print-config"); + expect(exitCode).toBe(1); + expect(logs.join("\n")).toContain("--ttl must be a positive integer of milliseconds"); + expect(gatewayCalls.find((c) => c.method === "attach.grant")).toBeUndefined(); + }); + it("rejects an empty --ttl rather than silently defaulting", async () => { await runAttach("--ttl", "", "--print-config"); expect(exitCode).toBe(1); diff --git a/src/cli/attach-cli.ts b/src/cli/attach-cli.ts index 414ae175077d..137e75c1f8e9 100644 --- a/src/cli/attach-cli.ts +++ b/src/cli/attach-cli.ts @@ -9,6 +9,7 @@ import { } from "../../packages/gateway-protocol/src/client-info.js"; import { getRuntimeConfig } from "../config/io.js"; import { callGateway } from "../gateway/call.js"; +import { parseStrictPositiveInteger } from "../infra/parse-finite-number.js"; import { defaultRuntime } from "../runtime.js"; type AttachGrant = { @@ -34,7 +35,10 @@ export async function registerAttachCli(program: Command, _argv: string[] = proc .command("attach") .description("Attach Claude Code to a gateway session with scoped MCP tools") .option("--session ", "Gateway session key to bind (default: main session)") - .option("--ttl ", "Grant TTL in milliseconds (default: gateway policy)") + .option( + "--ttl ", + "Grant TTL in positive base-10 integer milliseconds (default: gateway policy)", + ) .option("--bin ", "Claude Code binary to spawn", "claude") .option( "--print-config", @@ -48,10 +52,10 @@ export async function registerAttachCli(program: Command, _argv: string[] = proc .action(async (opts: { session?: string; ttl?: string; bin: string; printConfig: boolean }) => { let ttlMs: number | undefined; if (opts.ttl !== undefined) { - ttlMs = Number(opts.ttl); - if (!Number.isFinite(ttlMs) || ttlMs <= 0) { + ttlMs = parseStrictPositiveInteger(opts.ttl); + if (ttlMs === undefined) { defaultRuntime.error( - `--ttl must be a positive number of milliseconds. Got: ${JSON.stringify(opts.ttl)}`, + `--ttl must be a positive integer of milliseconds. Got: ${JSON.stringify(opts.ttl)}`, ); defaultRuntime.exit(1); return;