From f58883b09b9866be469a57313e1ed0552240d616 Mon Sep 17 00:00:00 2001 From: aiirvizionz Date: Sat, 18 Jul 2026 17:46:44 -0600 Subject: [PATCH] fix(promote): reject non-decimal numeric limits --- packages/cli/src/commands/promote.test.ts | 27 +++++++++++++++++++++++ packages/cli/src/commands/promote.ts | 6 +++-- 2 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 packages/cli/src/commands/promote.test.ts diff --git a/packages/cli/src/commands/promote.test.ts b/packages/cli/src/commands/promote.test.ts new file mode 100644 index 00000000..784f70e5 --- /dev/null +++ b/packages/cli/src/commands/promote.test.ts @@ -0,0 +1,27 @@ +import { describe, expect, it } from 'vitest'; +import { parseNonNegativeInteger, parsePositiveInteger } from './promote.js'; + +describe('promote numeric option parsers', () => { + it('accepts decimal positive integers', () => { + expect(parsePositiveInteger('25')).toBe(25); + }); + + it.each(['0', '-1', '1.5', '1e2', '0x10', 'Infinity', 'NaN', 'abc'])( + 'rejects invalid positive integer %s', + (value) => { + expect(() => parsePositiveInteger(value)).toThrow('positive integer'); + }, + ); + + it('accepts decimal non-negative integers', () => { + expect(parseNonNegativeInteger('0')).toBe(0); + expect(parseNonNegativeInteger('2000')).toBe(2000); + }); + + it.each(['-1', '1.5', '1e2', '0x10', 'Infinity', 'NaN', 'abc'])( + 'rejects invalid non-negative integer %s', + (value) => { + expect(() => parseNonNegativeInteger(value)).toThrow('zero or a positive integer'); + }, + ); +}); diff --git a/packages/cli/src/commands/promote.ts b/packages/cli/src/commands/promote.ts index af5e2764..cfbacea3 100644 --- a/packages/cli/src/commands/promote.ts +++ b/packages/cli/src/commands/promote.ts @@ -866,13 +866,15 @@ function stripAiPrefix(p: string): string { return p.replace(/^ai-/, '').toLowerCase(); } -function parsePositiveInteger(value: string): number { +export function parsePositiveInteger(value: string): number { + if (!/^\d+$/.test(value)) throw new InvalidArgumentError('must be a positive integer'); const parsed = Number(value); if (!Number.isInteger(parsed) || parsed < 1) throw new InvalidArgumentError('must be a positive integer'); return parsed; } -function parseNonNegativeInteger(value: string): number { +export function parseNonNegativeInteger(value: string): number { + if (!/^\d+$/.test(value)) throw new InvalidArgumentError('must be zero or a positive integer'); const parsed = Number(value); if (!Number.isInteger(parsed) || parsed < 0) throw new InvalidArgumentError('must be zero or a positive integer'); return parsed;