---
name: code-signing-setup
type: release
tags: [release, signing, notarisation, macos, windows, secrets]
description: "Step-by-step walkthrough: procure signing certificates and set the GitHub secrets that activate conditional code-signing in the CI workflow."
---

# Code-signing setup

The CI workflow (`build.yml`) signs automatically when the relevant GitHub secrets are present. If they aren't set, the workflow still builds correctly — it just produces an unsigned `.dmg` / `.msi`. Set the secrets once and every subsequent tag push signs for free.

Linux ships clean today: the AppImage is unsigned but accompanied by a SHA-256 checksum, which is sufficient for the v0.1 trust posture.

---

## macOS — Developer ID signing + notarisation

**Prerequisite:** enrol in the Apple Developer Program at <https://developer.apple.com> ($99/year individual or $299/year organisation). Notarisation requires an enrolled account; unsigned `.dmg` files trigger Gatekeeper warnings (documented in `docs/release/install-warnings.md`).

1. **Generate a Developer ID Application certificate.**
   - Xcode → Settings → Accounts → select your Apple ID → Manage Certificates → click `+` → Developer ID Application.
   - Alternatively: Apple Developer portal → Certificates, Identifiers & Profiles → Certificates → `+`.

2. **Export the certificate as a `.p12`.**
   - Open Keychain Access → My Certificates → find "Developer ID Application: Your Name (TEAMID)".
   - Right-click → Export → choose `.p12` format → set a strong export password. Keep the password; you'll need it next.

3. **Base64-encode the `.p12` for GitHub.**
   ```sh
   base64 -i developer-id.p12 | pbcopy
   ```

4. **Set the GitHub secrets** (run from the repo root; paste when prompted):
   ```sh
   gh secret set APPLE_CERTIFICATE            # paste the base64 blob
   gh secret set APPLE_CERTIFICATE_PASSWORD   # the .p12 export password
   gh secret set APPLE_SIGNING_IDENTITY       # e.g. "Developer ID Application: Jake Sames (AB12CD34EF)"
   gh secret set APPLE_ID                     # your Apple ID email address
   gh secret set APPLE_PASSWORD               # an app-specific password from appleid.apple.com
   gh secret set APPLE_TEAM_ID               # 10-character team ID (visible in the Developer portal)
   ```
   To create the app-specific password: <https://appleid.apple.com> → Sign-In and Security → App-Specific Passwords → Generate.

5. **Re-tag.** The next CI run will sign and notarise the `.dmg` automatically. The `tauri-action` runner detects the env vars at build time — no workflow edits required.

---

## Windows — EV code-signing certificate

**Why EV and not OV?** Extended Validation certificates earn immediate SmartScreen reputation. OV certificates require download volume to "warm up" before SmartScreen stops warning users. For a new product, EV is the only practical path to a clean install experience.

1. **Purchase an EV code-signing certificate.** Reputable CAs:
   - DigiCert — supports KeyLocker (cloud signing, CI-friendly)
   - Sectigo — supports Code Signing on Demand
   - SSL.com — supports eSigner cloud signing
   Typical cost: £200–£400/year. Budget 1–5 business days for identity verification.

2. **Use the CA's cloud-signing service for CI.** EV certs ship on a USB hardware token that cannot be copied to a CI runner. Every major CA now offers a cloud equivalent:
   - DigiCert KeyLocker, Sectigo CSOD, SSL.com eSigner.
   - Follow the CA's CI integration guide to obtain a signing credential (usually a client certificate or API token) that does not require the physical token.

3. **Set the GitHub secrets** once you have the cloud-signing credential:
   ```sh
   gh secret set WINDOWS_CERTIFICATE          # base64-encoded cert (local) or cloud-signing client cert
   gh secret set WINDOWS_CERTIFICATE_PASSWORD # cert password / PIN
   ```
   If your CA's cloud-signing workflow requires additional env vars (e.g. a KeyLocker API key), set those as secrets and pass them in the `env:` block of the `Build (release)` step in `build.yml` — keep the existing pattern.

4. **Re-tag.** The `tauri-action` runner picks up `WINDOWS_CERTIFICATE` + `WINDOWS_CERTIFICATE_PASSWORD` and signs the `.msi` and `.exe` automatically.

---

## Verify after setting secrets

Run a test tag to confirm signing is working before the real release:

```sh
git tag v0.1.0-test1
git push origin v0.1.0-test1
```

Watch the CI run. In the macOS job log look for `Signed using developer ID...` and in the Windows job look for `Signed using SignTool`. Once confirmed, delete the test tag:

```sh
git push --delete origin v0.1.0-test1
git tag -d v0.1.0-test1
```

---

## Until signing is configured

- macOS users see a Gatekeeper warning on first launch. Workaround: right-click the `.dmg` → Open. Documented in `docs/release/install-warnings.md`.
- Windows users see a SmartScreen warning on first run. Workaround: More info → Run anyway. Documented in `docs/release/install-warnings.md`.
- Linux ships clean today (AppImage + SHA-256 checksum).
