From d3422d960a0e0cdbb8b94bd8785c559d645501c2 Mon Sep 17 00:00:00 2001 From: JerryNee Date: Fri, 26 Jun 2026 00:56:37 -0500 Subject: [PATCH] fix(pagination): reject fractional pagination flags --- src/lib/pagination.test.ts | 8 ++++++++ src/lib/pagination.ts | 10 +++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/lib/pagination.test.ts b/src/lib/pagination.test.ts index 33fd735..a11ea33 100644 --- a/src/lib/pagination.test.ts +++ b/src/lib/pagination.test.ts @@ -43,10 +43,18 @@ describe('validatePaginationFlags', () => { expect(() => validatePaginationFlags({ pageSize: Number.NaN })).toThrow(ApiError); }); + it('rejects fractional pageSize values', () => { + expect(() => validatePaginationFlags({ pageSize: 1.5 })).toThrow(ApiError); + }); + it('rejects maxItems=0', () => { expect(() => validatePaginationFlags({ maxItems: 0 })).toThrow(ApiError); }); + it('rejects fractional maxItems values', () => { + expect(() => validatePaginationFlags({ maxItems: 2.5 })).toThrow(ApiError); + }); + it('accepts pageSize=100 (the hard cap)', () => { expect(() => validatePaginationFlags({ pageSize: 100 })).not.toThrow(); }); diff --git a/src/lib/pagination.ts b/src/lib/pagination.ts index 59dbc12..ba63f9e 100644 --- a/src/lib/pagination.ts +++ b/src/lib/pagination.ts @@ -27,9 +27,9 @@ const DEFAULT_PAGE_SIZE = 25; * Validates and normalizes pagination flags. Per the CLI OpenAPI spec * §components.parameters.PageSize the hard cap is 100. Values above the * cap are now rejected with exit 5 rather than silently clamped, giving - * callers fast feedback that their flag value is out of range. Sub-1 / - * NaN values also throw. `maxItems` is validated but not capped (it is a - * client-side cursor, not a server parameter). + * callers fast feedback that their flag value is out of range. Fractional, + * sub-1, and NaN values also throw. `maxItems` is validated but not capped + * (it is a client-side cursor, not a server parameter). * * NOTE: `runResultHistory` previously did its own silent clamp via * `Math.min(Math.max(1, n), 100)` — that was unified to this path by the @@ -38,7 +38,7 @@ const DEFAULT_PAGE_SIZE = 25; export function validatePaginationFlags(flags: PaginationFlags): PaginationFlags { const out: PaginationFlags = { ...flags }; if (out.pageSize !== undefined) { - if (!Number.isFinite(out.pageSize) || out.pageSize < 1) { + if (!Number.isFinite(out.pageSize) || !Number.isInteger(out.pageSize) || out.pageSize < 1) { throw localValidationError( 'page-size', `must be a positive integer between 1 and ${HARD_PAGE_SIZE_CAP}`, @@ -52,7 +52,7 @@ export function validatePaginationFlags(flags: PaginationFlags): PaginationFlags } } if (out.maxItems !== undefined) { - if (!Number.isFinite(out.maxItems) || out.maxItems < 1) { + if (!Number.isFinite(out.maxItems) || !Number.isInteger(out.maxItems) || out.maxItems < 1) { throw localValidationError('maxItems', 'must be a positive integer'); } }