-
Notifications
You must be signed in to change notification settings - Fork 4
Verifying artifacts
(Since 1.7.0) install-from-cache can verify that a downloaded binary is byte-for-byte the one you published, and rebuild from source if it is not. This closes the gap where a network-downloaded artifact is written and loaded with no integrity check. The feature is opt-in per addon, adds no dependency, and never weakens the fall-back-to-source guarantee.
A GitHub release asset is mutable: a maintainer (or anyone who compromises the account) can replace the binary attached to an already-published release without cutting a new version. Your addon's npm package, by contrast, is immutable: a published version can never change. So the trick is to record what the binary should be inside the immutable npm package, where an attacker who can swap the mutable release asset cannot also rewrite the expectation.
That record is a hash bag: an artifactHashes object in your addon's package.json mapping each platform slot to the SHA-256 of its binary.
{
"artifactHashes": {
"linux-x64-137": "sha256:9e68bb76...",
"darwin-arm64-137": "sha256:fe4fe40a..."
}
}At install time, install-from-cache downloads the binary, computes its SHA-256, and compares it to the bag entry for the running platform before writing the file. A swapped binary no longer matches the hash your immutable package recorded, so it is rejected and the install falls through to npm run rebuild.
This needs no signing key, no transparency-log service, and no extra network request — the expectation ships with the package the user already downloaded from npm, and the check is a node:crypto SHA-256.
The hashes are produced by hash-github-cache, typically from a prepublishOnly hook so a plain npm publish stamps a fresh bag into the packed tarball:
{
"scripts": {
"install": "install-from-cache --artifact build/Release/ABC.node",
"save-to-github": "save-to-github-cache --artifact build/Release/ABC.node",
"prepublishOnly": "hash-github-cache --write",
"rebuild": "node-gyp rebuild"
}
}Your release order becomes: tag → CI builds every platform → save-to-github-cache uploads the assets → npm publish (which runs hash-github-cache --write, hashing the freshly-uploaded release and stamping the bag). Commit the stamped package.json afterward. See Hash GitHub cache for the utility's flags, the two-step alternative, and post-publish monitoring.
No change is needed on the install-from-cache side — verification switches on automatically for any addon whose package.json carries an artifactHashes bag.
- Canonical GitHub source, hash matches ⇒ the artifact is written and used.
- Canonical GitHub source, hash mismatches, or the bag has no entry for this platform ⇒ the artifact is rejected and the install builds from source. The check is strict: because a complete bag lists every binary you published, a downloaded binary that is not in the bag is treated as something that should not exist.
-
A custom mirror (
--host/--host-var/DOWNLOAD_HOST) ⇒ not checked. A curated mirror deliberately serves the deployer's own build, whose bytes need not match your upstream hashes; the mirror is that deployer's trust root. See Making a local mirror. -
No
artifactHashesinpackage.json⇒ nothing is checked; the installer behaves exactly as it did before (the feature is fully backward-compatible).
"Canonical GitHub source" means the default host — GITHUB_SERVER_URL (set automatically in GitHub Actions, and usable by GitHub Enterprise) or https://github.com — with no mirror override. The hash is computed over the decompressed binary, so a mirror that recompresses the same binary into a different wire format does not spuriously fail.
The strongest choice a consumer can make is to not download at all — build from source, trusting only npm plus the local toolchain. Set the environment variable when installing:
DOWNLOAD_FORCE_BUILD=1 npm install <addon>DOWNLOAD_FORCE_BUILD (or the --force-build flag, which an addon author can wire into the install script; the variable name is overridable with --force-build-var) skips the prebuilt download completely and runs npm run rebuild. Nothing is fetched, so there is nothing to verify.
Integrity verification proves a download matches what you published; it cannot defend against a compromise of the publish itself. If your npm account is compromised and a new malicious version is published, that version carries its own (malicious) bag — but that is a new, immutable, opt-in release, not a silent swap of an old one. Protect the publish path with npm two-factor authentication.