/** * Orchestrator-level verification for Task 1 (Sanitize before storing). * Tests the real implementation in src/lib/ingest/sanitize.ts (zod schemas + * sanitizers) and the CSV formula-injection guard in * src/lib/export/csvGenerator.ts (neutralizeFormulaPrefix). * * Run: node --experimental-loader ./scripts/cors-resolve-hook.mjs scripts/verify_sanitize_orchestrator.mjs */ import { sanitizeText, sanitizeMultilineText, sanitizeReceiptBatch, sanitizeReceipt, StoredReceiptSchema } from "../src/lib/ingest/sanitize.ts"; import { neutralizeFormulaPrefix } from "../src/lib/export/csvGenerator.ts"; let failed = 0; let checks = 0; function expect(cond, label) { checks++; if (!cond) { failed++; console.error(" FAIL:", label); } else console.log(" ok ", label); } console.log("[1] sanitizeText strips markup + control chars"); const dirty = `Händler GmbH\u0000\u0007`; const clean = sanitizeText(dirty, 200); expect(!clean.includes("<") && !clean.includes(">"), "no < > remain"); expect(!clean.includes("\u0000") && !clean.includes("\u0007"), "control chars stripped"); expect(clean.includes("Händler GmbH"), "text preserved"); expect(sanitizeText("a\u00a0b c", 100) === "a b c", "whitespace collapsed"); console.log("[2] multiline OCR keeps line layout, strips markup"); const ocr = "Zeile1\nZeile2\tZeile3"; const ocrClean = sanitizeMultilineText(ocr, 50_000); expect(ocrClean.includes("\n"), "newlines survive"); expect(!ocrClean.includes("<"), "markup stripped"); expect(ocrClean.includes("Zeile3"), "tab survived"); console.log("[3] length caps"); expect(sanitizeText("x".repeat(500), 64).length === 64, "capped at limit"); console.log("[4] sanitizeReceiptBatch — malicious receipt payload"); const evil = { id: "r1