fix: reject malformed cursor IDs and page discriminants

This commit is contained in:
jb
2026-09-19 10:08:10 -04:00
parent 373eb60d0b
commit 39b680bb37
2 changed files with 11 additions and 2 deletions
+7 -2
View File
@@ -259,7 +259,12 @@ export function validateInventoryCursorUse(state: InventoryCursorState, lookup:
/** Enforce the page discriminants without implementing page retrieval. */
export function validateInventoryPageResult(result: InventoryQueryResult): InventoryPageValidation {
if (result.status !== 'ready') return { valid: true };
if (result.status !== 'ready') {
return ['partial', 'stale', 'authorization_required', 'unavailable'].includes(result.status)
? { valid: true }
: { valid: false, reason: 'invalid_page_state' };
}
if (!['initial', 'continuation', 'after_end'].includes(result.pageState)) return { valid: false, reason: 'invalid_page_state' };
if (result.pageState === 'after_end') {
return result.rows.length === 0 && result.nextCursor === null
? { valid: true }
@@ -278,7 +283,7 @@ function validCursorPosition(position: unknown): boolean {
const candidate = position as { offset?: unknown; lastItemId?: unknown };
if (!Number.isSafeInteger(candidate.offset) || (candidate.offset as number) < 0) return false;
if (candidate.offset === 0) return candidate.lastItemId === null;
return typeof candidate.lastItemId === 'string' && /^(0|[1-9][0-9]*)$/.test(candidate.lastItemId);
return typeof candidate.lastItemId === 'string' && /^(0|[1-9][0-9]*)$(?![\s\S])/.test(candidate.lastItemId);
}
function sameSelectedResourceList(left: readonly SelectedResource[], right: readonly SelectedResource[]): boolean {