Self-Update Standalone Verifier
Zero-dep companion to b.selfUpdate.verify for install-pipeline contexts that run BEFORE the framework itself is installed — Dockerfile build stages, install.sh, update.sh, SEA-bundle verification at deploy time. The full b.selfUpdate.verify chain reaches into b.crypto, b.httpClient, b.audit, vendor imports, etc.; none of those exist yet when an operator's install script runs node verify-release.js against the downloaded artifact.
This module is intentionally hermetic — node:crypto + node:fs only, no framework imports, no third-party modules. Operators physically copy the file into their install pipeline alongside a public-key module they own. Both go into version control on the operator's side; neither updates without their explicit action.
Surface (single function):
verify(assetPath, signaturePath, pubkeyPem, opts?) → { ok: boolean, sha3_512: string, // hex digest of asset bytes (SBOM correlation) sha256: string, // hex digest of asset bytes (defense-in-depth) alg: string, // detected algorithm: "ecdsa-p384" | "ed25519" | "ml-dsa-87" }
The function refuses to load the asset into memory in one go; it streams the bytes through both hashers + the signature verifier so multi-GB SEA bundles don't OOM the install runner.
Throws on: - missing asset / signature / pubkey file - unrecognized pubkey PEM shape - signature length mismatch with the algorithm - cryptographic verify failure
Per the operator's request that surfaced this primitive (hermitstash-sync 2026-05-13): the install pipeline needs P-384 ECDSA + SHA3-512 as the baseline cross-check. ML-DSA-87 is also supported when the operator's pubkey carries the corresponding OID (Node 22+ via the FIPS 204 OIDs in node:crypto).
## How operators consume this
# one-time copy at framework-install time:
cp "$(node -p "require('@blamejs/core').selfUpdate.standaloneVerifier.path")" \
install/standalone-verifier.js
// install/verify-release.js (operator-owned, in their repo):
var verifier = require("./standalone-verifier");
var pubkey = require("./release-pubkey"); // operator-owned PEM
var result = verifier.verify(
"/tmp/blamejs-sea-bundle",
"/tmp/blamejs-sea-bundle.sig",
pubkey,
);
if (!result.ok) {
process.stderr.write("release verification FAILED\n");
process.exit(1);
}
process.stdout.write("verified " + result.alg + " sha3-512=" + result.sha3_512 + "\n");
The module is also reachable as b.selfUpdate.standaloneVerifier.verify from inside a fully-installed framework process — useful for tests that exercise the same code path the operator's install pipeline does, without forking a subprocess.
b.selfUpdate.standaloneVerifier.verify(assetPath, signaturePath, pubkeyPem, opts?) #
{
maxAssetBytes: number, // asset-size ceiling (default 2 GiB); refuse a larger asset before hashing
extraDigests: array, // additional node:crypto digest names to compute in the same stream
}
Verify a signed release asset using only node:crypto + node:fs (no framework imports). For install-pipeline contexts where the framework itself is not yet installed.
Streams the asset in 64 KiB chunks through SHA-256 + SHA-3-512 + the signature verifier in parallel — single allocation peak (one buffer sized to fstat(asset).size for Ed25519 / ML-DSA-87, ECDSA P-384 needs no buffer because createVerify is incremental). The signature commits to a SHA3-512 digest and the ECDSA encoding is dispatched by structure (DER SEQUENCE vs raw IEEE-P1363), so both encodings of a SHA3-512-signed P-384 sidecar verify.
Returns { ok, sha3_512, sha256, alg, bytes, digests } on success; throws on unrecognized pubkey shape, missing files, or signature mismatch. alg is one of "ecdsa-p384", "ed25519", "ml-dsa-87" (auto-detected from the pubkey PEM). bytes is the verified asset byte count; digests maps each requested opts.extraDigests name to its hex digest (computed in the same single pass).
var verifier = require("./standalone-verifier");
var pubkey = require("./release-pubkey");
var result = verifier.verify(
"/tmp/blamejs-sea-bundle",
"/tmp/blamejs-sea-bundle.sig",
pubkey,
);
if (!result.ok) process.exit(1);
process.stdout.write("verified " + result.alg + " sha3-512=" + result.sha3_512 + "\n");
Last updated 2026-08-08T16:39:49.652Z by seeder.