From bd811eb753e281b69eba4028d468c1a4f2872818 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Thu, 22 Oct 2026 00:38:03 +0200 Subject: [PATCH] test(crypto): follow a pushed payload array into the write that sends it The lab CSV import builds its rows into an array and writes each chunk with one createMany({ data: toWrite }). The ciphertext-writer scan only read payload literals at the call site, so it never saw the encrypted note that write carries; the column stayed covered only by the name scan. The scan now follows an identifier payload into the literals the same file pushes onto it, and asserts it sees the chunked note write. --- .../encrypted-column-writers.test.ts | 34 +++++++++++++++++-- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/src/lib/crypto/__tests__/encrypted-column-writers.test.ts b/src/lib/crypto/__tests__/encrypted-column-writers.test.ts index 5b2814c04..e5e007f14 100644 --- a/src/lib/crypto/__tests__/encrypted-column-writers.test.ts +++ b/src/lib/crypto/__tests__/encrypted-column-writers.test.ts @@ -28,9 +28,13 @@ * call or a variable derived from one. * 3. Assert the result is a subset of the rotation registry. * - * Known limit, stated so it is not mistaken for coverage: a payload assembled - * somewhere other than the call site (`data: updates` where `updates` is built - * field by field) resolves to nothing here. Those columns are covered by the + * A payload passed as an array the same file fills with `.push({…})` + * (`createMany({ data: toWrite })`, the shape a chunked writer takes) is + * followed into those pushed literals. + * + * Known limit, stated so it is not mistaken for coverage: any other payload + * assembled somewhere other than the call site (`data: updates` where + * `updates` is built field by field) resolves to nothing here. Those columns are covered by the * name scan in the sibling guard; the two signals are deliberately * independent, and a column has to escape BOTH to go unregistered. The scan * asserts a non-zero, anchored match count, so a matcher that quietly stops @@ -398,6 +402,19 @@ function scanCiphertextWrites(): Map> { depth = 0, ): void => { if (depth > 4) return; + // `data: rows` where the file fills `rows` with `rows.push({…})`: walk + // each pushed literal as part of the payload. + const ident = /^\s*(\w+)\s*$/.exec(value)?.[1]; + if (ident) { + for (const push of src.matchAll( + new RegExp(`(? { } }); + it("follows a payload array filled by push into the write that sends it", () => { + // The lab CSV import builds its rows into an array and writes each chunk + // with one `createMany({ data: toWrite })`. + expect( + [...(written.get("LabResult.noteEncrypted") ?? [])].some((at) => + at.startsWith("src/lib/import/labs-csv.ts:"), + ), + "the chunked lab CSV write of LabResult.noteEncrypted was not seen", + ).toBe(true); + }); + it("registers every column the code writes ciphertext into", () => { const registered = new Set(ENCRYPTED_COLUMNS.map(encryptedColumnKey)); const unregistered = [...written.keys()]