73 lines
2.6 KiB
TypeScript
73 lines
2.6 KiB
TypeScript
// 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);
|
|
});
|
|
});
|