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 /config-baseline.sig. 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) #

stable0.6.0
{
  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.

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) #

stable0.7.39
{
  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 ConfigDriftError("VENDOR_MANIFEST_MISSING") when MANIFEST.json is absent and ConfigDriftError("VENDOR_MANIFEST_SHAPE") when its top-level packages map is missing — operators see a hard fail instead of a silent zero-files-checked pass.

try {
  var result = b.configDrift.verifyVendorIntegrity({
    libVendorDir: "/srv/app/lib/vendor",
  });
  result.ok;            // → true
  result.checkedCount;  // → 42
  result.mismatches;    // → []
} catch (e) {
  e.code; // → "VENDOR_MANIFEST_MISSING"
}

Last updated 2026-08-08T16:39:49.652Z by seeder.