sign.sh#
Three verbs: build a manifest of what you are about to ship, sign a file, and verify one.
verify is the half that matters and the half that works today — it runs everywhere,
needs no key material of ours, and is what a customer runs. sign refuses rather than
inventing a key.
install/sign.sh manifest agent/wheelhouse-agent ui/dist
install/sign.sh verify SHA256SUMSUsage#
sign.sh manifest <binary> [ui_dist_dir] build wheelhouse.manifest beside <binary>
sign.sh sign <file>... write a detached <file>.asc for each
sign.sh verify <checksum-file> [sig] check the sums, then the signature
sign.sh <binary> [ui_dist_dir] same as `manifest` (older callers)Environment#
| Variable | Used by | Meaning |
|---|---|---|
RELEASE_SIGNING_KEY | sign | The GPG key id, fingerprint or user id to sign with. |
GPG_PASSPHRASE | sign | Optional; enables batch signing on a runner. |
WHEELHOUSE_PUBKEY | verify | An armoured public key file to verify against. Without it, the caller's own keyring is used. |
REQUIRE_SIGNATURE | verify | Set to 1 to make verify fail when nothing is signed. |
manifest#
Writes wheelhouse.manifest beside the binary: a header line with a UTC timestamp, then
one sha256sum-format line per file.
Wheelhouse manifest 2026-09-02T21:03:11Z
5c1f… agent
9a02… ui/index.html
1d77… ui/assets/index-4f2a1c.jsThe paths name the shipped layout — agent beside ui/ — not where the inputs sat
when the manifest was built, so sha256sum -c works inside the bundle you distribute
rather than only on the machine that made it.
sign#
A detached, armoured signature per file: <file>.asc. An existing one is removed first
rather than appended to.
verify#
Two steps, in this order, and the first one is not optional:
- The sums. If the file holds lines matching
^[0-9a-f]{64}, they are checked withsha256sum -cfrom the file's own directory — so a manifest's relative paths resolve. A mismatch is fatal:checksums do not match — do not install this build. A file with no such lines is treated as a plain artefact to verify a signature over. - The signature. Given explicitly, or found automatically as
<file>.ascthen<file>.sig.
| Situation | Result |
|---|---|
No signature found, REQUIRE_SIGNATURE unset | Says so, and says plainly that checksums proved the download survived the network, not who built it. Exit 0. |
No signature found, REQUIRE_SIGNATURE=1 | Fatal. |
Signature found, WHEELHOUSE_PUBKEY set | Imported into a throwaway keyring in a temporary directory, verified there, and the keyring is deleted — so verifying a download never touches the caller's own keyring. |
Signature found, no WHEELHOUSE_PUBKEY | Verified against the caller's keyring, with a message naming both fixes if it fails. |
Verifying a release download#
curl -fsSLO https://releases.rhymelikedi.me/latest/SHA256SUMS
curl -fsSLO https://releases.rhymelikedi.me/latest/wheelhouse-0.5.1-amd64.iso
install/sign.sh verify SHA256SUMSOr without this script at all:
sha256sum --ignore-missing -c SHA256SUMSBoth are checksum verification. Neither is a signature, and neither will be until a key exists.
See also#
- Channel index format — where
SHA256SUMSand thesignedflag come from. - The ISO and The
.deb— what you are verifying. install.sh— the lab install this manifest is for.- Download and verify
Checked against#
install/sign.sh (build_manifest, sign_files,
verify_file, usage),
.forgejo/workflows/publish.sh,
.forgejo/workflows/release-index.py,
docs/deploy.md "Releases and update channels",
docs/security.md "Verifying what you downloaded".