Skip to content

Commit dc4d337

Browse files
fix(test): guard parseDuration --since against overflow with VALIDATION_ERROR (#27)
1 parent 6e7f2b3 commit dc4d337

2 files changed

Lines changed: 28 additions & 2 deletions

File tree

src/commands/test.result.history.spec.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,24 @@ describe('parseDuration', () => {
169169
it('case-insensitive day suffix', () => {
170170
expect(parseDuration('7D', NOW)).toBe('2026-05-27T12:00:00.000Z');
171171
});
172+
173+
it('overflow hours throws VALIDATION_ERROR instead of crashing', () => {
174+
expect(() => parseDuration('99999999999h', NOW)).toThrow();
175+
try {
176+
parseDuration('99999999999h', NOW);
177+
} catch (err: unknown) {
178+
expect((err as { code?: string }).code).toBe('VALIDATION_ERROR');
179+
}
180+
});
181+
182+
it('overflow days throws VALIDATION_ERROR instead of crashing', () => {
183+
expect(() => parseDuration('99999999999d', NOW)).toThrow();
184+
try {
185+
parseDuration('99999999999d', NOW);
186+
} catch (err: unknown) {
187+
expect((err as { code?: string }).code).toBe('VALIDATION_ERROR');
188+
}
189+
});
172190
});
173191

174192
// ---------------------------------------------------------------------------

src/commands/test.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3809,12 +3809,20 @@ export function parseDuration(raw: string, now: Date = new Date()): string {
38093809
const hourMatch = /^(\d+)h$/i.exec(raw);
38103810
if (hourMatch) {
38113811
const hours = Number(hourMatch[1]);
3812-
return new Date(now.getTime() - hours * 60 * 60 * 1000).toISOString();
3812+
const result = new Date(now.getTime() - hours * 60 * 60 * 1000);
3813+
if (!Number.isFinite(result.getTime())) {
3814+
throw localValidationError('since', 'duration is too large; maximum is ~1141552511h');
3815+
}
3816+
return result.toISOString();
38133817
}
38143818
const dayMatch = /^(\d+)d$/i.exec(raw);
38153819
if (dayMatch) {
38163820
const days = Number(dayMatch[1]);
3817-
return new Date(now.getTime() - days * 24 * 60 * 60 * 1000).toISOString();
3821+
const result = new Date(now.getTime() - days * 24 * 60 * 60 * 1000);
3822+
if (!Number.isFinite(result.getTime())) {
3823+
throw localValidationError('since', 'duration is too large; maximum is ~47564688d');
3824+
}
3825+
return result.toISOString();
38183826
}
38193827
// Pass-through: ISO timestamp or epoch value — server validates.
38203828
return raw;

0 commit comments

Comments
 (0)