-
Notifications
You must be signed in to change notification settings - Fork 0
Release Process
How releases get cut. Fully automated via GitHub Actions — you don't run codesign or notarytool locally.
# Bump version in four files, commit, tag, push.
# That's it. Workflow does everything else.
git commit -am "chore(release): bump to v0.1.9"
git tag v0.1.9
git push origin main v0.1.9
gh run watch # follow the workflow
# Then: review the draft release, click Publish.A tag push matching v* triggers .github/workflows/release.yml. The workflow runs a matrix:
-
aarch64-apple-darwinonmacos-latest— actively used -
x86_64-apple-darwinonmacos-13— configured but unreliable (Intel runner pool is constrained; jobs frequently sit queued for hours)
Each matrix job is 14 steps:
- Checkout the tagged commit.
- Setup Node + Rust toolchains.
-
Cache cargo registry and
src-tauri/target/. -
npm ciroot + sidecar. -
Pre-import Apple Developer ID cert into a fresh keychain in
$RUNNER_TEMP. Necessary socopy-runtime-modules.mjscan codesignbetter_sqlite3.nodewith a secure timestamp — without that, notarytool rejects the .app. (PR #9, PR #10) -
Build sidecar —
prepare-node(bundle real Node binary, ad-hoc sign),build(esbuild →dist/index.cjs),package(wrap in self-extracting bash stub),runtime-modules(copy + sign.nodefiles). - Probe Apple signing secrets — logs whether codesign and notarization will run. Doesn't gate later steps.
-
Strip AppleDouble metadata from
src-tauri/target,sidecar/,node_modules. Without this,gtar-restored cache files include._*companions that get bundled into the .app and breaktauri-plugin-updaterextraction on client. (PR #2) -
Wipe cached bundle outputs —
rm -rf src-tauri/target/<triple>/release/bundle/so tauri-bundler regenerates the.app.tar.gzfrom the freshly-built.apprather than reusing a stale cached tarball. (PR #12) -
tauri-action@v0— Rust compile, .app bundle, codesign with Developer ID, notarize via Apple, .dmg build, updater bundle sign with minisign, upload all to a draft GitHub release. -
Verify update tarball — raw-parses the produced
.app.tar.gztar stream (BSDtar -thides AppleDouble; can't trust it). Fails the build if any._*entries leak through. - Summarize artifacts in the run log.
All eight at https://github.com/mrdulasolutions/AOS-Mail/settings/secrets/actions:
| Secret | What it is | How to set |
|---|---|---|
APPLE_CERTIFICATE |
Base64-encoded .p12 of the Developer ID Application cert |
security export -k login.keychain-db -t identities -f pkcs12 -P <pw> -o cert.p12 && base64 -i cert.p12 | gh secret set APPLE_CERTIFICATE |
APPLE_CERTIFICATE_PASSWORD |
The password you set when exporting the .p12
|
echo -n '<pw>' | gh secret set APPLE_CERTIFICATE_PASSWORD |
APPLE_SIGNING_IDENTITY |
Exact CN: Developer ID Application: <Name> (<Team ID>)
|
Look up with security find-identity -v -p codesigning
|
APPLE_ID |
Apple ID email enrolled in the Developer Program | Plain string |
APPLE_PASSWORD |
App-specific password for notarization (xxxx-xxxx-xxxx-xxxx) |
https://account.apple.com → Sign-In and Security → App-Specific Passwords |
APPLE_TEAM_ID |
10-char Team ID | Visible in the signing identity CN; also at https://developer.apple.com/account |
TAURI_SIGNING_PRIVATE_KEY |
Contents of ~/.tauri/aos-mail-v2.key (minisign private key) |
cat ~/.tauri/aos-mail-v2.key | gh secret set TAURI_SIGNING_PRIVATE_KEY |
TAURI_SIGNING_PRIVATE_KEY_PASSWORD |
Password for the minisign key | echo -n '<pw>' | gh secret set TAURI_SIGNING_PRIVATE_KEY_PASSWORD |
If any signing secret is missing, the build produces an unsigned .app (won't pass Gatekeeper on a fresh Mac). If notarization secrets are missing, the build is signed but not notarized — users see the "unidentified developer" warning. If TAURI_SIGNING_PRIVATE_KEY is missing, no .app.tar.gz.sig and no latest.json — auto-update breaks.
They MUST agree, or tauri build warns about version mismatch and notarytool sometimes rejects.
-
package.json→"version" -
sidecar/package.json→"version"(optional but conventional) -
src-tauri/tauri.conf.json→"version" -
src-tauri/Cargo.toml→[package] version -
src-tauri/Cargo.lock→[[package]] name = "aos-mail"→version
git commit -am "chore(release): bump to v0.1.9"
git push origin maingit tag v0.1.9
git push origin v0.1.9The tag push triggers release.yml.
gh run watch
# or open https://github.com/mrdulasolutions/AOS-Mail/actionsarm64 typically completes in ~10-15 minutes. x64 may sit queued indefinitely depending on macos-13 runner availability — see "Intel matrix" below.
When green, GitHub Releases has a draft with:
-
AOS.Mail_<version>_aarch64.dmg— signed + notarized installer. -
AOS.Mail_aarch64.app.tar.gz— auto-update bundle. -
AOS.Mail_aarch64.app.tar.gz.sig— minisign signature for the bundle. -
latest.json— updater manifest (darwin-aarch64entry only currently).
Quick sanity check:
mkdir /tmp/verify && cd /tmp/verify
gh release download v0.1.9 --pattern '*aarch64*.tar.gz'
tar -xzf AOS.Mail_aarch64.app.tar.gz
spctl -a -vv "AOS Mail.app" # expect: accepted / Notarized Developer ID
xcrun stapler validate "AOS Mail.app" # expect: The validate action worked!gh release edit v0.1.9 --draft=false
# or click "Publish release" in the UIThe moment the draft is published, releases/latest/download/latest.json flips, and every running install picks up the new version on its next update check.
The workflow tries each step idempotently — you can re-tag (delete and re-push the tag) to re-run. To move a tag:
git tag -d v0.1.9
git push origin :refs/tags/v0.1.9
git tag v0.1.9 <new-commit-sha>
git push origin v0.1.9Before re-tagging, delete the draft release (if any) — otherwise tauri-action appends artifacts on top of the broken ones:
gh release delete v0.1.9 --yesSee Troubleshooting for common build failures and their fixes.
The workflow includes x86_64-apple-darwin on macos-13 runners, but GitHub's Intel macOS runner pool has been constrained — jobs frequently sit queued for hours and time out. For now, arm64-only is the practical default.
latest.json only contains a darwin-aarch64 entry. The matrix runs both arms and each uploads its own latest.json to the same draft release; whichever uploaded last wins. A workflow patch to merge both architectures' entries before publishing is on the roadmap. Until then, Intel users have no auto-update channel.
-
gh release create— tauri-action creates the draft for us. -
Manual
codesign— tauri-action handles it. -
Manual
xcrun notarytool submit— tauri-action handles it. -
Manual
stapler staple— tauri-action handles it. -
Manual
npx @tauri-apps/cli signer sign— tauri-action handles it.
If you find yourself running any of those locally as part of a release, something's wrong with the secrets or the workflow.
- Updater Keys and Signing — Apple Developer ID + Tauri minisign key management.
- DEVELOPER.md → Release pipeline — same info, with more inline detail.
- docs/RELEASE.md — original release doc (some details may be out of date, see DEVELOPER.md for current).
- docs/POST-MORTEM-2026-05.md — the v0.1.8 release incident retrospective.