From f4f644fbc3f15aad33b42d8621f75e9c3d72d258 Mon Sep 17 00:00:00 2001 From: jamesread Date: Sat, 18 Jul 2026 11:21:29 +0100 Subject: [PATCH] fix: Early support for MacOS Signing (#931) --- .github/workflows/build-and-release.yml | 5 +++ .goreleaser.yml | 17 ++++++++++ docs/modules/dev/pages/signing.adoc | 41 +++++++++++++++++++++---- 3 files changed, 57 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build-and-release.yml b/.github/workflows/build-and-release.yml index 4058a43..2761a0c 100644 --- a/.github/workflows/build-and-release.yml +++ b/.github/workflows/build-and-release.yml @@ -145,6 +145,11 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.CONTAINER_TOKEN }} GH_TOKEN: ${{ secrets.CONTAINER_TOKEN }} + MACOS_SIGN_P12: ${{ secrets.MACOS_SIGN_P12 }} + MACOS_SIGN_PASSWORD: ${{ secrets.MACOS_SIGN_PASSWORD }} + MACOS_NOTARY_KEY: ${{ secrets.MACOS_NOTARY_KEY }} + MACOS_NOTARY_KEY_ID: ${{ secrets.MACOS_NOTARY_KEY_ID }} + MACOS_NOTARY_ISSUER_ID: ${{ secrets.MACOS_NOTARY_ISSUER_ID }} - name: Upload unsigned Windows zip for SignPath id: upload-windows-zip diff --git a/.goreleaser.yml b/.goreleaser.yml index 79902a9..47a80c2 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -182,6 +182,23 @@ nfpms: - src: var/manpage/OliveTin.1.gz dst: /usr/share/man/man1/OliveTin.1.gz +# Sign and notarize darwin binaries via quill (no macOS runner required). +# Skipped when MACOS_SIGN_P12 is unset so local/snapshot builds stay unsigned. +notarize: + macos: + - enabled: '{{ isEnvSet "MACOS_SIGN_P12" }}' + ids: + - default + sign: + certificate: "{{.Env.MACOS_SIGN_P12}}" + password: "{{.Env.MACOS_SIGN_PASSWORD}}" + notarize: + issuer_id: "{{.Env.MACOS_NOTARY_ISSUER_ID}}" + key_id: "{{.Env.MACOS_NOTARY_KEY_ID}}" + key: "{{.Env.MACOS_NOTARY_KEY}}" + wait: true + timeout: 30m + release: # Stay draft until the sign-windows job replaces unsigned Windows assets and undrafts. draft: true diff --git a/docs/modules/dev/pages/signing.adoc b/docs/modules/dev/pages/signing.adoc index beb0dec..f0baeb9 100644 --- a/docs/modules/dev/pages/signing.adoc +++ b/docs/modules/dev/pages/signing.adoc @@ -7,7 +7,7 @@ OliveTin signs release binaries on two platforms: ## macOS release signing -Release builds can sign and notarize the `darwin` binaries using [quill](https://github.com/anchore/quill) via GoReleaser. This runs on the existing Linux CI runner; no macOS runner is required. +Release builds can sign and notarize the `darwin` binaries using [quill](https://github.com/anchore/quill) via GoReleaser. This runs on the existing Linux CI runner; no macOS runner or Xcode is required. Signing is **optional**. If the GitHub secrets below are not all set, GoReleaser skips macOS signing and publishes unsigned binaries (the previous behaviour). @@ -19,12 +19,41 @@ Signing is **optional**. If the GitHub secrets below are not all set, GoReleaser ### One-time setup -#### 1. Create the signing certificate +#### 1. Create the signing certificate (OpenSSL, no Mac/Xcode) + +Work in a private directory. Keep the private key offline and never commit it. + +```sh +mkdir -p ~/apple-signing && cd ~/apple-signing +chmod 700 . + +openssl genrsa -out developer_id_app.key 2048 +openssl req -new -key developer_id_app.key -out developer_id_app.csr \ + -subj "/emailAddress=you@example.com/CN=Your Name/C=GB" +``` 1. Open [Certificates, Identifiers & Profiles](https://developer.apple.com/account/resources/certificates/list). -2. Create a certificate of type **Developer ID Application**. -3. Download the `.cer` file and double-click it to add it to **Keychain Access** on a Mac. -4. In Keychain Access, export the certificate as a **Personal Information Exchange (`.p12`)** file. You will set an export password — remember it; this becomes `MACOS_SIGN_PASSWORD`. +2. Create a certificate of type **Developer ID Application**. Prefer **G2 Sub-CA** if the portal asks. +3. Upload `developer_id_app.csr` and download the resulting `.cer` (often named `developerID_application.cer`). + +Build a `.p12` that includes Apple's Developer ID G2 intermediate: + +```sh +curl -fsSLO https://www.apple.com/certificateauthority/DeveloperIDG2CA.cer + +openssl x509 -inform DER -in developerID_application.cer -out developerID_application.pem +openssl x509 -inform DER -in DeveloperIDG2CA.cer -out DeveloperIDG2CA.pem + +# Export password becomes MACOS_SIGN_PASSWORD. +# On OpenSSL 3 (e.g. Fedora), -legacy improves compatibility with some tooling: +openssl pkcs12 -export -legacy \ + -inkey developer_id_app.key \ + -in developerID_application.pem \ + -certfile DeveloperIDG2CA.pem \ + -out Certificates.p12 +``` + +If you already have a Mac with the certificate in Keychain Access, you can export a `.p12` from there instead; the OpenSSL path above is enough when you do not. #### 2. Create the notarization API key @@ -55,7 +84,7 @@ In **Settings → Secrets and variables → Actions**, create: | `MACOS_NOTARY_KEY_ID` | Key ID from App Store Connect (e.g. `ABC123DEF4`) | | `MACOS_NOTARY_ISSUER_ID` | Issuer UUID from App Store Connect | -All five must be present for signing to run. Any missing secret disables signing for that release. +All five must be present for signing to run. GoReleaser enables the step when `MACOS_SIGN_P12` is set; missing companion secrets will fail that release. ### Renewal