Skip to content

Verifying release signatures

Every Fathom release artifact from 0.5.0 onward is signed with minisign (detached Ed25519) and attached to its GitHub Release. This how-to shows you how to install minisign, verify a downloaded wheel or sdist, and understand the custody, rotation, and revocation policy for the signing key.

Releases before 0.5.0 are unsigned. Signing was introduced with the 0.4.0 tree, which reached PyPI as 0.5.0. The five earlier PyPI releases — 0.1.0, 0.2.0, 0.3.0, 0.3.1 and 0.3.2 — have no .minisig, and the GitHub releases for 0.3.0, 0.3.1, 0.3.3 and 0.4.0 carry no assets at all. There is nothing to verify for those versions, and no signature will be published retroactively: back-signing an old artifact today would assert a custody chain that did not exist when it was built. Use 0.5.0 or later if you need a verifiable artifact.

What is signed, and how

  • Artifacts: every fathom_rules-*.whl and fathom_rules-*.tar.gz from 0.5.0 onward. pypi-publish.yml fails the release if any artifact in dist/ reaches the publish step without a sibling .minisig.
  • Algorithm: Ed25519 via minisign's standard .minisig format — detached signature, one file per artifact, binary-safe.
  • Where signatures appear:
  • Alongside each wheel / sdist as <artifact>.minisig on the GitHub Release page.
  • In the dist/ directory produced by scripts/sign_release.sh during the pypi-publish workflow.
  • Pubkey: published at docs/reference/release-signing-pubkey.minisig and embedded in the Fathom wheel at fathom/_data/release_pubkey.minisign so that fathom verify-artifact works offline.

A .minisig file is a small text blob containing an Ed25519 signature plus a trusted comment. It is not a bundle — the artifact and its .minisig travel together but remain separate files.

Installing minisign

Pick the instruction that matches your platform. All of them give you a minisign binary on your PATH.

  • macOS (Homebrew):
brew install minisign
  • Linux (Debian, Ubuntu):
sudo apt install minisign

On Fedora / RHEL: sudo dnf install minisign. On Arch: sudo pacman -S minisign.

Confirm the install:

minisign -v

Verifying a downloaded artifact

You have two equivalent paths. Use the first if you already have Fathom installed; use the second if you only have minisign and the public key file.

Option A — fathom verify-artifact (embedded pubkey)

The CLI carries the release pubkey inside the wheel, so once you have any recent Fathom version installed you can verify later downloads offline:

fathom verify-artifact fathom_rules-1.2.0-py3-none-any.whl

If <artifact>.minisig lives next to the artifact, the CLI picks it up automatically. Override either side with --sig <path> or --pubkey <path> when auditing a specific file. Exit code 0 means the signature verified; non-zero means the verification failed or the inputs were malformed — re-download the artifact before trusting it.

Option B — raw minisign

No Fathom install needed. Download the artifact, its .minisig, and the pubkey file from docs/reference/release-signing-pubkey.minisig, then:

minisign -Vm fathom_rules-1.2.0-py3-none-any.whl \
         -p release-signing-pubkey.minisig

minisign looks for <artifact>.minisig by default. Pass -x <path> to point at a signature that lives elsewhere. A Signature and comment signature verified line means the artifact is authentic.

The pubkey's first line is also pasted into every GitHub Release body, so you can cross-check the key you fetched from the repository against the one on the release page.

M-of-N custody policy

The release private key is never held in a single place. Two named custodians each hold one half of the operational state, and both must agree out-of-band before a release tag is pushed.

  • MINISIGN_KEY_PRIMARY — GitHub Actions secret, held by custodian A. Loaded into scripts/sign_release.sh during the pypi-publish workflow.
  • MINISIGN_KEY_SECONDARY — offline backup of the same keypair, held by custodian B. Used only for rotation, recovery, and the custody handshake described below.
  • Both custodians confirm the target tag, commit SHA, and intended version via a signed email or Signal message before custodian A authorises the tag push that triggers signing. No single custodian can ship a release on their own, because the handshake is the authorisation step — not merely a courtesy.

The policy exists so that a compromise of a single machine, inbox, or GitHub token cannot produce a valid Fathom release.

Rotation cadence

  • Scheduled: rotate the keypair annually. Track the next rotation date in the repository's release runbook.
  • On compromise: rotate immediately if either custodian suspects their copy of the key has been exposed, if a custodian's workstation is lost or stolen, or if MINISIGN_KEY_PRIMARY is ever printed to logs.

Rotation procedure

  1. Both custodians meet out-of-band and generate a new keypair with minisign -G.
  2. Update docs/reference/release-signing-pubkey.minisig and src/fathom/_data/release_pubkey.minisign with the new public key, in a single commit.
  3. Distribute the new private key: update the MINISIGN_KEY_PRIMARY GitHub Actions secret; custodian B stores the new offline backup.
  4. Publish a dedicated release note flagging the rotation, including the new key ID and the date from which signatures use it.
  5. Retire the previous private-key material (securely erase offline copies, delete the old GitHub secret).

Revocation

minisign has no CRL or OCSP equivalent — trust in a key is defined by the key file you hold. To revoke a compromised key:

  1. Follow the rotation procedure above, treating it as an emergency.
  2. Issue a release note that explicitly invalidates every artifact signed by the previous key and lists which published versions are affected.
  3. Recommend that users re-fetch and re-verify any still-in-use artifacts against the new pubkey before continuing to rely on them.

Users who pin the pubkey (for example by vendoring release-signing-pubkey.minisig) should update their pinned copy from the new release. The embedded pubkey in fathom/_data/ updates automatically once users install a release signed under the new key.