Files
quixos-protocol/test/resource-lock.test.ts
T

278 lines
8.9 KiB
TypeScript

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