import { test } from "node:test"; import assert from "node:assert/strict"; import { mkdtempSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { Ledger, fingerprint, contributions, deliveredFingerprint } from "../client.ts"; function fresh(): Ledger { return new Ledger(mkdtempSync(join(tmpdir(), "vault-ledger-"))); } test("a first delivery is a grant, the same value again is nothing, a new value is a rotation", () => { const ledger = fresh(); const t0 = new Date("2026-09-20T10:00:00Z"); const t1 = new Date("2026-09-21T10:00:00Z"); const granted = ledger.record("anchor-redis", "anchor", "first-value", t0); assert.equal(granted.outcome, "granted"); assert.equal(granted.held.rotations, 0); assert.equal(granted.held.since, t0.toISOString()); assert.equal(granted.held.fingerprint, fingerprint("first-value")); assert.equal(ledger.record("anchor-redis", "anchor", "first-value", t1).outcome, "unchanged"); assert.equal(ledger.get("anchor-redis")!.rotations, 0, "an unchanged delivery counted as a rotation"); const rotated = ledger.record("anchor-redis", "anchor", "second-value", t1); assert.equal(rotated.outcome, "rotated"); assert.equal(rotated.held.rotations, 1); assert.equal(rotated.held.since, t0.toISOString(), "a rotation reset the grant date"); assert.equal(rotated.held.changed, t1.toISOString()); assert.equal(rotated.held.fingerprint, fingerprint("second-value")); assert.deepEqual(rotated.held.history, [{ fingerprint: fingerprint("first-value"), until: t1.toISOString() }]); }); test("the ledger holds fingerprints and never the value, in files nobody else can read", () => { const dir = mkdtempSync(join(tmpdir(), "vault-ledger-")); const ledger = new Ledger(dir); ledger.record("anchor-redis", "anchor", "the-actual-password", new Date()); ledger.record("anchor-redis", "anchor", "the-rotated-password", new Date()); for (const name of readdirSync(dir)) { const raw = readFileSync(join(dir, name), "utf8"); assert.doesNotMatch(raw, /the-actual-password|the-rotated-password/, `${name} holds a value`); assert.equal(statSync(join(dir, name)).mode & 0o777, 0o600, `${name} is readable by others`); } }); test("withdrawing forgets a holder, and listing is by login", () => { const ledger = fresh(); ledger.record("b-app", "b", "x", new Date()); ledger.record("a-app", "a", "y", new Date()); assert.deepEqual(ledger.list().map((h) => h.as), ["a-app", "b-app"]); assert.equal(ledger.withdraw("a-app"), true); assert.equal(ledger.withdraw("a-app"), false, "withdrawing twice said it found something"); assert.deepEqual(ledger.list().map((h) => h.as), ["b-app"]); }); test("a login is a name, not a path", () => { const ledger = fresh(); assert.throws(() => ledger.record("../etc/passwd", "n", "v"), /a login is a name/); }); test("what the mesh delivers is read from the contributions file and fingerprinted, never returned", () => { const dir = mkdtempSync(join(tmpdir(), "vault-grants-")); const secret = join(dir, "anchor.redis.secret"); writeFileSync(secret, "minted-value\n"); // the host may leave a trailing newline; the value has none const receives = join(dir, "mesh.json"); writeFileSync(receives, JSON.stringify({ requirement: "secret", given: [ { from: "redis", node: "anchor", as: "anchor-redis", secret }, { from: "offer-only", node: "anchor" }, // a contribution with no login grants nothing ], })); const asked = contributions(receives); assert.deepEqual(asked.map((c) => c.as), ["anchor-redis"]); const seen = deliveredFingerprint(asked[0]); assert.deepEqual(seen, { fingerprint: fingerprint("minted-value"), length: "minted-value".length }); assert.match(JSON.stringify(deliveredFingerprint({ as: "x", secret: join(dir, "missing") })), /not readable/); });