Skip to content

Commit 9e57acf

Browse files
agviegasclaude
andcommitted
fix(Indexes): validate index number keys/values are non-negative 32-bit integers
User-defined index number keys and values are stored as Uint32, so negative or floating-point numbers were silently corrupted (negatives wrap, floats truncate) with no error. CREATE_INDEX/UPDATE_INDEX now reject out-of-range number keys/values with an IndexValidationError that reports the offending indices, instead of accepting and corrupting them. Closes #214 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 705ea90 commit 9e57acf

2 files changed

Lines changed: 43 additions & 0 deletions

File tree

packages/fragments/src/Utils/edit/edit-function.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,38 @@ export function edit(
318318
) {
319319
// Validate index definition
320320
const { keys, values, end, start } = request.data;
321+
// Number keys/values are stored as Uint32, so they must be non-negative
322+
// integers in range. Reject negatives/floats/overflow with a clear error
323+
// instead of silently corrupting them (negatives wrap, floats truncate).
324+
const validateNumbers = (
325+
items: (number | string)[] | undefined,
326+
key: "keys" | "values",
327+
) => {
328+
if (!items || items.length === 0 || typeof items[0] !== "number") {
329+
return;
330+
}
331+
const numberErrors: { index: number; value: number }[] = [];
332+
for (let index = 0; index < items.length; index++) {
333+
const value = items[index] as number;
334+
if (!Number.isInteger(value) || value < 0 || value > 0xffffffff) {
335+
numberErrors.push({ index, value });
336+
}
337+
}
338+
if (numberErrors.length) {
339+
throw new Error(
340+
`Invalid index request: ${key} must be non-negative 32-bit integers`,
341+
{
342+
cause: {
343+
type: "invalid-number",
344+
key,
345+
errors: numberErrors,
346+
} satisfies ET.IndexValidationError["cause"],
347+
},
348+
);
349+
}
350+
};
351+
validateNumbers(keys, "keys");
352+
validateNumbers(values, "values");
321353
// 1:1
322354
if (values && !end) {
323355
if (values.length !== keys.length) {

packages/fragments/src/Utils/edit/edit-types.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,17 @@ export interface IndexValidationError extends Error {
543543
start: number;
544544
end: number;
545545
}[];
546+
}
547+
| {
548+
// Number keys/values are stored as Uint32, so they must be
549+
// non-negative integers within range. Anything else would be silently
550+
// corrupted (negatives wrap, floats truncate).
551+
type: "invalid-number";
552+
key: "keys" | "values";
553+
errors: {
554+
index: number;
555+
value: number;
556+
}[];
546557
};
547558
}
548559

0 commit comments

Comments
 (0)