Files
chlova/orchestrator/test/repository.test.ts
T
Kantin-Petit 56e948c976 feat: AssetRepository SQLite + cycle need-review persistant (v0.10.0)
Table assets sur node:sqlite (Node 24, zéro dep native) : CRUD,
listByStatus, incrementExec, setRiskTier anti-escalade, expireProvisional
(cron PROVISOIRE→BLOQUÉ). 6 tests. Bump Node 24 (sqlite stable), Dockerfile
24.13 + copie tsconfig.build.json. 0 vuln.

Palier de risque : reversible (persistance d'état, aucune mutation d'infra).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 01:24:35 +02:00

58 lines
2.5 KiB
TypeScript

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");
});
});