mesh-vault provides `secret` (novox/hq ADR 0085, design 24). The value is the pair credential the controller mints — the vault holds no copy, only a ledger of who holds one, its fingerprint and every rotation, and two tools that answer by fingerprint and never by value. Rotation is `rotate secret`, unchanged machinery pointed at a secret with an owner (design 13). Named in the mesh's own namespace, beside mesh-controller and mesh-catalog, because it is the mesh's own code rather than wrapped software. redis is the first consumer: its own password stops being an own-secret nothing could rotate and becomes a `secret` it requires, read from the same file into the same hole. The server now restarts on its config, or it would keep the password it started with through every rotation (playbook 06).
81 lines
3.8 KiB
TypeScript
81 lines
3.8 KiB
TypeScript
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/);
|
|
});
|