diff --git a/.changeset/strict-server-cli-numbers.md b/.changeset/strict-server-cli-numbers.md new file mode 100644 index 000000000..d9e04a2b2 --- /dev/null +++ b/.changeset/strict-server-cli-numbers.md @@ -0,0 +1,5 @@ +--- +"@moonshot-ai/kimi-code": patch +--- + +Reject malformed numeric values for server CLI options instead of accepting partial decimal prefixes. diff --git a/apps/kimi-code/src/cli/sub/server/shared.ts b/apps/kimi-code/src/cli/sub/server/shared.ts index aa2b686ce..5f12a0bfc 100644 --- a/apps/kimi-code/src/cli/sub/server/shared.ts +++ b/apps/kimi-code/src/cli/sub/server/shared.ts @@ -129,10 +129,16 @@ function parseHost(raw: string | boolean | undefined): string { return raw; } +function parseDecimalInteger(raw: string): number | undefined { + if (!/^\d+$/.test(raw)) return undefined; + const n = Number(raw); + return Number.isSafeInteger(n) ? n : undefined; +} + function parseIdleGraceMs(raw: string | undefined): number { if (raw === undefined) return DEFAULT_IDLE_GRACE_MS; - const n = Number.parseInt(raw, 10); - if (!Number.isFinite(n) || n < 0) { + const n = parseDecimalInteger(raw); + if (n === undefined) { throw new Error(`error: invalid --idle-grace-ms value: ${raw}`); } return n; @@ -140,8 +146,8 @@ function parseIdleGraceMs(raw: string | undefined): number { export function parsePort(raw: string | undefined, label: string, fallback: number): number { if (raw === undefined) return fallback; - const n = Number.parseInt(raw, 10); - if (!Number.isFinite(n) || n < 0 || n > 65535) { + const n = parseDecimalInteger(raw); + if (n === undefined || n > 65535) { throw new Error(`error: invalid ${label} value: ${raw}`); } return n; diff --git a/apps/kimi-code/test/cli/server/server.test.ts b/apps/kimi-code/test/cli/server/server.test.ts index b6ee71f95..f01e48311 100644 --- a/apps/kimi-code/test/cli/server/server.test.ts +++ b/apps/kimi-code/test/cli/server/server.test.ts @@ -663,6 +663,27 @@ describe('shared parsers stay strict', () => { expect(parsePort('8080', '--port', 58627)).toBe(8080); }); + it('rejects --port values that are not complete decimal integers', async () => { + const { parsePort } = await import('#/cli/sub/server/shared'); + expect(() => parsePort('123abc', '--port', 58627)).toThrow(/invalid --port/); + expect(() => parsePort('1.5', '--port', 58627)).toThrow(/invalid --port/); + expect(() => parsePort('10ms', '--port', 58627)).toThrow(/invalid --port/); + }); + + it('rejects --idle-grace-ms values that are not complete decimal integers', async () => { + const { parseServerOptions } = await import('#/cli/sub/server/shared'); + expect(() => parseServerOptions({ idleGraceMs: '123abc' })).toThrow( + /invalid --idle-grace-ms/, + ); + expect(() => parseServerOptions({ idleGraceMs: '1.5' })).toThrow( + /invalid --idle-grace-ms/, + ); + expect(() => parseServerOptions({ idleGraceMs: '10ms' })).toThrow( + /invalid --idle-grace-ms/, + ); + expect(parseServerOptions({ idleGraceMs: '1000' }).idleGraceMs).toBe(1000); + }); + it('rejects unknown --log-level values', async () => { const { parseLogLevel } = await import('#/cli/sub/server/shared'); expect(() => parseLogLevel('shout')).toThrow(/invalid --log-level/);