Config Drift
Monitor + alert when runtime config diverges from a declared baseline.
The framework's audit chain captures DATA writes (every row, every key change). It does NOT capture RUNTIME CONFIG — an operator who silently changes allowedOrigins three weeks ago leaves no signal. b.configDrift fills that gap: at every boot the operator passes the baseline snapshot they want tracked. The primitive hashes it with SHA3-512, signs the digest with the audit-signing key, and writes the result to a sidecar at . On the next boot the sidecar is loaded, verified, and diffed against the new snapshot. Drift surfaces as an audit event (config.drift.detected); no boot block — the operator may have a legitimate reason to change config, and the framework's job is to make the change auditable, not to refuse to start.
The signed sidecar uses b.auditSign — same SLH-DSA-SHAKE-256f keypair the audit chain anchors on. An attacker who flips a config value would also need to forge the signing key to update the sidecar cleanly; otherwise next-boot verify catches the tamper.
b.configDrift.verifyVendorIntegrity is a sibling primitive that re-hashes every file under lib/vendor/ against the manifest's sha256 digests at boot — catches a half-applied vendor refresh, a corrupted install, or a vendored cjs modified without a manifest update.
b.configDrift.create(opts) #
{
dataDir: string, // directory holding the baseline sidecar (required)
audit: object, // b.audit instance; pass false to disable
baseline: string, // baseline name — sidecar is `config-baseline-.sig`
criticalKeys: string[], // keys whose drift raises severity to "high"
ignoreKeys: string[], // keys excluded from drift detection
}
Build a per-baseline drift detector bound to a dataDir. Returns a handle exposing .checkpoint(snapshot) (write or compare against the signed sidecar), .read() (load + verify the sidecar without mutating it), and .sidecarPath (absolute path of the sidecar file).
Drift on a key listed in opts.criticalKeys surfaces as config.drift.detected with severity: "high" and outcome failure; drift in any other key surfaces as severity: "low" and outcome success. When criticalKeys is omitted every key is treated as high severity. Keys listed in opts.ignoreKeys are captured in the snapshot but never raise a drift event.
// requires: write access to the dataDir below
var fakeAudit = { safeEmit: function () {} };
var detector = b.configDrift.create({
dataDir: "/tmp/blamejs-drift-demo",
audit: fakeAudit,
criticalKeys: ["allowedOrigins", "csp"],
ignoreKeys: ["bootCount"],
});
detector.sidecarPath;
// → "/tmp/blamejs-drift-demo/config-baseline.sig"
var first = await detector.checkpoint({
allowedOrigins: ["https://app.example.com"],
csp: "default-src 'self'",
bootCount: 1,
});
first.signed; // → true
first.drifted; // → false
first.previousAt; // → null
b.configDrift.verifyVendorIntegrity(opts) #
{
libVendorDir: string, // absolute path to the lib/vendor tree to verify; default: the framework's own (cwd-independent). Per-file manifest paths resolve under this directory.
manifestPath: string, // absolute path to MANIFEST.json (defaults under libVendorDir)
}
At-boot integrity check over lib/vendor/*. MANIFEST.json carries a sha256 digest per bundled file; the call re-hashes each one and surfaces mismatches without throwing. Returns { ok, checkedCount, mismatches } and emits vendor.integrity.verified (success) or vendor.integrity.tampered (failure) on every invocation so a corrupted install lands in the audit chain at boot, not later.
Throws config-drift/vendor-manifest-missing when MANIFEST.json is absent and config-drift/vendor-manifest-shape when its top-level packages is missing, null, an array, or an object with no packages in it, so an operator sees a hard fail instead of a silent zero-files-checked pass. An entry that cannot be verified, because it names no path or carries no hash, and a package that declares no files at all, are reported as a mismatch with actual: " for the same reason. A run that verified nothing therefore never returns ok: true.
It does not abort the process on a mismatch. Read ok and stop the boot yourself; SECURITY.md's operator checklist carries the shape.
var result = b.configDrift.verifyVendorIntegrity();
result.ok; // → true
typeof result.checkedCount; // → "number"
result.mismatches; // → []
// At boot, before any listener opens. The call reports; stopping is yours.
var integrity = b.configDrift.verifyVendorIntegrity();
if (!integrity.ok) {
console.error("vendored artifact mismatch", integrity.mismatches);
process.exitCode = 1;
}
integrity.ok; // → true