provisioner: a provider consumes the mesh's credential, seals nothing (ADR 0053)

runProvisioner now reconciles the mesh's `receives` contributions: for each
consumer it reads the mesh-minted password from the file the host unsealed and calls
the adapter to create the resource under the login the mesh derived. The adapter is
create({as,password,values}) / remove({as}), returning nothing — the consumer
already receives its copy through the mesh's own asymmetric channel. $MESH_SEAL_KEY,
the symmetric seal()/writeSealedCredential path, and the *.grant.json / *.credential
files are gone; the seal()/unseal() primitive had no other caller and was removed.

Claude-Session: https://claude.ai/code/session_01LrgweAeERJYBg88c5cKDzF
This commit is contained in:
2026-09-05 00:27:24 +02:00
parent 6ef6c761b2
commit 436f12edce
2 changed files with 103 additions and 112 deletions
+4 -36
View File
@@ -1,42 +1,10 @@
// Small, stable primitives every module's code may need. No behaviour here changes when a module
// changes; that is the whole point of it living in the sdk.
import { createCipheriv, createDecipheriv, randomBytes, scryptSync } from "node:crypto";
// --- sealing ---
//
// A secret is sealed to a key so a copy of it at rest is not a working credential. AES-256-GCM;
// the key is derived from a per-node passphrase the host holds. The host unseals on the machine;
// nothing else does (novox/hq ADR 0043's link is the boundary — the sdk only carries the mechanism).
const MAGIC = "msk1"; // versions the sealed format, so it can change without silent misreads
/** Seal plaintext to a passphrase. Returns `msk1:<salt>:<iv>:<tag>:<ciphertext>`, base64 parts. */
export function seal(plaintext: string, passphrase: string): string {
const salt = randomBytes(16);
const iv = randomBytes(12);
const key = scryptSync(passphrase, salt, 32);
const cipher = createCipheriv("aes-256-gcm", key, iv);
const enc = Buffer.concat([cipher.update(plaintext, "utf8"), cipher.final()]);
const tag = cipher.getAuthTag();
return [MAGIC, b64(salt), b64(iv), b64(tag), b64(enc)].join(":");
}
/** Unseal what seal produced. Throws — loudly — on any tamper or wrong key. */
export function unseal(sealed: string, passphrase: string): string {
const parts = sealed.split(":");
if (parts.length !== 5 || parts[0] !== MAGIC) {
throw new Error("not a sealed value this version understands");
}
const [, salt, iv, tag, enc] = parts.map((p, i) => (i === 0 ? Buffer.alloc(0) : ub64(p)));
const key = scryptSync(passphrase, salt, 32);
const decipher = createDecipheriv("aes-256-gcm", key, iv);
decipher.setAuthTag(tag);
return Buffer.concat([decipher.update(enc), decipher.final()]).toString("utf8");
}
const b64 = (b: Buffer): string => b.toString("base64url");
const ub64 = (s: string): Buffer => Buffer.from(s, "base64url");
// There was a symmetric seal()/unseal() here, for a provider to seal a credential to a key before
// writing it. It is gone: a provider is handed the credential the mesh minted and seals nothing
// (novox/hq ADR 0053), the mesh's own secret delivery is asymmetric and belongs to the host, and
// nothing else called it. The primitive left with the provisioner that was its only caller.
// --- semver ---
//