// PB-26-208: PeachScript normalization before limits. // // normalize-then-decode allocated unbounded intermediates (regex copy, // Array.from) before any ceiling, and decode measured UTF-16 length — not // decoded bytes — against the export ceiling. One bounded parser replaces // the sequence: raw code points are capped at ceiling + a small pasted- // whitespace allowance, then a single scan skips whitespace, validates // every other code point, and stops once the decoded ceiling is crossed. import { describe, expect, test, vi } from "vitest"; import { decodePeachScript, isPeachScript } from "./peachScript"; import { IMPORT_LIMITS } from "../shared/import-limits"; // Mirror of the parser ceilings: floor(MAX_JSON_BYTES / 3) decoded code // points (each PUA glyph costs 3 UTF-8 bytes, matching the export ceiling) // plus a 64 KiB raw-whitespace allowance for pasted text. const MAX_CP = Math.floor(IMPORT_LIMITS.MAX_JSON_BYTES / 3); const ALLOWANCE = 64 * 1024; const MAX_RAW = MAX_CP + ALLOWANCE; const GLYPH = String.fromCodePoint(0xe041); describe("PB-26-208 bounded PeachScript parser", () => { test("whitespace-only input over ceiling + allowance fails as too large without Array.from", () => { const fromSpy = vi.spyOn(Array, "from"); try { expect(() => decodePeachScript(" ".repeat(MAX_RAW + 1))).toThrow( "PEACHSCRIPT_TOO_LARGE", ); expect( fromSpy.mock.calls.some( (args) => typeof args[0] === "string" && args[0].length > MAX_RAW, ), "decode must not Array.from an over-ceiling input", ).toBe(false); } finally { fromSpy.mockRestore(); } }); test("valid script at the encoded ceiling decodes; one more glyph fails", () => { const atCeiling = GLYPH.repeat(MAX_CP); expect(decodePeachScript(atCeiling).length).toBe(MAX_CP); expect(() => decodePeachScript(`${atCeiling}${GLYPH}`)).toThrow( "PEACHSCRIPT_TOO_LARGE", ); }); test("whitespace allowance boundary: allowance passes, allowance + 1 fails", () => { expect(decodePeachScript(" ".repeat(ALLOWANCE) + GLYPH).length).toBe(1); expect(() => decodePeachScript(" ".repeat(ALLOWANCE + 1) + GLYPH)).toThrow( "PEACHSCRIPT_TOO_LARGE", ); }); test("lone surrogates and astral characters throw without partial output", () => { expect(() => decodePeachScript(`${GLYPH}\ud800${GLYPH}`)).toThrow( "INVALID_PEACHSCRIPT_CHARACTER", ); expect(() => decodePeachScript("\udc00")).toThrow( "INVALID_PEACHSCRIPT_CHARACTER", ); expect(() => decodePeachScript(`${GLYPH}\u{1D2E0}`)).toThrow( "INVALID_PEACHSCRIPT_CHARACTER", ); }); test("isPeachScript shares the bound: oversized input is simply invalid", () => { expect(isPeachScript(" ".repeat(MAX_RAW + 1))).toBe(false); expect(isPeachScript(GLYPH.repeat(MAX_CP + 1))).toBe(false); expect(isPeachScript(` ${GLYPH}\n`)).toBe(true); }); });