import { expect, mock, test } from "bun:test"; /** * What the REAL adapter actually sends to the broker. * * Until now nothing executed `polyfill-adapter.ts`: every behavioural test ran * against the in-memory port, and the only thing standing between this package * and a destructive statement was a regex over its own source. An adversarial * review walked through that regex four separate ways — `COPY DEFAULT TO GRAPH`, * a keyword hidden behind the comment-stripper, `DELETE{` with no space, and a * literal split across concatenated lines — each time with the full suite green. * * A pattern over source can always be out-written. So this file stops describing * the code and starts EXERCISING it: the polyfill is replaced by a recorder, the * adapter is driven through its write path, and every query it emits is read back. * Whatever the source looks like, what leaves the adapter is checked. */ const emitted: string[] = []; mock.module("@ng-eventually/polyfill", () => ({ docs: { async sparqlUpdate(_sessionId: string | number, query: string) { emitted.push(query); return []; }, async sparqlQuery() { return { results: { bindings: [] } }; }, async docCreate() { return "did:ng:o:created"; }, }, inbox: { async postToDocument() {}, async readForDocument() { return []; }, }, async readUnion() { return []; }, storeRegistry: { async createEntityDoc() { return "did:ng:o:index"; }, async openDocumentInbox() { return "did:ng:o:inbox"; }, }, })); /** Every SPARQL 1.1 form that can destroy or displace data. */ const DESTRUCTIVE = /\b(DELETE|DROP|CLEAR|MOVE|COPY|ADD|LOAD|MODIFY|WITH|SILENT)\b/i; async function capture(run: (port: Awaited>) => Promise) { emitted.length = 0; await run(await makePort()); return [...emitted]; } async function makePort() { const { polyfillPort } = await import("../src/polyfill-adapter"); return polyfillPort({ sessionId: "session-under-test" }); } test("the adapter's only write emits one INSERT DATA and nothing else", async () => { const queries = await capture(async (port) => { await port.addLiteralProperty( "did:ng:o:index", "did:ng:o:object", "urn:ng-helpers:index:value", "2026-01-02", ); }); expect(queries).toEqual([ "INSERT DATA { GRAPH " + '{ "2026-01-02" } }', ]); for (const query of queries) { expect(query).not.toMatch(DESTRUCTIVE); } }); test("creating an index emits only INSERTs, whatever else it does", async () => { const { indexing } = await import("../src/indexing"); const queries = await capture(async (port) => { await indexing(port).createIndex("http://schema.org/datePublished"); }); expect(queries.length).toBeGreaterThan(0); // not vacuously true for (const query of queries) { expect(query.startsWith("INSERT DATA")).toBe(true); expect(query).not.toMatch(DESTRUCTIVE); } }); test("a hostile value cannot smuggle a second statement past the broker", async () => { const queries = await capture(async (port) => { await port.addLiteralProperty( "did:ng:o:index", "did:ng:o:object", "urn:ng-helpers:index:value", '" } } ; DROP GRAPH ; INSERT DATA { GRAPH { "c', ); }); expect(queries).toHaveLength(1); const query = queries[0] ?? ""; // The payload survives as inert text inside the literal — what matters is that // it never becomes a statement. Exactly two quotes are real delimiters. let unescaped = 0; for (let i = 0; i < query.length; i += 1) { if (query[i] !== '"') continue; let backslashes = 0; for (let j = i - 1; j >= 0 && query[j] === "\\"; j -= 1) backslashes += 1; if (backslashes % 2 === 0) unescaped += 1; } expect(unescaped).toBe(2); expect(query.startsWith("INSERT DATA { GRAPH ")).toBe(true); });