Why Oam.js ships unsigned, checksummed binaries
Every Oam.js release binary is unsigned. No Apple notarization, no
Windows Authenticode. What every release does ship is a
SHA256SUMS manifest, and the installers refuse to
install anything that does not match it. This post spells the trust
model out: what gets verified, what that verification proves, and —
just as important — what it does not.
What the installer actually verifies
curl -fsSL https://oamjs.org/install.sh | sh downloads
two things into a temp directory: the binary for your OS and
architecture, and the SHA256SUMS manifest published by
the same release. Then it:
-
looks up the expected hash for exactly that asset name. The
manifest is written in binary mode —
<hash> *<asset>— so the lookup strips the*marker and matches the filename exactly; a naivegrep " <asset>$"would never match anything; -
hashes the downloaded file with
sha256sum, falling back toshasum -a 256; -
compares the two and dies on any disagreement —
checksum mismatch, with the expected and actual values printed.
The failure paths refuse rather than degrade. No entry for the asset
in the manifest: refuse. Neither sha256sum nor
shasum on the machine: refuse, rather than install
unverified. Pointing OAM_INSTALL_BASE at a mirror does
not relax anything — whatever the source, the installer still
verifies against the published SHA256SUMS. And
oam self-update re-runs this same installer, so there
is one copy of the verify logic, not two drifting ones.
What a checksum proves — and what it does not
A matching SHA-256 proves you received exactly the bytes the release published. A flipped bit in transit, a truncated download, a proxy serving a stale file — the check catches all of it, loudly.
It does not prove who published those bytes. A code signature binds
a binary to an identity through a certificate authority; a checksum
binds it to whatever the release page currently says. Someone in
control of the YawLabs/oam GitHub account could publish
a malicious binary and a SHA256SUMS that matches it,
and every check above would pass. The trust anchor is GitHub account
control, nothing stronger. The installer prints
checksum ok, and that is easy to read as more than it
is — so here it is, stated plainly.
Why ship unsigned at all
Because of how oam actually reaches machines. The canonical channel
is the one-line installer, and curl, scoop and brew fetches bypass
the Gatekeeper and SmartScreen quarantine entirely — on that path a
signature would change nothing about the install, and the
SHA256SUMS manifest is the integrity check. The release
script does keep a documented seam where a signing step —
notarization, Authenticode — would slot in without changing the
installers. That is a fact about the script, not a commitment.
The cost lands on the other path. macOS quarantines files downloaded by a browser, and these binaries are unsigned, so Gatekeeper refuses the first run of a hand-downloaded binary. The workaround, after moving it into place:
xattr -d com.apple.quarantine ~/.local/bin/oam
Verify the checksum first. Clearing the quarantine attribute is you personally asserting the trust a signature would have carried — the wrong move on bytes you have not checked.
Why four extra files ship with every release
Alongside the binaries, every release publishes
SHA256SUMS, and every release since v0.8.1 adds
LICENSE, NOTICE
and THIRD_PARTY_LICENSES.md. The manifest is the trust
model above. The other three exist because the binary is a binary
redistribution of V8, ICU, the Node streams port and ~380 Rust
crates, and those licenses require their notices to travel with the
bytes. THIRD_PARTY_LICENSES.md reproduces the notices
for the Rust crates; NOTICE carries what no cargo tool
can see — V8 itself, the 16 third-party trees bundled inside the
prebuilt V8 static library, the vendored Node.js sources, the
vendored web-platform-tests data.
The installer copies the three license files next to the binary, in
~/.oam/bin/licenses, so the copy on your machine
carries its own attribution instead of pointing back at a repo.
Best-effort, and honestly so: releases before v0.8.1 shipped no
license assets, and on those the installer says so rather than
leaving an empty directory that implies otherwise.
Verifying by hand
If you take a binary from the downloads page instead of running the installer, the same check is two commands. macOS and Linux — check every file the release published:
curl -fsSLO https://github.com/YawLabs/oam/releases/download/v0.9.0/SHA256SUMS
shasum -a 256 -c SHA256SUMS --ignore-missing
Or one file, compared against the manifest by eye:
shasum -a 256 oam-aarch64-apple-darwin
Windows (PowerShell):
Get-FileHash .\oam-x86_64-pc-windows-msvc.exe -Algorithm SHA256 | Format-List
One trap: Get-FileHash prints uppercase and the
manifest is lowercase. Compare case-insensitively, or pipe through
.Hash.ToLower().
The current release is v0.9.0. The full table of binaries, sizes and
sums — and the OAM_VERSION knob for pinning one — is on
the downloads page.