skills/rust-app-distribution/SKILL.md
Distribution pipeline for signed Rust desktop applications -- code signing, notarization, auto-updates, and package manager distribution. Activate on: code signing, macOS notarization, Apple Developer, Authenticode, Windows signing, auto-updater, Homebrew formula, winget manifest, Scoop bucket, Tauri updater, app distribution, release pipeline. NOT for: library crate publishing (use crates.io docs), web deployment (use devops-automator).
npx skillsauth add curiositech/windags-skills rust-app-distributionInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
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).
IF macOS distribution needed:
IF Windows distribution AND budget < $50/month:
IF CI platform is GitHub Actions:
IF simple GitHub-hosted releases:
cargo tauri signer generatehttps://github.com/ORG/REPO/releases/latest/download/latest.jsonIF custom release infrastructure needed:
IF enterprise deployment with restricted internet:
IF macOS users AND want simple install:
komac or manuallyIF Windows users AND mainstream distribution:
komac for manifest generationIF Windows power users OR faster approval:
Detection rule: xcrun notarytool returns "The entitlements in the app are invalid" or similar entitlement errors.
Symptom: Notarization fails despite valid signing.
Diagnosis:
Fix:
# Check current entitlements
codesign -d --entitlements - MyApp.app
# Remove Mac App Store entitlements, keep only:
# - com.apple.security.cs.allow-jit (if needed)
# - com.apple.security.cs.allow-unsigned-executable-memory (if needed)
# - com.apple.security.cs.disable-library-validation (if needed)
# - com.apple.security.network.client (for network access)
Detection rule: Windows users report "Windows protected your PC" even with valid EV certificate.
Symptom: Valid signature but SmartScreen still warns about unknown publisher.
Diagnosis:
Fix:
Detection rule: Update check succeeds but installation fails with signature verification error.
Symptom: App downloads update but refuses to install.
Diagnosis:
Fix:
# Verify signature manually
cargo tauri signer verify \
--public-key-path ~/.tauri/myapp.pub \
--signature-path release.sig \
--file MyApp-setup.exe
# Check manifest format
curl -s https://releases.myapp.com/latest.json | jq .
# Re-sign update if signature invalid
cargo tauri signer sign \
--private-key-path ~/.tauri/myapp.key \
--file MyApp-setup.exe
Detection rule: CI builds start failing with "certificate not found" or "certificate expired" errors.
Symptom: Previously working builds suddenly fail during signing step.
Diagnosis:
Fix:
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:
Fix:
# Ensure complete architecture matrix
strategy:
matrix:
include:
- os: macos-latest
target: aarch64-apple-darwin
- os: macos-13 # Intel runner
target: x86_64-apple-darwin
- os: windows-latest
target: x86_64-pc-windows-msvc
# Verify binary architecture
file target/release/myapp # Should show correct arch
lipo -info target/release/myapp # macOS universal binary check
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.
Step 2 - Auto-Updater Keys:
# Generate signing keypair
cargo tauri signer generate -w ~/.tauri/devtools.key
# Output shows:
# Private key: ~/.tauri/devtools.key (keep secret!)
# Public key: dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWdu... (embed in app)
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: Release
on:
push:
tags: ["v*"]
jobs:
build:
strategy:
matrix:
include:
- os: macos-latest
target: aarch64-apple-darwin
- os: windows-latest
target: x86_64-pc-windows-msvc
runs-on: ${{ matrix.os }}
steps:
- uses: tauri-apps/tauri-action@v0
env:
# Apple secrets
APPLE_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 signing
TAURI_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 frontend
import { check } from "@tauri-apps/plugin-updater";
async function testUpdate() {
console.log("Checking for updates...");
const update = await check();
if (update) {
console.log(`Found update: ${update.version}`);
// Expert validates signature is checked automatically by Tauri
await 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.
Pre-release validation checklist:
codesign -dv MyApp.app)spctl --assess --type exec -v MyApp.app)signtool verify /pa MyApp.exe)Do NOT use this skill for:
cargo publish and crates.io documentation insteaddevops-automator skill for containerized deploymentrust-tauri-development skill for app development and local buildingDelegate to other skills:
devops-automatorrust-tauri-developmentcross-platform-desktoptools
Building resilient distributed systems with circuit breakers, retries with full-jitter exponential backoff, retry budgets (per-request 3-attempt + per-client 10% ratio per Google SRE), deadline propagation, and the cascading-failure math (4 layers × 3 retries = 64x amplification). Grounded in Resilience4j, Microsoft Cloud Patterns, AWS Architecture Blog (Marc Brooker), and Google SRE Book.
testing
Designing HTTP cache headers that work correctly across browsers, CDNs, and shared proxies — `Cache-Control` directives per RFC 9111, `stale-while-revalidate` and `stale-if-error` per RFC 5861, the Vary header for varying responses, and surrogate keys for tag-based purging. Grounded in IETF RFCs and Cloudflare/Fastly docs.
development
Use when designing or fixing a Content Security Policy on a real site, choosing between nonce-based and hash-based CSP, adding strict-dynamic, debugging "Refused to execute inline script" errors, deploying CSP in report-only mode first, configuring report-to / report-uri, or auditing an existing policy for unsafe-inline / unsafe-eval / wildcards. Triggers: "CSP blocks legitimate inline script", strict-dynamic, nonce-{RANDOM}, sha256-{HASH}, object-src none, base-uri none, frame-ancestors, Trusted Types, X-Content-Security-Policy obsolete, report-only vs enforced. NOT for general HTTP security headers (HSTS, COOP/COEP), Trusted Types deep dive, CORS configuration, or building a WAF.
tools
Choosing and operating an HTTP API versioning strategy that doesn't break clients — Stripe's date-based pinned versions, the Deprecation/Sunset header pair (RFC 9745 + RFC 8594), URI vs header vs media-type approaches, and the version-transformer pattern. Grounded in Stripe's published architecture and IETF RFCs.