feat: ArtifactWriter auto-extension (artefact + doc) (v0.25.0)
Écrit un asset auto-créé (workflow/outil) + sa doc générée depuis le gabarit, chemins sanitizés (anti-traversée), semver validé. 5 tests (dépôt temp). Le dépôt fait foi avant tout passage en need-review. Palier de risque : reversible (écriture fichier locale, sans commit ni exécution). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
||||
import { mkdtemp, rm, readFile } from "node:fs/promises";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import {
|
||||
slugify,
|
||||
artifactRelPath,
|
||||
docRelPath,
|
||||
writeArtifact,
|
||||
type AssetDraft,
|
||||
} from "../src/autoext/artifact-writer.js";
|
||||
|
||||
const draft = (over: Partial<AssetDraft> = {}): AssetDraft => ({
|
||||
type: "workflow-n8n",
|
||||
name: "Backup Nextcloud",
|
||||
version: "1.0.0",
|
||||
riskTier: "privileged",
|
||||
summary: "Sauvegarde quotidienne.",
|
||||
content: '{"name":"x"}',
|
||||
...over,
|
||||
});
|
||||
|
||||
let root: string;
|
||||
beforeEach(async () => {
|
||||
root = await mkdtemp(join(tmpdir(), "chlova-"));
|
||||
});
|
||||
afterEach(async () => {
|
||||
await rm(root, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
describe("slugify & chemins", () => {
|
||||
it("slugifie un nom accentué", () => {
|
||||
expect(slugify("Sauvegarde Été #2")).toBe("sauvegarde-ete-2");
|
||||
});
|
||||
|
||||
it("refuse un nom vide", () => {
|
||||
expect(() => slugify(" ")).toThrow();
|
||||
});
|
||||
|
||||
it("chemins par type", () => {
|
||||
expect(artifactRelPath(draft())).toBe("workflows-n8n/backup-nextcloud.v1.0.0.json");
|
||||
expect(artifactRelPath(draft({ type: "tool" }))).toBe("tools/backup-nextcloud.v1.0.0.json");
|
||||
expect(docRelPath(draft())).toBe("docs/assets/workflow-n8n-backup-nextcloud.md");
|
||||
});
|
||||
});
|
||||
|
||||
describe("writeArtifact", () => {
|
||||
it("écrit artefact + doc", async () => {
|
||||
const { artifactPath, docPath } = await writeArtifact(root, draft());
|
||||
expect(await readFile(join(root, artifactPath), "utf8")).toBe('{"name":"x"}');
|
||||
const doc = await readFile(join(root, docPath), "utf8");
|
||||
expect(doc).toContain("Backup Nextcloud");
|
||||
expect(doc).toContain("v1.0.0");
|
||||
expect(doc).toContain("bloqué"); // privilégié → bloqué
|
||||
});
|
||||
|
||||
it("refuse une version non semver", async () => {
|
||||
await expect(writeArtifact(root, draft({ version: "1.0" }))).rejects.toThrow(/semver/);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user