import { describe, it, expect, beforeEach, afterEach } from "vitest"; import { AssetRepository } from "../src/gatekeeper/repository.js"; import { createAsset, EscalationError, PROVISIONAL_TTL_MS } from "../src/gatekeeper/assets.js"; let repo: AssetRepository; beforeEach(() => { repo = new AssetRepository(":memory:"); }); afterEach(() => { repo.close(); }); describe("AssetRepository", () => { it("crée et relit un asset", () => { const a = createAsset({ id: "a", type: "tool", version: "1.0.0", riskTier: "reversible", now: 1000 }); repo.create(a); expect(repo.get("a")).toEqual(a); }); it("liste par statut", () => { repo.create(createAsset({ id: "r", type: "tool", version: "1.0.0", riskTier: "reversible" })); repo.create(createAsset({ id: "p", type: "stack-portainer", version: "1.0.0", riskTier: "privileged" })); expect(repo.listByStatus("provisoire").map((x) => x.id)).toEqual(["r"]); expect(repo.listByStatus("bloqué").map((x) => x.id)).toEqual(["p"]); }); it("incrémente le compteur d'exécution", () => { repo.create(createAsset({ id: "a", type: "tool", version: "1.0.0", riskTier: "reversible" })); expect(repo.incrementExec("a")).toBe(1); expect(repo.incrementExec("a")).toBe(2); }); it("setRiskTier refuse l'escalade privileged→reversible", () => { repo.create(createAsset({ id: "p", type: "stack-portainer", version: "1.0.0", riskTier: "privileged" })); expect(() => repo.setRiskTier("p", "reversible")).toThrow(EscalationError); // le palier n'a pas changé expect(repo.get("p")?.riskTier).toBe("privileged"); }); it("expireProvisional bascule les provisoires échus en bloqué", () => { const t0 = 1_000_000; repo.create(createAsset({ id: "old", type: "tool", version: "1.0.0", riskTier: "reversible", now: t0 })); repo.create(createAsset({ id: "fresh", type: "tool", version: "1.0.0", riskTier: "reversible", now: t0 })); // bascule à un instant juste après l'expiration de "old" mais on garde "fresh" frais const switched = repo.expireProvisional(t0 + PROVISIONAL_TTL_MS + 1); expect(switched).toEqual(expect.arrayContaining(["old", "fresh"])); expect(repo.get("old")?.status).toBe("bloqué"); }); it("n'expire rien avant l'échéance", () => { const t0 = 1_000_000; repo.create(createAsset({ id: "a", type: "tool", version: "1.0.0", riskTier: "reversible", now: t0 })); expect(repo.expireProvisional(t0 + 1)).toEqual([]); expect(repo.get("a")?.status).toBe("provisoire"); }); });