macOS Signing Guide

How Chatons builds, signs, and notarizes macOS artifacts.

See also: Manual Signing Instructions


Build System

macOS artifacts are built with Electron Builder, configured in package.json > build.

Key build settings:

SettingValue
appIdcom.thibaut.chaton
productNameChatons
mac.hardenedRuntimetrue
mac.gatekeeperAssessfalse
mac.entitlementsbuild/entitlements.mac.plist
mac.entitlementsInheritbuild/entitlements.mac.plist
mac.typedistribution
mac.notarizefalse (overridden by CI when secrets are available)
mac.targetdmg
dmg.artifactName${productName}-latest-${arch}.${ext}

Output directory: release/


CI Workflow (.github/workflows/build-all-platforms.yml)

The CI workflow handles the complete signing and notarization pipeline.

Steps

  1. Check whether signing secrets are available
  2. Check whether notarization secrets are also available
  3. Import the signing certificate into a temporary keychain
  4. Build renderer and Electron main process
  5. Run Electron Builder for macOS DMG
  6. Validate produced DMGs and enclosed app bundles
  7. Retry stapling when notarization propagation is slow

Secrets

SecretPurpose
MAC_CERTIFICATE or MACOS_CERTIFICATE_P12_BASE64Signing certificate (base64-encoded P12)
MAC_CERTIFICATE_PWD or MACOS_CERTIFICATE_P12_PASSWORDCertificate password
MACOS_KEYCHAIN_PASSWORDTemporary keychain password
MAC_DEVELOPER_IDDeveloper ID certificate name
APPLE_IDApple ID for notarization
APPLE_APP_SPECIFIC_PASSWORDApp-specific password for notarization
APPLE_TEAM_IDApple team identifier

Signing Modes

Certificate secretsNotarization secretsResult
Missing--Unsigned build
PresentMissingSigned-only build
PresentPresentSigned and notarized build

Entitlements

build/entitlements.mac.plist currently grants:

EntitlementWhy
com.apple.security.cs.allow-jitJIT compilation for V8/Electron
com.apple.security.cs.allow-unsigned-executable-memoryElectron runtime requirement
com.apple.security.cs.allow-dyld-environment-variablesDynamic library loading
com.apple.security.cs.disable-executable-page-protectionElectron runtime requirement
com.apple.security.network.clientOutbound network access (API calls)
com.apple.security.network.serverLocal server (OAuth callbacks on port 1455)

Local Helper Scripts

scripts/build-signed.sh

Shell script for local signed builds. Expects environment variables:

VariableRequiredDescription
APPLE_TEAM_IDYesTeam ID
APPLE_SIGNING_IDENTITYYesCertificate name
CSC_LINKNoPath to .p12 certificate file
APPLE_IDNoFor notarization
APPLE_ID_PASSWORDNoFor notarization
export APPLE_TEAM_ID="ABCDE12345"
export APPLE_SIGNING_IDENTITY="Developer ID Application: Your Name (ABCDE12345)"
bash scripts/build-signed.sh

scripts/build-signed.js

Node helper that reads from build/config.js and optional .env, then runs Electron Builder.

Important Note

These local scripts are convenience tools. The CI workflow is the authoritative release path. It handles more edge cases, validation, and retry logic.


Verification

After a signed build:

# Verify app signature
codesign --verify --deep --strict release/mac/Chatons.app

# Check Gatekeeper assessment
spctl -a -t exec -vv release/mac/Chatons.app

# Verify DMG (if notarized)
spctl -a -v -t install release/Chatons-latest-arm64.dmg

# Check stapler ticket
xcrun stapler validate release/Chatons-latest-arm64.dmg

Artifact Naming

The DMG artifact name is:

Chatons-latest-arm64.dmg

Based on the pattern ${productName}-latest-${arch}.${ext}. The semver version number does not appear in the filename by default.


ScenarioUse
Real releasesGitHub Actions workflow
Preparation / debuggingLocal helper scripts
Direct low-level controlManual Signing Instructions

On this page