@@ -253,3 +253,231 @@ describe("adversarial: CI smoke test parity", () => {
253253 expect ( testRegex . test ( patchedPath ) ) . toBe ( false )
254254 } )
255255} )
256+
257+ // ─── Adversarial: copy-python.ts script execution ───────────────────
258+ describe ( "adversarial: copy-python.ts as a real script" , ( ) => {
259+ test ( "build script exits 0 on success" , async ( ) => {
260+ const result = await $ `bun run build` . cwd ( join ( import . meta. dir , ".." ) ) . nothrow ( )
261+ expect ( result . exitCode ) . toBe ( 0 )
262+ expect ( result . stderr . toString ( ) ) . not . toContain ( "ERROR" )
263+ } )
264+
265+ test ( "build script prints all three progress lines" , async ( ) => {
266+ const result = await $ `bun run build` . cwd ( join ( import . meta. dir , ".." ) ) . nothrow ( )
267+ const output = result . stderr . toString ( ) + result . stdout . toString ( )
268+ expect ( output ) . toContain ( "Copied altimate_python_packages" )
269+ expect ( output ) . toContain ( "Copied node_python_bridge.py" )
270+ expect ( output ) . toContain ( "Patched __dirname" )
271+ } )
272+
273+ test ( "consecutive builds produce identical dist/index.js" , async ( ) => {
274+ await $ `bun run build` . cwd ( join ( import . meta. dir , ".." ) )
275+ const first = readFileSync ( join ( dist , "index.js" ) , "utf8" )
276+
277+ await $ `bun run build` . cwd ( join ( import . meta. dir , ".." ) )
278+ const second = readFileSync ( join ( dist , "index.js" ) , "utf8" )
279+
280+ expect ( first ) . toBe ( second )
281+ } )
282+ } )
283+
284+ // ─── Adversarial: bundle runtime structure ──────────────────────────
285+ describe ( "adversarial: bundle runtime structure" , ( ) => {
286+ beforeAll ( async ( ) => {
287+ if ( ! existsSync ( join ( dist , "index.js" ) ) ) {
288+ await $ `bun run build` . cwd ( join ( import . meta. dir , ".." ) )
289+ }
290+ } )
291+
292+ test ( "__require is defined via createRequire (not a Bun-only global)" , ( ) => {
293+ const code = readFileSync ( join ( dist , "index.js" ) , "utf8" )
294+ // __require must be created from Node's standard createRequire
295+ expect ( code ) . toContain ( 'import { createRequire } from "node:module"' )
296+ expect ( code ) . toMatch ( / v a r _ _ r e q u i r e \s * = .* c r e a t e R e q u i r e \( i m p o r t \. m e t a \. u r l \) / )
297+ } )
298+
299+ test ( "__dirname lives inside __commonJS wrapper (correct scope)" , ( ) => {
300+ const code = readFileSync ( join ( dist , "index.js" ) , "utf8" )
301+ // Find the python-bridge module wrapper
302+ const bridgeStart = code . indexOf ( "// ../../node_modules/.bun/python-bridge" )
303+ expect ( bridgeStart ) . toBeGreaterThan ( - 1 )
304+
305+ const dirnamePos = code . indexOf ( "var __dirname" , bridgeStart )
306+ expect ( dirnamePos ) . toBeGreaterThan ( bridgeStart )
307+
308+ // __dirname should come BEFORE PYTHON_BRIDGE_SCRIPT in the same scope
309+ const bridgeScriptPos = code . indexOf ( "PYTHON_BRIDGE_SCRIPT" , dirnamePos )
310+ expect ( bridgeScriptPos ) . toBeGreaterThan ( dirnamePos )
311+ } )
312+
313+ test ( "PYTHON_BRIDGE_SCRIPT resolves node_python_bridge.py via __dirname" , ( ) => {
314+ const code = readFileSync ( join ( dist , "index.js" ) , "utf8" )
315+ // The bridge script path must use __dirname, not a hardcoded path
316+ expect ( code ) . toMatch ( / P Y T H O N _ B R I D G E _ S C R I P T \s * = \s * p a t h \. j o i n \( _ _ d i r n a m e , \s * " n o d e _ p y t h o n _ b r i d g e \. p y " \) / )
317+ } )
318+
319+ test ( "python bridge spawn uses PYTHON_BRIDGE_SCRIPT variable" , ( ) => {
320+ const code = readFileSync ( join ( dist , "index.js" ) , "utf8" )
321+ // The spawn call must use the variable, not an inline path
322+ expect ( code ) . toContain ( "spawn(intepreter, [PYTHON_BRIDGE_SCRIPT]" )
323+ } )
324+
325+ test ( "no other hardcoded python-bridge paths survive in bundle" , ( ) => {
326+ const code = readFileSync ( join ( dist , "index.js" ) , "utf8" )
327+ // After patching, the only python-bridge references should be:
328+ // 1. The comment line (// ../../node_modules/.bun/python-bridge@...)
329+ // 2. The require_python_bridge function name
330+ // 3. String literals for error messages
331+ // There should be NO hardcoded filesystem paths to python-bridge
332+ const lines = code . split ( "\n" )
333+ for ( const line of lines ) {
334+ if ( line . includes ( "python-bridge" ) && ! line . trimStart ( ) . startsWith ( "//" ) ) {
335+ // This line references python-bridge — it must NOT be a hardcoded path
336+ expect ( line ) . not . toMatch ( / [ " ' ] ( \/ | [ A - Z ] : \\ ) [ ^ " ' ] * p y t h o n - b r i d g e / )
337+ }
338+ }
339+ } )
340+ } )
341+
342+ // ─── Adversarial: publish pipeline ──────────────────────────────────
343+ describe ( "adversarial: publish.ts copies patched artifacts" , ( ) => {
344+ beforeAll ( async ( ) => {
345+ if ( ! existsSync ( join ( dist , "index.js" ) ) ) {
346+ await $ `bun run build` . cwd ( join ( import . meta. dir , ".." ) )
347+ }
348+ } )
349+
350+ test ( "dist/index.js is patched BEFORE publish.ts copies it" , ( ) => {
351+ // publish.ts calls `bun run build` on dbt-tools, then copies dist/index.js.
352+ // If copy-python.ts runs as part of build, the copied file must be patched.
353+ const code = readFileSync ( join ( dist , "index.js" ) , "utf8" )
354+ expect ( code ) . toContain ( "import.meta.dirname" )
355+ expect ( code ) . not . toMatch ( / v a r _ _ d i r n a m e \s * = \s * " (?: [ A - Z a - z ] : \\ \\ | \/ ) / )
356+ } )
357+
358+ test ( "dist/node_python_bridge.py is non-empty and valid Python" , ( ) => {
359+ const py = readFileSync ( join ( dist , "node_python_bridge.py" ) , "utf8" )
360+ expect ( py . length ) . toBeGreaterThan ( 500 ) // real file, not a stub
361+ // Must contain the IPC message handling that the JS bridge talks to
362+ expect ( py ) . toContain ( "def" )
363+ // Must handle the JSON-RPC protocol
364+ expect ( py ) . toMatch ( / j s o n | J S O N / )
365+ } )
366+ } )
367+
368+ // ─── Adversarial: mutation testing (what if the fix is removed?) ─────
369+ describe ( "adversarial: mutation testing" , ( ) => {
370+ test ( "unpatched bundle WOULD contain a hardcoded absolute path" , ( ) => {
371+ // Build raw bundle WITHOUT running copy-python.ts
372+ // We simulate this by checking what bun build alone produces
373+ const code = readFileSync ( join ( dist , "index.js" ) , "utf8" )
374+
375+ // The patched line should exist — if we remove the patch, the hardcoded
376+ // path would return. Verify the patch is structurally present.
377+ const patchedLine = code . split ( "\n" ) . find ( ( l ) => l . includes ( "var __dirname" ) && l . includes ( "import.meta.dirname" ) )
378+ expect ( patchedLine ) . toBeDefined ( )
379+
380+ // The patched line must have the ternary structure
381+ expect ( patchedLine ) . toContain ( "typeof import.meta.dirname" )
382+ expect ( patchedLine ) . toContain ( "?" )
383+ expect ( patchedLine ) . toContain ( ":" )
384+ expect ( patchedLine ) . toContain ( "__require" )
385+ } )
386+
387+ test ( "removing import.meta.dirname from replacement would break detection" , ( ) => {
388+ // The CI smoke test and build-integrity test both look for "import.meta.dirname".
389+ // If someone changes the replacement string to not include it, both guards catch it.
390+ const brokenReplacement = `var __dirname = __require("path").dirname(__require("url").fileURLToPath(import.meta.url))`
391+ // build-integrity.test.ts check:
392+ expect ( brokenReplacement ) . not . toContain ( "import.meta.dirname" )
393+ // This WOULD fail the integrity test — proving the guard works
394+ } )
395+
396+ test ( "removing the existence check would crash on missing bridge file" , ( ) => {
397+ // Verify the existence check is actually in the script
398+ const script = readFileSync ( join ( scriptDir , "copy-python.ts" ) , "utf8" )
399+ expect ( script ) . toContain ( "existsSync(bridgePy)" )
400+ expect ( script ) . toContain ( "process.exit(1)" )
401+ } )
402+ } )
403+
404+ // ─── Adversarial: regex catastrophic backtracking ───────────────────
405+ describe ( "adversarial: regex performance" , ( ) => {
406+ test ( "patch regex does not catastrophically backtrack on large input" , ( ) => {
407+ // Craft a pathological input that could cause ReDoS with a bad regex
408+ const huge = `var __dirname = "${ "a" . repeat ( 100_000 ) } "`
409+ const start = performance . now ( )
410+ runPatchLogic ( huge )
411+ const elapsed = performance . now ( ) - start
412+ // Must complete in under 100ms even on 100KB input
413+ expect ( elapsed ) . toBeLessThan ( 100 )
414+ } )
415+
416+ test ( "patch regex handles bundle with many var declarations" , ( ) => {
417+ // Simulate a large bundle with thousands of var declarations
418+ const lines = Array . from ( { length : 10_000 } , ( _ , i ) => `var x${ i } = "${ i } ";` )
419+ lines . push ( `var __dirname = "/ci/path/python-bridge"` )
420+ lines . push ( `var PYTHON_BRIDGE_SCRIPT = path.join(__dirname, "node_python_bridge.py");` )
421+ const bundle = lines . join ( "\n" )
422+
423+ const start = performance . now ( )
424+ const result = runPatchLogic ( bundle )
425+ const elapsed = performance . now ( ) - start
426+
427+ expect ( result . patched ) . toBe ( true )
428+ expect ( elapsed ) . toBeLessThan ( 200 ) // reasonable for 10K lines
429+ } )
430+ } )
431+
432+ // ─── Adversarial: path injection / malformed paths ──────────────────
433+ describe ( "adversarial: malformed inputs" , ( ) => {
434+ test ( "regex handles path with special regex characters" , ( ) => {
435+ // Paths with characters that are special in regex: . + * ? [ ] ( )
436+ const bundle = `var __dirname = "/home/runner/work/node_modules/.bun/python-bridge@1.1.0+build.123/node_modules/python-bridge"`
437+ const result = runPatchLogic ( bundle )
438+ expect ( result . patched ) . toBe ( true )
439+ } )
440+
441+ test ( "regex handles path with unicode characters" , ( ) => {
442+ const bundle = `var __dirname = "/home/用户/项目/node_modules/python-bridge"`
443+ const result = runPatchLogic ( bundle )
444+ expect ( result . patched ) . toBe ( true )
445+ } )
446+
447+ test ( "regex handles path with spaces" , ( ) => {
448+ const bundle = `var __dirname = "/home/runner/my project/node_modules/python-bridge"`
449+ const result = runPatchLogic ( bundle )
450+ expect ( result . patched ) . toBe ( true )
451+ } )
452+
453+ test ( "regex handles empty path with python-bridge" , ( ) => {
454+ const bundle = `var __dirname = "python-bridge"`
455+ const result = runPatchLogic ( bundle )
456+ expect ( result . patched ) . toBe ( true )
457+ } )
458+
459+ test ( "patch does NOT corrupt surrounding code" , ( ) => {
460+ const before = `console.log("before");\n`
461+ const target = `var __dirname = "/ci/python-bridge";\n`
462+ const after = `var SCRIPT = path.join(__dirname, "bridge.py");\n`
463+ const bundle = before + target + after
464+
465+ const result = runPatchLogic ( bundle )
466+ // Before and after lines must survive untouched
467+ expect ( result . output ) . toContain ( `console.log("before");` )
468+ expect ( result . output ) . toContain ( `var SCRIPT = path.join(__dirname, "bridge.py");` )
469+ // Target line is replaced
470+ expect ( result . output ) . toContain ( "import.meta.dirname" )
471+ expect ( result . output ) . not . toContain ( "/ci/python-bridge" )
472+ } )
473+
474+ test ( "patch preserves semicolons and line structure" , ( ) => {
475+ const bundle = `var __dirname = "/ci/python-bridge";`
476+ const result = runPatchLogic ( bundle )
477+ // The replacement should end where the original ended
478+ // Original: var __dirname = "..."; → var __dirname = typeof ...;
479+ // The semicolon after the closing quote is NOT part of the match,
480+ // so it should survive
481+ expect ( result . output ) . toMatch ( / \) ; $ / )
482+ } )
483+ } )
0 commit comments