Repository navigation
Signing
Every EDLD release is signed, and so is every commit and tag. Releases are signed by Indevlin's release key, in GitHub Actions; commits and tags by the maintainer who made them.
A release on the releases page carries seven files: five artefacts, a checksum manifest listing all five, and one detached signature over that manifest.
| File | Contents |
|---|---|
EDLD-<version>-linux-x86_64.tar.gz |
Linux binary |
EDLD-<version>-windows-x86_64.zip |
Windows binary |
EDLD-<version>-macos-arm64.zip |
macOS binary |
EDLD-<version>-server-linux-x86_64.tar.gz |
EDLD-server, Linux (SERVER.md) |
EDLD-<version>-server-windows-x86_64.zip |
EDLD-server, Windows |
EDLD-<version>.sha256 |
SHA-256 of all five, one per line |
EDLD-<version>.sha256.sig |
SSH signature over that manifest |
GitHub also attaches its own Source code (zip) and Source code (tar.gz) to every release, generated from the tag. Those are the source download. They are produced by GitHub rather than by the release workflow, so they are not part of the manifest and carry no signature of ours. To obtain source you can verify, clone the repository and check the signed tag — see Signed commits and tags.
The artefacts are not signed individually. The manifest names each one by digest and the manifest itself is signed, so a valid signature plus a matching digest gives the same guarantee for any file, and one signature check covers the whole release. Verification is therefore two steps:
- The signature on
EDLD-<version>.sha256is valid for a key insigning/allowed_signers, under the identityindevlin-vcs@indevlin.com. - Your file's SHA-256 matches its line in that manifest.
Step 2 is worthless without step 1. Anyone who alters an artefact can recompute its checksum and rewrite the manifest; what they cannot do is re-sign it. Never check a digest against a manifest whose signature you have not verified.
The Windows and macOS binaries may also carry a platform code signature (Authenticode, and Apple notarization), which your operating system checks by itself. The signature here is independent of that and can be verified on any platform.
Quick verify:
# One artefact
bash scripts/verify_release.sh EDLD-20261009-linux-x86_64.tar.gz
# Or every artefact you downloaded, from the download directory
bash scripts/verify_release.shThe script finds allowed_signers beside your downloads or in the checkout it
came from, refuses any key in it whose fingerprint it does not already know,
then checks the signature and the digests.
Manual verify:
# 1. Authenticate the manifest — this must pass before the checksums mean
# anything at all
ssh-keygen -Y verify \
-f signing/allowed_signers \
-I indevlin-vcs@indevlin.com \
-n edld.release \
-s EDLD-20261009.sha256.sig \
< EDLD-20261009.sha256
# 2. Check your download against the now-trusted manifest.
# --ignore-missing checks only the files you actually downloaded.
sha256sum -c --ignore-missing EDLD-20261009.sha256The key that signs new releases is committed at
signing/id_ed25519_signing.pub, and every key that has signed a release
still on the releases page is listed in signing/allowed_signers. Their
fingerprints:
SHA256:fQaV3r44Ilmjd2RXNN70SDuDcfh/NjKZ7EQHS6p4YKo indevlin-vcs@indevlin.com (ED25519) current
SHA256:cLyptjOnhuQWARi4TGvLp1Gr3VCqx6MFE+KtWEY5KXI indevlin-edld-release (ED25519) retired
Check before trusting: ssh-keygen -lf signing/id_ed25519_signing.pub must
print the current one. A key file can be replaced as easily as a checksum
list, so compare against something you did not download alongside it — this
page on the primary server, git.indevlin.com. scripts/verify_release.sh
carries the same list and checks it for you.
indevlin-vcs@indevlin.com is a label, not an address anything is sent to or
checked against. An SSH signature records a key and a namespace and nothing
about a person, which is also why relabelling a key — as happened when EDLD
moved to the indevlin organization — leaves every signature it made
valid.
Commits and tags are SSH-signed by the maintainer who made them, with a key
registered as a signing key on that maintainer's GitHub account, which is what
puts a Verified badge on them. Git finds the signing key in your
allowed_signers and reports the principal listed with it; by convention that
is the committer's email, which git log supplies:
# One-time setup, from a clone
echo "$(git log -1 --format=%ce) namespaces=\"git\" $(cut -d' ' -f1,2 signing/id_ed25519_signing.pub)" \
>> ~/.ssh/allowed_signers
git config --global gpg.ssh.allowedSignersFile ~/.ssh/allowed_signers
git log --show-signature -1 # a commit
git tag -v 20260926 # a tagThat authenticates the source through git's own object hashing, which is a stronger guarantee than a digest in a manifest: it covers the full history, not one snapshot.
Today the release key is also the maintainer's commit key, which is why the
line above reads it from signing/. If the two are ever separated (see
Rotating the release key), use the maintainer's published commit key there
instead.
EDLD uses git.indevlin.com (idev) as the authoritative source and
github.com/indevlin/EDLD (ghub) as its mirror.
1. Finish work on dev, merge to main
2. git checkout main
3. git tag -s 20261009 -m 'Release 20261009' # signed tag, matching ./version
4. gpublish # push to idev, mirror to ghub
Pushing the tag starts the Release workflow. It checks the tag matches the
version file, builds and smoke-tests the five binaries, writes the checksum
manifest, checks that the SIGNING_KEY secret is the key in
signing/id_ed25519_signing.pub, signs the manifest, and verifies it exactly
as a user does — against signing/allowed_signers, then every digest — before
publishing the release with notes from CHANGELOG.md. It also asserts the
manifest covers five artefacts, so a glob that quietly matched fewer fails the
build rather than shipping a release that verifies while missing a platform.
Publishing a release by hand in the GitHub UI runs the same workflow, and a
manual run from the Actions tab builds any branch without publishing
(dry_run). See the comments at the top of .github/workflows/release.yml.
One repository secret signs releases (Settings → Secrets and variables →
Actions, on indevlin/EDLD):
| Secret | Content |
|---|---|
SIGNING_KEY |
The release private key: ed25519, no passphrase, whose public half is signing/id_ed25519_signing.pub
|
The signing identity is not a secret; it is indevlin-vcs@indevlin.com, set in
the workflow and in signing/allowed_signers. The SIGNING_IDENTITY secret
older workflows read is not used by this one. A run uses the workflow file in
the commit it builds, so keep that secret until main and dev both carry
this workflow, then delete it.
Not required on a schedule. Do it if the key may have been exposed, or to give releases a key of their own, separate from the maintainer's commit key.
# 1. A new key, on a trusted machine; the private half never enters the repo
ssh-keygen -t ed25519 -N "" -C indevlin-edld-release -f ~/indevlin-edld-release
# 2. The repository: the new public key, and the new key added to the list
cp ~/indevlin-edld-release.pub signing/id_ed25519_signing.pub
echo "indevlin-vcs@indevlin.com namespaces=\"edld.release\" $(cat ~/indevlin-edld-release.pub)" \
>> signing/allowed_signers
ssh-keygen -lf ~/indevlin-edld-release.pub # the new fingerprint- Add that fingerprint to
RELEASE_KEY_FPSinscripts/verify_release.shand to the list above, marking the old one retired. - Replace the
SIGNING_KEYsecret with the new private key, then delete the local private copy or move it offline. - Commit, and tag the next release.
Leave a retired key in allowed_signers and RELEASE_KEY_FPS for as long as
releases it signed are on the releases page; removing it only makes those
releases unverifiable.
Getting Started
Guides
Reference
- Automation
- Building
- Configuration
- Dossier
- Edcars
- Exploration Exobiology Plan
- Licensing
- Mission Bootstrap
- Privacy
- Roadmap
- Server
- Signing
- Startup
- Streamer Stats Overlay
- Surface Survey
- Terminal Output
- Theming
Releases