import assert from "node:assert/strict"; import { mkdtemp, mkdir, rm, symlink, writeFile } from "node:fs/promises"; import os from "node:os"; import path from "node:path"; import test from "node:test"; import { formatQuixosLock, formatQuixosLockDocument, loadQuixosLock, nixGitInput, parseQuixosLock, parseQuixosLockDocument, resolveQuixosLock, retentionTagForCommit, } from "../src/resource-lock/index.js"; const quixosCommit = "1".repeat(40); const namedCommit = "2".repeat(40); const packageCommit = "3".repeat(64); const fixture = `quixos-lock version 1 { quixos source { repository "https://gitea.example/quixos/quixos.git"; policy track-development; ref "dev/alice/main"; commit "${quixosCommit}"; } interface Named source { repository "https://repos.example/alice/interface-named.git"; commit "${namedCommit}"; } package TodoRuntime source { repository "ssh://git@repos.example/alice/package-todo-runtime.git"; commit "${packageCommit}"; } } `; test("parses and canonically formats a Git-only repository lock", () => { const parsed = parseQuixosLock(fixture, "quixos.lock"); assert.equal(parsed.ok, true); if (!parsed.ok) return; assert.equal(parsed.lock.formatVersion, 1); assert.equal(parsed.lock.quixos.commit, quixosCommit); assert.equal(parsed.lock.quixos.policy, "track-development"); assert.equal(parsed.lock.quixos.ref, "dev/alice/main"); assert.deepEqual( parsed.lock.resources.map(({ kind, binding }) => ({ kind, binding })), [ { kind: "interface", binding: "Named" }, { kind: "package", binding: "TodoRuntime" }, ], ); assert.deepEqual(parseQuixosLock(formatQuixosLock(parsed.lock)), { ok: true, lock: parsed.lock, diagnostics: [], }); }); test("validates pinned Quixos selections without imposing policy on resource locks", () => { const mismatch = parseQuixosLockDocument(`quixos-lock version 1 { quixos source { repository "https://gitea.example/quixos/quixos.git"; policy pinned; ref "${namedCommit}"; commit "${quixosCommit}"; } }`); assert.equal(mismatch.ok, false); if (!mismatch.ok) { assert.equal(mismatch.diagnostics[0]?.code, "pinned-quixos-commit-mismatch"); } const resourceBaseline = parseQuixosLockDocument(`quixos-lock version 1 { quixos source { repository "https://gitea.example/quixos/quixos.git"; commit "${quixosCommit}"; } }`); assert.equal(resourceBaseline.ok, true); }); test("derives immutable retention and Nix inputs without storing extra identity", () => { const source = { resolver: "git" as const, repository: "https://repos.example/alice/interface-named.git", commit: namedCommit, }; const ref = `refs/tags/quixos-reachability/${namedCommit}`; assert.equal(retentionTagForCommit(namedCommit.toUpperCase()), ref); assert.deepEqual(nixGitInput(source), { type: "git", url: source.repository, ref, rev: namedCommit, }); }); test("rejects mutable revisions, embedded credentials, and duplicate bindings", () => { const parsed = parseQuixosLock(`quixos-lock version 1 { quixos source { repository "https://user:secret@example/quixos.git"; commit "main"; } interface Named source { repository "file:///tmp/named"; commit "${namedCommit}"; } interface Named source { repository "https://repos.example/named.git?ref=main"; commit "${namedCommit}"; } }`); assert.equal(parsed.ok, false); if (parsed.ok) return; assert.deepEqual( new Set(parsed.diagnostics.map((entry) => entry.code)), new Set([ "invalid-git-commit", "embedded-git-credential", "unsupported-git-transport", "decorated-git-repository", "duplicate-resource-binding", ]), ); }); test("resolves root-relative lock fragments into one deterministic resource closure", async () => { const root = `quixos-lock version 1 { quixos source { repository "https://gitea.example/quixos/quixos.git"; commit "${quixosCommit}"; } import "locks/web-studio.lock"; import "locks/domain.lock"; package RootRuntime source { repository "https://repos.example/alice/package-root.git"; commit "${packageCommit}"; } }`; const sources = new Map([ [ "locks/web-studio.lock", `quixos-lock fragment version 1 { import "locks/shared.lock"; interface Placeable source { repository "https://repos.example/alice/interface-placeable.git"; commit "${namedCommit}"; } }`, ], [ "locks/shared.lock", `quixos-lock fragment version 1 { interface Named source { repository "https://repos.example/alice/interface-named.git"; commit "${namedCommit}"; } }`, ], [ "locks/domain.lock", `quixos-lock fragment version 1 { package TodoRuntime source { repository "https://repos.example/alice/package-todo.git"; commit "${packageCommit}"; } }`, ], ]); const result = await resolveQuixosLock(root, async (relativePath) => { const source = sources.get(relativePath); if (!source) throw new Error("missing fixture"); return source; }); assert.equal(result.ok, true); if (!result.ok) return; assert.deepEqual(result.lock.sourceFiles, [ "quixos.lock", "locks/web-studio.lock", "locks/shared.lock", "locks/domain.lock", ]); assert.deepEqual( result.lock.resources.map(({ kind, binding }) => ({ kind, binding })), [ { kind: "package", binding: "RootRuntime" }, { kind: "interface", binding: "Placeable" }, { kind: "interface", binding: "Named" }, { kind: "package", binding: "TodoRuntime" }, ], ); }); test("lock fragments format canonically and cannot redeclare the Quixos source", () => { const document = { kind: "fragment" as const, formatVersion: 1 as const, imports: ["locks/shared.lock"], resources: [ { kind: "interface" as const, binding: "Named", source: { resolver: "git" as const, repository: "https://repos.example/alice/interface-named.git", commit: namedCommit, }, }, ], }; assert.deepEqual(parseQuixosLockDocument(formatQuixosLockDocument(document)), { ok: true, document, diagnostics: [], }); const invalid = parseQuixosLockDocument( `quixos-lock fragment version 1 { quixos source { repository "https://gitea.example/quixos/quixos.git"; commit "${quixosCommit}"; } }`, "bad.lock", ); assert.equal(invalid.ok, false); if (!invalid.ok) assert.equal(invalid.diagnostics[0]?.code, "fragment-has-quixos-source"); }); test("lock imports reject traversal, cycles, root documents, and cross-file binding collisions", async () => { const invalidPath = parseQuixosLockDocument( `quixos-lock fragment version 1 { import "../outside.lock"; }`, "bad-path.lock", ); assert.equal(invalidPath.ok, false); if (!invalidPath.ok) assert.equal(invalidPath.diagnostics[0]?.code, "invalid-import-path"); const root = `quixos-lock version 1 { quixos source { repository "https://gitea.example/quixos/quixos.git"; commit "${quixosCommit}"; } import "a.lock"; import "root-again.lock"; interface Named source { repository "https://repos.example/alice/interface-named.git"; commit "${namedCommit}"; } }`; const sources = new Map([ [ "a.lock", `quixos-lock fragment version 1 { import "b.lock"; interface Named source { repository "https://repos.example/alice/interface-named-copy.git"; commit "${namedCommit}"; } }`, ], ["b.lock", `quixos-lock fragment version 1 { import "a.lock"; }`], ["root-again.lock", root], ]); const result = await resolveQuixosLock(root, async (relativePath) => sources.get(relativePath) ?? ""); assert.equal(result.ok, false); if (!result.ok) { assert.deepEqual( new Set(result.diagnostics.map(({ code }) => code)), new Set(["duplicate-resource-binding", "import-cycle", "imported-root-lock"]), ); } }); test("file loading rejects a symlink in any import path component", async (context) => { const directory = await mkdtemp(path.join(os.tmpdir(), "quixos-lock-test-")); context.after(() => rm(directory, { recursive: true, force: true })); const outside = path.join(directory, "outside"); await mkdir(outside); await writeFile(path.join(outside, "fragment.lock"), "quixos-lock fragment version 1 {}\n"); await symlink(outside, path.join(directory, "linked"), "dir"); await writeFile( path.join(directory, "quixos.lock"), `quixos-lock version 1 { quixos source { repository "https://gitea.example/quixos/quixos.git"; commit "${quixosCommit}"; } import "linked/fragment.lock"; }`, ); const result = await loadQuixosLock(path.join(directory, "quixos.lock")); assert.equal(result.ok, false); if (!result.ok) { assert.equal(result.diagnostics[0]?.code, "import-read-failed"); assert.match(result.diagnostics[0]?.message ?? "", /symbolic links/); } });