Skip to content

Sign and publish a release

renew reads a release manifest only once its minisign signature verifies against the public key the app carries. Publishing a release is four steps.

Terminal window
minisign -G

This writes minisign.pub and a secret key (by default under ~/.minisign/). Keep the secret key off the server that hosts the releases. The app carries the public key: the second line of minisign.pub, which starts with RW.

const RELEASE_KEY: &str = "RWQ…";

2. Put each binary where the app can fetch it

Section titled “2. Put each binary where the app can fetch it”

Each platform gets the raw executable, not an archive, at an HTTPS URL. Take its sha256 and its size in bytes:

Terminal window
sha256sum app-linux-x86_64 # Linux
stat -c %s app-linux-x86_64
shasum -a 256 app-macos-arm64 # macOS
stat -f %z app-macos-arm64

An app that runs from a macOS .app bundle also publishes the bundle, after it is signed, notarised and stapled, zipped with ditto so its signature, links and extended attributes survive:

Terminal window
ditto -c -k --keepParent App.app App-macos-arm64.app.zip
shasum -a 256 App-macos-arm64.app.zip
stat -f %z App-macos-arm64.app.zip
{
"version": "1.1.0",
"platforms": {
"linux-x86_64": { "url": "https://example.com/app/1.1.0/app-linux-x86_64", "sha256": "…", "size": 10485760 },
"macos-arm64": {
"url": "https://example.com/app/1.1.0/app-macos-arm64", "sha256": "…", "size": 9437184,
"app": { "url": "https://example.com/app/1.1.0/App-macos-arm64.app.zip", "sha256": "…", "size": 12582912 }
}
}
}

The platform keys are linux-x86_64, macos-arm64 and windows-x86_64; renew::platform_key() gives the running build’s key. Each sha256 is 64 hex digits and each size is above 0 and at most 512 MiB, or 1 GiB for an app zip. Formats has every field and limit.

Terminal window
minisign -Sm manifest.json

This writes manifest.json.minisig next to the manifest. Serve both over HTTPS, the signature at the manifest’s URL with .minisig appended:

https://example.com/app/manifest.json
https://example.com/app/manifest.json.minisig

Sign again every time the manifest changes: renew verifies the signature over the exact bytes it fetched, so a manifest edited after signing is refused, even a change of whitespace.

cargo run --example demo in a checkout does all four steps in a temporary folder, with a key it makes on the spot, and serves the files from a local port; plain http is allowed only to this machine. Its source, examples/demo.rs, is a working publisher and client in one file.