import { describe, test, expect } from 'vitest' import { createQuery, type Queryable } from '../src/db/pool.js' describe('T2 parameterized query wrapper (no SQLi path)', () => { test('passes params SEPARATELY from SQL text — never interpolated', async () => { const calls: { text: string; params: readonly unknown[] }[] = [] const fake: Queryable = { async query(text, params) { calls.push({ text, params }) return { rows: [{ ok: 1 }] } }, } const query = createQuery(fake) const rows = await query<{ ok: number }>('SELECT * FROM hosts WHERE host_id = $1', ["'; DROP TABLE hosts; --"]) expect(rows).toEqual([{ ok: 1 }]) expect(calls[0]?.text).toBe('SELECT * FROM hosts WHERE host_id = $1') // The malicious value stays a bound param — it is NOT concatenated into the SQL text. expect(calls[0]?.text).not.toContain('DROP TABLE') expect(calls[0]?.params).toEqual(["'; DROP TABLE hosts; --"]) }) })