AUDIT / src /lib /__tests__ /capabilityPolicy.test.ts
Arypulka98's picture
feat(audit): deploy full backend cluster node (part 2)
cc11e77 verified
Raw
History Blame Contribute Delete
8.23 kB
/**
* capabilityPolicy.test.ts — Unit test S25
*
* capabilityPolicy è un modulo PURO (zero imports di runtime) →
* nessun mock necessario, tutto testabile in isolamento.
*
* Copertura:
* - checkPolicy: safe / medium / risky / dangerous / unknown
* - requiresConfirm: tutti i livelli di rischio
* - getRisk: spot checks
* - listPolicyRules: completezza e assenza duplicati
* - preview: troncatura a 200 chars
*/
import { describe, it, expect } from "vitest";
import {
checkPolicy,
requiresConfirm,
getRisk,
listPolicyRules,
} from "@/lib/capabilityPolicy";
// ─── checkPolicy ─────────────────────────────────────────────────────────────
describe("checkPolicy", () => {
it("web_search → safe, allowed=true, preview contiene la query", () => {
const r = checkPolicy("web_search", { query: "typescript vitest" });
expect(r.risk).toBe("safe");
expect(r.allowed).toBe(true);
expect(r.preview).toContain("typescript vitest");
expect(r.tool).toBe("web_search");
});
it("read_file → safe, allowed=true, preview contiene il path", () => {
const r = checkPolicy("read_file", { path: "/src/main.ts" });
expect(r.risk).toBe("safe");
expect(r.allowed).toBe(true);
expect(r.preview).toContain("/src/main.ts");
});
it("write_file → medium, allowed=true", () => {
const r = checkPolicy("write_file", { path: "/out.ts", content: "x" });
expect(r.risk).toBe("medium");
expect(r.allowed).toBe(true);
});
it("pip_install → medium, allowed=true", () => {
const r = checkPolicy("pip_install", { package: "numpy" });
expect(r.risk).toBe("medium");
expect(r.allowed).toBe(true);
});
it("github_push → risky, allowed=true (richiede confirm ma non è bloccato)", () => {
const r = checkPolicy("github_push", { branch: "main", message: "feat: test" });
expect(r.risk).toBe("risky");
expect(r.allowed).toBe(true); // risky è allowed, ma requiresConfirm=true
});
it("exec_code_backend → risky, allowed=true", () => {
const r = checkPolicy("exec_code_backend", { lang: "python", code: "print(1)" });
expect(r.risk).toBe("risky");
expect(r.allowed).toBe(true);
expect(r.preview).toContain("python");
});
it("delete_file → dangerous, allowed=false (blocco automatico)", () => {
const r = checkPolicy("delete_file", { path: "/critical.ts" });
expect(r.risk).toBe("dangerous");
expect(r.allowed).toBe(false); // dangerous non è mai allowed automaticamente
expect(r.preview).toContain("/critical.ts");
});
it("clear_memory → dangerous, allowed=false", () => {
const r = checkPolicy("clear_memory", {});
expect(r.risk).toBe("dangerous");
expect(r.allowed).toBe(false);
});
it("clear_all_files → dangerous, allowed=false", () => {
const r = checkPolicy("clear_all_files", {});
expect(r.risk).toBe("dangerous");
expect(r.allowed).toBe(false);
});
it("tool sconosciuto → risky (default sicuro), allowed=true", () => {
const r = checkPolicy("non_existent_tool_xyz", {});
expect(r.risk).toBe("risky");
expect(r.allowed).toBe(true);
expect(r.label).toBe("Azione sconosciuta");
});
it("preview è sempre ≤200 chars anche con query lunghissima", () => {
const longQuery = "a".repeat(500);
const r = checkPolicy("web_search", { query: longQuery });
expect(r.preview.length).toBeLessThanOrEqual(200);
});
it("checkPolicy senza args non crasha", () => {
expect(() => checkPolicy("recall")).not.toThrow();
expect(() => checkPolicy("delete_file")).not.toThrow();
});
it("safe tools: recall, search_github, get_weather, get_news", () => {
const safeTools = ["recall", "search_github", "get_weather", "get_news", "search_wikipedia"];
for (const tool of safeTools) {
const r = checkPolicy(tool, {});
expect(r.risk, `${tool} dovrebbe essere safe`).toBe("safe");
expect(r.allowed).toBe(true);
}
});
});
// ─── requiresConfirm ─────────────────────────────────────────────────────────
describe("requiresConfirm", () => {
it("tools safe → false", () => {
expect(requiresConfirm("web_search")).toBe(false);
expect(requiresConfirm("read_file")).toBe(false);
expect(requiresConfirm("recall")).toBe(false);
expect(requiresConfirm("get_weather")).toBe(false);
});
it("tools medium → false (no confirm, ma UI notifica)", () => {
expect(requiresConfirm("write_file")).toBe(false);
expect(requiresConfirm("pip_install")).toBe(false);
expect(requiresConfirm("remember")).toBe(false);
});
it("tools risky → true", () => {
expect(requiresConfirm("github_push")).toBe(true);
expect(requiresConfirm("exec_code_backend")).toBe(true);
});
it("tools dangerous → true", () => {
expect(requiresConfirm("delete_file")).toBe(true);
expect(requiresConfirm("clear_memory")).toBe(true);
expect(requiresConfirm("clear_all_files")).toBe(true);
});
it("tool sconosciuto → true (fail-safe)", () => {
expect(requiresConfirm("unknown_tool_abc")).toBe(true);
});
});
// ─── getRisk ─────────────────────────────────────────────────────────────────
describe("getRisk", () => {
it("ritorna il livello corretto per ogni categoria", () => {
expect(getRisk("web_search")).toBe("safe");
expect(getRisk("read_file")).toBe("safe");
expect(getRisk("write_file")).toBe("medium");
expect(getRisk("pip_install")).toBe("medium");
expect(getRisk("github_push")).toBe("risky");
expect(getRisk("delete_file")).toBe("dangerous");
expect(getRisk("clear_all_files")).toBe("dangerous");
});
it("tool sconosciuto → risky (default)", () => {
expect(getRisk("completely_unknown_xyz")).toBe("risky");
});
});
// ─── listPolicyRules ─────────────────────────────────────────────────────────
describe("listPolicyRules", () => {
it("ritorna almeno 20 regole (obiettivo S25)", () => {
const rules = listPolicyRules();
expect(rules.length).toBeGreaterThanOrEqual(20);
});
it("ogni regola ha tool (string), risk (valido), label, description", () => {
const validRisks = new Set(["safe", "medium", "risky", "dangerous"]);
const rules = listPolicyRules();
for (const r of rules) {
expect(typeof r.tool).toBe("string");
expect(r.tool.length, `tool vuoto in rule: ${JSON.stringify(r)}`).toBeGreaterThan(0);
expect(validRisks.has(r.risk), `risk '${r.risk}' non valido`).toBe(true);
expect(typeof r.label).toBe("string");
expect(typeof r.description).toBe("string");
}
});
it("nessun tool duplicato nel registry", () => {
const rules = listPolicyRules();
const names = rules.map(r => r.tool);
const unique = new Set(names);
expect(unique.size).toBe(names.length);
});
it("ogni categoria di rischio ha almeno 1 tool", () => {
const rules = listPolicyRules();
const bySafe = rules.filter(r => r.risk === "safe");
const byMedium = rules.filter(r => r.risk === "medium");
const byRisky = rules.filter(r => r.risk === "risky");
const byDangerous = rules.filter(r => r.risk === "dangerous");
expect(bySafe.length, "safe tools").toBeGreaterThan(0);
expect(byMedium.length, "medium tools").toBeGreaterThan(0);
expect(byRisky.length, "risky tools").toBeGreaterThan(0);
expect(byDangerous.length, "dangerous tools").toBeGreaterThan(0);
});
it("listPolicyRules ritorna copia (modifica non altera il registry)", () => {
const rules = listPolicyRules();
rules.push({ tool: "fake_hack", risk: "safe", label: "x", description: "x" });
const rules2 = listPolicyRules();
expect(rules2.some(r => r.tool === "fake_hack")).toBe(false);
});
});