{"category":"Desktop & Native","tags":["code-signing","notarization","distribution","auto-updater","homebrew","winget","release-pipeline"],"pairs-with":[{"skill":"rust-tauri-development","reason":"Tauri apps need signing and distribution"},{"skill":"cross-platform-desktop","reason":"Platform-specific installer and signing requirements"},{"skill":"devops-automator","reason":"CI/CD infrastructure for automated builds and releases"}]}
Ship signed Rust desktop applications to users on macOS and Windows. This skill covers the full distribution pipeline: code signing certificates, Apple notarization, Windows Authenticode, auto-updater mechanisms, and publishing to package managers (Homebrew, winget, Scoop).
Decision Points
Certificate Selection Decision Tree
IF macOS distribution needed:
→ THEN Apple Developer Program required ($99/year)
→ Generate Developer ID Application cert (automatic with membership)
→ For installers: also generate Developer ID Installer cert
IF Windows distribution AND budget < $50/month:
→ THEN use EV certificate from DigiCert/Sectigo ($300-500/year)
→ Store on hardware HSM or Azure Key Vault
→ ELSE IF US/Canada business with 3+ years history:
→ Use Azure Trusted Signing ($9.99/month)
→ Faster setup, cloud-based HSM
IF CI platform is GitHub Actions:
→ THEN use tauri-action for automated builds
→ Store certs in GitHub Secrets
→ ELSE IF CI platform is Azure DevOps:
→ Use Azure Trusted Signing integration
→ Store Apple certs in Azure Key Vault
Auto-Updater Implementation Decision
IF simple GitHub-hosted releases:
→ THEN use Tauri updater with GitHub releases endpoint
Detection rule: CI builds start failing with "certificate not found" or "certificate expired" errors.
Symptom: Previously working builds suddenly fail during signing step.
Diagnosis:
Apple Developer ID certificate expired (1 year validity)
Windows EV certificate expired
Apple app-specific password revoked
Fix:
Apple: Renew certificate in Apple Developer portal, export new .p12
Windows: Renew EV certificate with provider, update KeyVault
Update secrets: Replace base64-encoded certificates in CI secrets
Test: Run manual build to verify new certificates work
Cross-Platform Binary Mismatch
Detection rule: Package manager users report "architecture not supported" or binary won't launch.
Symptom: Installer downloads but app won't run on user's architecture.
Diagnosis:
Built x86_64 binary but user has ARM64 machine
Universal binary not actually universal
Wrong target specified in CI matrix
Fix:
# Ensure complete architecture matrixstrategy:matrix:include:-os:macos-latesttarget:aarch64-apple-darwin-os:macos-13# Intel runnertarget:x86_64-apple-darwin-os:windows-latesttarget:x86_64-pc-windows-msvc# Verify binary architecturefiletarget/release/myapp# Should show correct archlipo-infotarget/release/myapp# macOS universal binary check
Worked Examples
Complete Release Pipeline Setup
Scenario: Setting up automated releases for a Tauri app "DevTools" that needs macOS and Windows distribution.
Step 1 - Certificate Setup:
# Generate Apple Developer ID (via Apple Developer portal)# Download .p12 file, encode for CI:base64 -i ~/Downloads/certificates.p12 -o apple_cert.txt
# For Windows - setup Azure Trusted Signing:# 1. Create account at codesigning.azure.net# 2. Create certificate profile "production"# 3. Note tenant ID, client ID, account name
Expert catches: Novices often skip the app-specific password step or try to use their Apple ID password directly. Expert immediately generates app-specific password at appleid.apple.com.
Expert catches: The public key goes in tauri.conf.json under plugins.updater.pubkey, NOT as a file. Novices often try to reference a pubkey file path.
Step 3 - CI Configuration:
name:Releaseon:push:tags: ["v*"]
jobs:build:strategy:matrix:include:-os:macos-latesttarget:aarch64-apple-darwin-os:windows-latesttarget:x86_64-pc-windows-msvcruns-on:${{matrix.os}}steps:-uses:tauri-apps/tauri-action@v0env:# Apple secretsAPPLE_SIGNING_IDENTITY:${{secrets.APPLE_SIGNING_IDENTITY}}APPLE_ID:${{secrets.APPLE_ID}}APPLE_PASSWORD:${{secrets.APPLE_APP_PASSWORD}}APPLE_TEAM_ID:${{secrets.APPLE_TEAM_ID}}# Windows secrets AZURE_TENANT_ID:${{secrets.AZURE_TENANT_ID}}AZURE_CLIENT_ID:${{secrets.AZURE_CLIENT_ID}}AZURE_CLIENT_SECRET:${{secrets.AZURE_CLIENT_SECRET}}# Update signingTAURI_SIGNING_PRIVATE_KEY:${{secrets.TAURI_SIGNING_PRIVATE_KEY}}with:tagName:v__VERSION__releaseName:"DevTools v__VERSION__"
Expert catches: The APPLE_SIGNING_IDENTITY must match the certificate name exactly, including the team ID in parentheses. Novices often forget the team ID or get the format wrong.
Decision point navigated: Since this is a GitHub Actions setup with Windows distribution, expert chose Azure Trusted Signing over EV certificate for cost and simplicity. For a GitLab CI setup, would have chosen traditional EV cert.
Step 4 - Testing Update Flow:
// In the app frontendimport { check } from"@tauri-apps/plugin-updater";
asyncfunctiontestUpdate() {
console.log("Checking for updates...");
const update = awaitcheck();
if (update) {
console.log(`Found update: ${update.version}`);
// Expert validates signature is checked automatically by Tauriawait update.downloadAndInstall();
}
}
Expert catches: The updater automatically validates signatures using the embedded public key. Novices often try to add manual signature verification, which is redundant and error-prone.
Quality Gates
Pre-release validation checklist:
macOS app signed with Developer ID Application certificate (verify: codesign -dv MyApp.app)