tests / judge.test.ts
import { describe, expect, it, vi } from "vitest";
import { assess, jevAssessor, QUESTIONS, resolveApiKey, type JevClient } from "../src/judge";
function fakeClient(answers: Record<string, unknown>) {
const systemOne = vi.fn().mockResolvedValue({ answers });
return { client: { systemOne } as unknown as JevClient, systemOne };
}
const goodAnswers = {
destroys_data: { noul: 0.9 },
touches_system: { noul: 0.1 },
network_exfil: { noul: 0.05 },
privilege_or_persistence: { noul: 0.2 },
obfuscated: { noul: 0.0 },
severity: { score: 2.4 },
};
describe("assess", () => {
it("maps jev answers into an Assessment", async () => {
const { client } = fakeClient(goodAnswers);
const result = await assess(client, { command: "rm -rf build", cwd: "/repo" });
expect(result.hazards).toEqual({
destroys_data: 0.9,
touches_system: 0.1,
network_exfil: 0.05,
privilege_or_persistence: 0.2,
obfuscated: 0,
});
expect(result.severity).toBe(2.4);
});
it("sends the command, cwd and platform as named state and all six questions in one request", async () => {
const { client, systemOne } = fakeClient(goodAnswers);
await assess(client, { command: "ls", cwd: "/repo" });
expect(systemOne).toHaveBeenCalledTimes(1);
const [request, options] = systemOne.mock.calls[0];
expect(request.state).toMatchObject({ command: "ls", cwd: "/repo", platform: process.platform });
expect(Object.keys(request.questions).sort()).toEqual(Object.keys(QUESTIONS).sort());
expect(Object.keys(request.questions)).toHaveLength(6);
expect(options.signal).toBeInstanceOf(AbortSignal);
});
it("rejects a malformed answer instead of treating it as safe", async () => {
const { client } = fakeClient({ ...goodAnswers, destroys_data: { noul: NaN } });
await expect(assess(client, { command: "ls", cwd: "/" })).rejects.toThrow(/destroys_data/);
const { client: client2 } = fakeClient({ ...goodAnswers, severity: { score: undefined } });
await expect(assess(client2, { command: "ls", cwd: "/" })).rejects.toThrow(/severity/);
});
it("rejects out-of-range hazard probabilities and severities", async () => {
for (const noul of [1.5, -0.1]) {
const { client } = fakeClient({ ...goodAnswers, destroys_data: { noul } });
await expect(assess(client, { command: "ls", cwd: "/" })).rejects.toThrow(/destroys_data/);
}
for (const score of [-1, 3.5]) {
const { client } = fakeClient({ ...goodAnswers, severity: { score } });
await expect(assess(client, { command: "ls", cwd: "/" })).rejects.toThrow(/severity/);
}
});
it("accepts boundary values", async () => {
for (const [noul, score] of [[0, 0], [1, 3]]) {
const { client } = fakeClient({ ...goodAnswers, destroys_data: { noul }, severity: { score } });
const result = await assess(client, { command: "ls", cwd: "/" });
expect(result.hazards.destroys_data).toBe(noul);
expect(result.severity).toBe(score);
}
});
it("propagates client errors", async () => {
const client = { systemOne: vi.fn().mockRejectedValue(new Error("network down")) } as unknown as JevClient;
await expect(assess(client, { command: "ls", cwd: "/" })).rejects.toThrow("network down");
});
});
describe("resolveApiKey", () => {
it("prefers the plugin setting over the environment", () => {
expect(resolveApiKey("from-settings", { JEV_API_KEY: "from-env" })).toBe("from-settings");
});
it("trims the setting", () => {
expect(resolveApiKey(" padded ", {})).toBe("padded");
});
it("falls back to JEV_API_KEY when the setting is blank or missing", () => {
expect(resolveApiKey("", { JEV_API_KEY: "from-env" })).toBe("from-env");
expect(resolveApiKey(" ", { JEV_API_KEY: " from-env " })).toBe("from-env");
expect(resolveApiKey(undefined, { JEV_API_KEY: "from-env" })).toBe("from-env");
});
it("returns undefined when neither is set", () => {
expect(resolveApiKey("", {})).toBeUndefined();
expect(resolveApiKey(undefined, { JEV_API_KEY: " " })).toBeUndefined();
});
});
describe("jevAssessor", () => {
it("rejects with a message naming both places to set the key when none is available", async () => {
const failure = jevAssessor(() => undefined)({ command: "ls", cwd: "/" });
await expect(failure).rejects.toThrow(/plugin settings/);
await expect(jevAssessor(() => undefined)({ command: "ls", cwd: "/" })).rejects.toThrow(/JEV_API_KEY/);
});
it("treats a blank key as missing", async () => {
await expect(jevAssessor(() => " ")({ command: "ls", cwd: "/" })).rejects.toThrow(/no jev API key/);
});
it("asks for the key on every call so changed settings apply without a reload", async () => {
const getKey = vi.fn<() => string | undefined>(() => undefined);
const assessor = jevAssessor(getKey);
await assessor({ command: "ls", cwd: "/" }).catch(() => undefined);
await assessor({ command: "ls", cwd: "/" }).catch(() => undefined);
expect(getKey).toHaveBeenCalledTimes(2);
});
});
tests / judge.test.ts
import { describe, expect, it, vi } from "vitest";
import { assess, jevAssessor, QUESTIONS, resolveApiKey, type JevClient } from "../src/judge";
function fakeClient(answers: Record<string, unknown>) {
const systemOne = vi.fn().mockResolvedValue({ answers });
return { client: { systemOne } as unknown as JevClient, systemOne };
}
const goodAnswers = {
destroys_data: { noul: 0.9 },
touches_system: { noul: 0.1 },
network_exfil: { noul: 0.05 },
privilege_or_persistence: { noul: 0.2 },
obfuscated: { noul: 0.0 },
severity: { score: 2.4 },
};
describe("assess", () => {
it("maps jev answers into an Assessment", async () => {
const { client } = fakeClient(goodAnswers);
const result = await assess(client, { command: "rm -rf build", cwd: "/repo" });
expect(result.hazards).toEqual({
destroys_data: 0.9,
touches_system: 0.1,
network_exfil: 0.05,
privilege_or_persistence: 0.2,
obfuscated: 0,
});
expect(result.severity).toBe(2.4);
});
it("sends the command, cwd and platform as named state and all six questions in one request", async () => {
const { client, systemOne } = fakeClient(goodAnswers);
await assess(client, { command: "ls", cwd: "/repo" });
expect(systemOne).toHaveBeenCalledTimes(1);
const [request, options] = systemOne.mock.calls[0];
expect(request.state).toMatchObject({ command: "ls", cwd: "/repo", platform: process.platform });
expect(Object.keys(request.questions).sort()).toEqual(Object.keys(QUESTIONS).sort());
expect(Object.keys(request.questions)).toHaveLength(6);
expect(options.signal).toBeInstanceOf(AbortSignal);
});
it("rejects a malformed answer instead of treating it as safe", async () => {
const { client } = fakeClient({ ...goodAnswers, destroys_data: { noul: NaN } });
await expect(assess(client, { command: "ls", cwd: "/" })).rejects.toThrow(/destroys_data/);
const { client: client2 } = fakeClient({ ...goodAnswers, severity: { score: undefined } });
await expect(assess(client2, { command: "ls", cwd: "/" })).rejects.toThrow(/severity/);
});
it("rejects out-of-range hazard probabilities and severities", async () => {
for (const noul of [1.5, -0.1]) {
const { client } = fakeClient({ ...goodAnswers, destroys_data: { noul } });
await expect(assess(client, { command: "ls", cwd: "/" })).rejects.toThrow(/destroys_data/);
}
for (const score of [-1, 3.5]) {
const { client } = fakeClient({ ...goodAnswers, severity: { score } });
await expect(assess(client, { command: "ls", cwd: "/" })).rejects.toThrow(/severity/);
}
});
it("accepts boundary values", async () => {
for (const [noul, score] of [[0, 0], [1, 3]]) {
const { client } = fakeClient({ ...goodAnswers, destroys_data: { noul }, severity: { score } });
const result = await assess(client, { command: "ls", cwd: "/" });
expect(result.hazards.destroys_data).toBe(noul);
expect(result.severity).toBe(score);
}
});
it("propagates client errors", async () => {
const client = { systemOne: vi.fn().mockRejectedValue(new Error("network down")) } as unknown as JevClient;
await expect(assess(client, { command: "ls", cwd: "/" })).rejects.toThrow("network down");
});
});
describe("resolveApiKey", () => {
it("prefers the plugin setting over the environment", () => {
expect(resolveApiKey("from-settings", { JEV_API_KEY: "from-env" })).toBe("from-settings");
});
it("trims the setting", () => {
expect(resolveApiKey(" padded ", {})).toBe("padded");
});
it("falls back to JEV_API_KEY when the setting is blank or missing", () => {
expect(resolveApiKey("", { JEV_API_KEY: "from-env" })).toBe("from-env");
expect(resolveApiKey(" ", { JEV_API_KEY: " from-env " })).toBe("from-env");
expect(resolveApiKey(undefined, { JEV_API_KEY: "from-env" })).toBe("from-env");
});
it("returns undefined when neither is set", () => {
expect(resolveApiKey("", {})).toBeUndefined();
expect(resolveApiKey(undefined, { JEV_API_KEY: " " })).toBeUndefined();
});
});
describe("jevAssessor", () => {
it("rejects with a message naming both places to set the key when none is available", async () => {
const failure = jevAssessor(() => undefined)({ command: "ls", cwd: "/" });
await expect(failure).rejects.toThrow(/plugin settings/);
await expect(jevAssessor(() => undefined)({ command: "ls", cwd: "/" })).rejects.toThrow(/JEV_API_KEY/);
});
it("treats a blank key as missing", async () => {
await expect(jevAssessor(() => " ")({ command: "ls", cwd: "/" })).rejects.toThrow(/no jev API key/);
});
it("asks for the key on every call so changed settings apply without a reload", async () => {
const getKey = vi.fn<() => string | undefined>(() => undefined);
const assessor = jevAssessor(getKey);
await assessor({ command: "ls", cwd: "/" }).catch(() => undefined);
await assessor({ command: "ls", cwd: "/" }).catch(() => undefined);
expect(getKey).toHaveBeenCalledTimes(2);
});
});