// tests/mutator/claude-encryption.integration.test.ts // Integration test: verifies the encrypted wrapper round-trips correctly. import { $ } from "bun"; import { afterAll, describe, expect, test } from "bun:test"; import * as fs from "fs/promises"; import * as path from "path"; import { buildEncryptedWrapper } from "../../src/utils/encryptedWrapper"; describe("buildEncryptedWrapper round-trip", () => { const tmpDir = `/tmp/claude-enc-test-${Date.now()}`; const wrapperPath = path.join(tmpDir, "loader.js"); afterAll(async () => { try { await fs.rm(tmpDir, { recursive: true, force: true }); } catch {} }); test("wraps hello-world payload and executes correctly via bun", async () => { await fs.mkdir(tmpDir, { recursive: true }); const payload = 'process.stdout.write("hello from encrypted wrapper\\n");'; const wrapped = buildEncryptedWrapper(payload); await fs.writeFile(wrapperPath, wrapped, "utf-8"); // Run the wrapper with bun const result = await $`bun run ${wrapperPath}`.cwd(tmpDir).quiet(); expect(result.exitCode).toBe(0); expect(result.stdout.toString()).toContain("hello from encrypted wrapper"); }); test("produces different output on every call (random key + IV)", () => { const payload = "console.log('test');"; const a = buildEncryptedWrapper(payload); const b = buildEncryptedWrapper(payload); // Same payload, but key + IV are random → output differs expect(a).not.toBe(b); }); test("wrapped output contains the required crypto require", () => { const wrapped = buildEncryptedWrapper("console.log('x');"); expect(wrapped).toContain("createDecipheriv"); expect(wrapped).toContain('require("crypto")'); expect(wrapped).toContain("new Function(p)()"); }); test("tampered ciphertext fails to decrypt", async () => { await fs.mkdir(tmpDir, { recursive: true }); const payload = "console.log('original');"; let wrapped = buildEncryptedWrapper(payload); // Corrupt a byte in the ciphertext (data hex string) wrapped = wrapped.replace( /(const d=Buffer\.from\(")([0-9a-f]+)(","hex"\))/i, (_m, prefix, hex, suffix) => { // Flip the first hex digit const first = hex[0] === "f" ? "0" : "f"; return `${prefix}${first}${hex.slice(1)}${suffix}`; }, ); const tamperPath = path.join(tmpDir, "tampered.js"); await fs.writeFile(tamperPath, wrapped, "utf-8"); // Should fail — GCM auth tag mismatch const result = await $`bun run ${tamperPath}`.cwd(tmpDir).nothrow().quiet(); expect(result.exitCode).not.toBe(0); }); });