6 KiB
Release Guide
The release pipeline runs on GitHub Actions. Pushing a version tag to upstream triggers .github/workflows/release.yml, which builds every artifact, creates a draft GitHub release, and signs SHA256SUMS with the Specter Signer GPG key.
Prerequisites
upstreampoints atgit@github.com:cryptoadvance/specter-desktop.git(git remote -vshould show both fetch and push).- You are on
masterwith a clean workspace andgit pull upstream masterapplied. - Release-notes PR has already merged (see Release notes below).
Cut a release
git tag v1.13.1
git push upstream v1.13.1
That's it. The Release workflow on GitHub Actions takes it from here:
release-pip— builds the sdist/wheel and publishes to PyPI via trusted publishing.build-specterd-{linux,windows,macos}— builds thespecterdbinary on each platform. macOS uses nativemacos-14(arm64) andmacos-15-intel(x64) runners and smoke-tests each daemon before packaging.build-electron-{linux,windows,macos}— builds the Electron apps using each platform'sspecterdartifact. Windows uses the publicelectronuserland/builder:wineimage; macOS signs + notarizes ifAPPLE_CERTIFICATE_BASE64et al. are configured.create-release— collects all artifacts, generatesSHA256SUMS, signs it with the GPG key from theGPG_PRIVATE_KEYsecret, generates a release body (with auto-generated "What's Changed" viagh api .../generate-notes), and creates a draft GitHub release.trigger-docker— POSTs a repository-dispatch tolncm/docker-specter-desktopso Aaron's Docker build picks up the new tag (needsAARON_TRIGGERsecret; skipped otherwise).
The release lands as a draft — review and publish it manually on GitHub.
Required secrets
| Secret | Purpose |
|---|---|
GPG_PRIVATE_KEY |
ASCII-armored private key for signing SHA256SUMS |
GPG_PASSPHRASE |
Passphrase for the above |
APPLE_CERTIFICATE_BASE64 |
Developer ID cert for macOS signing (optional — unsigned fallback) |
APPLE_CERTIFICATE_PASSWORD |
p12 password |
APPLE_ID, APPLE_APP_SPECIFIC_PASSWORD, APPLE_TEAM_ID |
Apple notarization credentials |
APPLE_PROVISIONING_PROFILE_BASE64 |
Optional provisioning profile |
AARON_TRIGGER |
PAT for triggering lncm/docker-specter-desktop |
PyPI publishing uses trusted publishing (OIDC) — no secret required.
Release notes
Update docs/release-notes.md via a normal PR before tagging. Use the GitHub API or gh to pull "What's Changed" between the previous tag and master, prepend a heading, and open a PR. The create-release workflow job also appends auto-generated notes to the release body.
GitHub pages download page
./utils/generate_downloadpage.sh still generates the specter-static website's download page off utils/templates/. Clone specter-static alongside specter-desktop and run:
./utils/generate_downloadpage.sh
The script installs the markdown prerequisite, regenerates the GH-page and download page, asks whether to replace/update the GitHub release page for the latest version, and offers to commit/push the static-site changes.
Troubleshooting
If something fails mid-pipeline, re-running individual jobs is safe — they actions/download-artifact from prior jobs and overwrite existing release assets via softprops/action-gh-release. If the draft release already has assets from a stale run, delete the draft and re-run create-release.
macOS builds are the most likely to fail due to Apple signing/notarization glitches. The workflow falls back to unsigned builds when APPLE_CERTIFICATE_BASE64 is empty — useful for smoke-testing the pipeline on forks.
Validate a release candidate on a fork
Do not create or push a tag until the candidate diff and local checks have been reviewed. Once local review is approved, use immutable pre-release tags on the selected validation fork; never move a pre-tag after GitHub Actions has tested it. The release manifest records ${{ github.repository }}, so a fork-built app downloads its fork artifacts while the real upstream release continues to download from cryptoadvance/specter-desktop.
git remote get-url origin
# Confirm that origin is the intended validation fork, not upstream.
git fetch upstream master
git merge-base --is-ancestor upstream/master HEAD
git status --short --branch
git diff --check upstream/master...HEAD
cd pyinstaller/electron
npm test
cd ../..
CANDIDATE_TAG=v2.1.11-pre1
if git rev-parse --verify "refs/tags/${CANDIDATE_TAG}"; then
echo "Tag already exists locally: ${CANDIDATE_TAG}"
exit 1
fi
git tag "${CANDIDATE_TAG}"
git push origin "${CANDIDATE_TAG}"
The -preN tag creates a draft GitHub prerelease. PyPI publishing is disabled outside cryptoadvance/specter-desktop, and absent Apple/GPG secrets exercise the unsigned fork fallback; that does not validate upstream signing or notarization.
Before accepting the candidate, record the workflow run URL and verify:
- both macOS daemon jobs report the expected native architecture and pass
specterd --help; specterd-v2.1.11-preN-osx_x64.zip,specterd-v2.1.11-preN-osx_arm64.zip, andSpecter-v2.1.11-preN.dmgare present;SHA256SUMScontains those three artifacts;- the published prerelease and embedded daemon repository point to the selected fork;
- the unsigned DMG launches, downloads, verifies, and relaunches on both a real Intel Mac and a real Apple Silicon Mac, including an upgrade with existing settings.
If the candidate changes, create v2.1.11-pre2 (then pre3, and so on) at the new reviewed commit. Upstream still requires a secret-enabled signing/notarization validation before publication.