rea/src/config.test.ts

160 lines
5.1 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { parseConfig } from "./config.js";
describe("runtime configuration", () => {
it("allows target-free startup and applies runtime defaults", () => {
const empty = parseConfig({});
expect(empty.ok).toBe(true);
if (empty.ok) {
expect(empty.value.hopperTargetPath).toBeUndefined();
expect(empty.value.analysisProvider).toBe("auto");
}
const result = parseConfig({ HOPPER_TARGET_PATH: "/usr/bin/true" });
expect(result.ok).toBe(true);
if (result.ok) {
expect(result.value.hopperTargetKind).toBe("executable");
expect(result.value.hopperLoaderArgs).toEqual([]);
expect(result.value.logLevel).toBe("info");
expect(result.value.referenceSourcePolicy).toEqual({
secretPatterns: [],
});
}
});
it("parses one shared provider selector and rejects unstable IDs", () => {
expect(
parseConfig({
REA_ANALYSIS_PROVIDER: "ida",
REA_IDA_MCP_CONFIG: "/tmp/ida-mcp.json",
}),
).toMatchObject({
ok: true,
value: { analysisProvider: "ida", idaMcpConfigPath: "/tmp/ida-mcp.json" },
});
expect(parseConfig({ REA_IDA_MCP_CONFIG: "relative.json" }).ok).toBe(false);
expect(parseConfig({ REA_ANALYSIS_PROVIDER: "ghidra" })).toMatchObject({
ok: true,
value: { analysisProvider: "ghidra" },
});
expect(parseConfig({ REA_ANALYSIS_PROVIDER: "auto" })).toMatchObject({
ok: true,
value: { analysisProvider: "auto" },
});
for (const invalid of ["", "Auto", "ghidra_1", "ghidra "])
expect(parseConfig({ REA_ANALYSIS_PROVIDER: invalid }).ok).toBe(false);
});
it("parses absolute BYO Ghidra and optional Java paths", () => {
expect(
parseConfig({
GHIDRA_INSTALL_DIR: "/opt/ghidra_12.1.4_PUBLIC",
JAVA_HOME: "/usr/lib/jvm/jdk-21",
}),
).toMatchObject({
ok: true,
value: {
ghidraInstallDir: "/opt/ghidra_12.1.4_PUBLIC",
ghidraJavaHome: "/usr/lib/jvm/jdk-21",
},
});
expect(parseConfig({ GHIDRA_INSTALL_DIR: "relative/ghidra" }).ok).toBe(
false,
);
expect(parseConfig({ JAVA_HOME: "relative/jdk" }).ok).toBe(false);
});
it("parses an optional absolute BYO ilspycmd path", () => {
expect(
parseConfig({ REA_ILSPY_CMD_PATH: "/home/user/.dotnet/tools/ilspycmd" }),
).toMatchObject({
ok: true,
value: {
ilspyCmdPath: "/home/user/.dotnet/tools/ilspycmd",
},
});
expect(parseConfig({ REA_ILSPY_CMD_PATH: "relative/ilspycmd" }).ok).toBe(
false,
);
});
});
describe("runtime target configuration", () => {
it("rejects invalid target kinds with actionable environment diagnostics", () => {
const result = parseConfig({ HOPPER_TARGET_KIND: "archive" });
expect(result.ok).toBe(false);
if (result.ok) throw new Error("Expected invalid target kind");
expect(result.error.message).toContain("Invalid REA environment");
});
it("parses database kind and loader arguments", () => {
expect(
parseConfig({
HOPPER_LAUNCHER_PATH: "/custom/hopper",
REA_ANALYSIS_PROVIDER: "hopper",
HOPPER_TARGET_PATH: "/fixture/sample.hop",
HOPPER_TARGET_KIND: "database",
HOPPER_LOADER_ARGS_JSON: '["-l","FAT","--aarch64","-l","Mach-O"]',
}),
).toMatchObject({
ok: true,
value: {
hopperLauncherPath: "/custom/hopper",
analysisProvider: "hopper",
hopperTargetPath: "/fixture/sample.hop",
hopperTargetKind: "database",
hopperLoaderArgs: ["-l", "FAT", "--aarch64", "-l", "Mach-O"],
logLevel: "info",
referenceSourcePolicy: {
secretPatterns: [],
},
},
});
});
});
describe("runtime collection configuration", () => {
it.each(["not-json", "{}", '"just a string"', '["ok",1]'])(
"rejects invalid loader args: %s",
(encoded) => {
const result = parseConfig({
HOPPER_TARGET_PATH: "/tmp/a",
HOPPER_LOADER_ARGS_JSON: encoded,
});
expect(result.ok).toBe(false);
if (result.ok)
throw new Error("expected malformed loader arguments to fail");
expect(result.error.message).toContain(
encoded === "not-json" ? "valid JSON" : "array of strings",
);
},
);
it("parses supported log levels and rejects unknown levels", () => {
const configured = parseConfig({ REA_LOG_LEVEL: "debug" });
expect(configured.ok && configured.value.logLevel).toBe("debug");
expect(parseConfig({ REA_LOG_LEVEL: "verbose" }).ok).toBe(false);
});
it("parses reference source secret patterns", () => {
const result = parseConfig({
REA_REFERENCE_SECRET_PATTERNS_JSON: '["*.env", "*.pem", "secrets/"]',
});
expect(result.ok).toBe(true);
if (result.ok) {
expect(result.value.referenceSourcePolicy).toEqual({
secretPatterns: ["*.env", "*.pem", "secrets/"],
});
}
});
it.each(["not-json", "{}", '["*.ok", 1]'])(
"rejects invalid reference source secret patterns: %s",
(encoded) => {
expect(
parseConfig({ REA_REFERENCE_SECRET_PATTERNS_JSON: encoded }).ok,
).toBe(false);
},
);
});