CI secrets for release builds

The Release workflow builds signed Windows and macOS installers (and unsigned Linux packages) when you push a tag matching v* — for example after npm run release -- patch.

On macOS, signing alone is not enough for Gatekeeper. After a clean download, macOS shows “Apple could not verify Consoleri.app…” until the app is notarized. This document covers signing and notarization secrets end to end.

Add secrets under the repository: Settings → Secrets and variables → Actions → New repository secret. Do not store certificates or Apple passwords in Variables — those values can appear in logs.

Secret overview

Secret

Platform

Purpose

WIN_CSC_LINK

Windows

Base64-encoded .pfx / .p12 code-signing certificate

WIN_CSC_KEY_PASSWORD

Windows

Password for that certificate

MAC_CSC_LINK

macOS

Base64-encoded .p12 Developer ID Application certificate

MAC_CSC_KEY_PASSWORD

macOS

Password for that certificate

APPLE_API_KEY

macOS notarization (preferred)

Base64-encoded App Store Connect API .p8 private key (or raw PEM)

APPLE_API_KEY_ID

macOS notarization (preferred)

Key ID of that API key

APPLE_API_ISSUER

macOS notarization (preferred)

Issuer ID (UUID) from App Store Connect

APPLE_TEAM_ID

macOS notarization (Apple ID method only)

10-character Apple Team ID

APPLE_ID

macOS notarization (alternative)

Apple ID email

APPLE_APP_SPECIFIC_PASSWORD

macOS notarization (alternative)

App-specific password for that Apple ID

Linux builds do not need signing or notarization secrets. GITHUB_TOKEN is provided by GitHub Actions automatically.

If a signing secret is missing, electron-builder still produces installers, but they are unsigned. If notarization secrets are missing while notarize is enabled, the macOS job fails.

You only need one complete notarization method: API Key (APPLE_API_KEY + APPLE_API_KEY_ID + APPLE_API_ISSUER) or Apple ID (APPLE_ID + APPLE_APP_SPECIFIC_PASSWORD + APPLE_TEAM_ID). Preferred for CI: API Key. Do not rely on mixing both sets — the Release workflow picks API Key when complete and ignores Apple ID credentials in that case.

Windows signing (WIN_CSC_*)

You need a code-signing certificate as a .pfx / .p12 file (EV or OV from a public CA such as DigiCert, Sectigo, SSL.com).

  1. Export the certificate from your CA portal or Windows Certificate Manager as a Personal Information Exchange (``.pfx``), including the private key.

  2. Note the export password — that becomes WIN_CSC_KEY_PASSWORD.

  3. Encode the file as base64 for WIN_CSC_LINK:

# macOS / Linux
base64 -i Consoleri-windows.pfx | tr -d '\n' > win-csc-link.txt

# Windows (PowerShell)
[Convert]::ToBase64String([IO.File]::ReadAllBytes("Consoleri-windows.pfx")) | Set-Content -NoNewline win-csc-link.txt
  1. In GitHub: Settings → Secrets and variables → Actions → New repository secret.

  2. Name: WIN_CSC_LINK — paste the contents of win-csc-link.txt (the base64 string itself, not a file path).

  3. Name: WIN_CSC_KEY_PASSWORD — paste the .pfx password.

If GitHub rejects a very long secret (Windows env vars can truncate above ~8192 characters), re-export the .pfx without the full certificate chain and encode again.

macOS signing (MAC_CSC_*)

Prerequisite: an active Apple Developer Program membership.

You need a Developer ID Application certificate (distribution outside the Mac App Store — GitHub Releases DMG/ZIP).

On Apple Developer

  1. Open Certificates, Identifiers & Profiles → Certificates.

  2. Click + to create a certificate.

  3. Under Software, select Developer ID Application (not Apple Development, Apple Distribution, or Mac App Distribution).

  4. Choose G2 Sub-CA when asked for the intermediary.

  5. Create a Certificate Signing Request on a Mac: Keychain Access → Certificate Assistant → Request a Certificate From a Certificate Authority.

    • Choose Saved to disk (do not use “Emailed to the CA”).

    • Leave CA Email empty.

  6. Upload the .certSigningRequest on the Apple site, continue, then download the .cer certificate.

  7. Double-click the .cer to install it into your login keychain.

  8. In Keychain Access → My Certificates, find Developer ID Application: … (it must show a disclosure triangle and a private key underneath).

  9. Export that certificate as a .p12 file and set an export password.

  10. Note your Team ID: developer.apple.com/account → Membership details (10 characters, e.g. ABCDE12345). Needed only if you use Apple ID notarization (APPLE_TEAM_ID).

On GitHub — signing secrets

base64 -i Consoleri-macos.p12 | tr -d '\n' > mac-csc-link.txt
  1. Open the GitHub repository → Settings → Secrets and variables → Actions.

  2. Click New repository secret (not Variables).

  3. Name: MAC_CSC_LINK — paste the contents of mac-csc-link.txt (the base64 string itself, not a file path).

  4. Name: MAC_CSC_KEY_PASSWORD — paste the .p12 export password.

The Release workflow maps these to CSC_LINK / CSC_KEY_PASSWORD for electron-builder on the macOS runner.

In a successful Release log, signing must show:

identityName=Developer ID Application: …

If you see Apple Development: instead, Gatekeeper will keep blocking downloads even if notarization is configured: MAC_CSC_* is missing, empty, or the .p12 is an Apple Development cert rather than Developer ID Application. Fix the certificate export and re-run Release.

macOS notarization

Notarization is required so Gatekeeper stops showing “Apple could not verify Consoleri.app…” after a clean download of the DMG.

On Apple — preferred: App Store Connect API Key

  1. Open App Store Connect.

  2. Go to Users and Access → Integrations → Team Keys (App Store Connect API).

  3. Copy the Issuer ID (UUID) at the top of the page — this becomes APPLE_API_ISSUER.

  4. Click Generate API Key (or +).

  5. Name it something like Consoleri CI, access Developer, then generate.

  6. Copy the Key ID — this becomes APPLE_API_KEY_ID.

  7. Download the .p8 private key file. Apple shows this download once; store it securely.

Encode the .p8 for GitHub (recommended):

# AuthKey_XXXXXXXXXX.p8 from the App Store Connect download
base64 -i AuthKey_XXXXXXXXXX.p8 | tr -d '\n' > apple-api-key.txt

notarytool needs a file path to the .p8, not the base64 string. The Release workflow decodes APPLE_API_KEY into ${RUNNER_TEMP}/AuthKey_<KEY_ID>.p8 and sets APPLE_API_KEY to that path before electron-builder runs. You can also store the raw PEM (including -----BEGIN PRIVATE KEY-----) in the secret; the workflow detects that and writes the file without base64 decoding.

On Apple — alternative: Apple ID + app-specific password

  1. Open appleid.apple.com and sign in with the Apple ID that belongs to the Developer team.

  2. Go to Sign-In and Security → App-Specific Passwords.

  3. Generate a password (label e.g. Consoleri CI). Copy it once — this becomes APPLE_APP_SPECIFIC_PASSWORD.

  4. APPLE_ID is that Apple ID email address.

  5. APPLE_TEAM_ID is the 10-character Team ID from developer.apple.com/account → Membership details.

On GitHub — notarization secrets

  1. Open the repository → Settings → Secrets and variables → Actions.

  2. Click New repository secret (do not use Variables).

  3. Add secrets for the method you chose.

Preferred for CI — API Key

Secret name

Value

APPLE_API_KEY

Contents of apple-api-key.txt (base64 of the .p8 file, no newlines) — or raw PEM

APPLE_API_KEY_ID

Key ID from App Store Connect (e.g. AB12CD34EF)

APPLE_API_ISSUER

Issuer ID UUID from the Integrations / Team Keys page

Do not set APPLE_TEAM_ID for this method in the workflow path — team is inferred from the API key. If API Key secrets are complete, the workflow ignores Apple ID secrets for that run.

Alternative — Apple ID

Secret name

Value

APPLE_ID

Apple ID email used for the Developer team

APPLE_APP_SPECIFIC_PASSWORD

App-specific password from appleid.apple.com

APPLE_TEAM_ID

10-character Team ID from Membership details

Use this set only when API Key secrets are not configured.

Verifying

  1. Confirm signing secrets and at least one complete notarization set exist in the repository.

  2. Cut a release: npm run release -- patch (pushes commit and tag when push is enabled).

  3. Open the Release workflow → macOS job. Expect:

    • Prepare step: Notarization strategy: App Store Connect API key (or Apple ID)

    • identityName=Developer ID Application: — if you still see Apple Development: , fix MAC_CSC_* before chasing Gatekeeper

    • notarization succeeding (no file couldn't be opened / invalid --key errors)

  4. On a clean Mac: download the DMG from the GitHub Release, open the app. Gatekeeper should not show “Apple could not verify Consoleri.app…”.

  5. Confirm Release assets include .exe, .dmg, .AppImage, and .deb installers only (not helper tools from unpacked builds).