From 963fc543d1d1e32b8ac246bec41bda519a550f2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A1=BE=E7=9B=BC?= Date: Fri, 12 Jun 2026 13:14:43 +0800 Subject: [PATCH] ci(desktop): mac code-signing + App Store Connect API-key notarization (#5013) * chore(desktop): drop dead NOTARIZE env flag from mac signing paths electron-builder (>=24) auto-notarizes via notarytool whenever APPLE_ID, APPLE_APP_SPECIFIC_PASSWORD, and APPLE_TEAM_ID are present in the env. The NOTARIZE=true flag set in the release workflow, build-dmg.sh, and scripts/build/darwin.ts was never read by electron-builder, and the build-dmg.sh comment claiming it enabled notarization was misleading. Remove the no-op and document the actual auto-detection behavior. * ci(desktop): notarize via App Store Connect API key instead of Apple ID Switch the macOS desktop release notarization path from the Apple ID + app-specific password method to the App Store Connect API key method, which is more robust (no 2FA, no password expiry) and reuses the notary key already provisioned for the org. The signing step now reads APPLE_NOTARY_API_KEY_P8_BASE64, APPLE_NOTARY_KEY_ID, and APPLE_NOTARY_ISSUER_ID, decodes the .p8 to a temp file, and exports APPLE_API_KEY/APPLE_API_KEY_ID/APPLE_API_ISSUER, which electron-builder (>=24) consumes to notarize via notarytool. Published mac releases now require those notary secrets plus APPLE_TEAM_ID. --- .github/workflows/desktop-release.yml | 23 +++++++++++++------ .../apps/electron/scripts/build-dmg.sh | 10 ++++---- packages/desktop/scripts/build/darwin.ts | 6 +++-- 3 files changed, 24 insertions(+), 15 deletions(-) diff --git a/.github/workflows/desktop-release.yml b/.github/workflows/desktop-release.yml index 442ddf6ba3..4adf4de8c7 100644 --- a/.github/workflows/desktop-release.yml +++ b/.github/workflows/desktop-release.yml @@ -377,8 +377,9 @@ jobs: shell: 'bash' env: IS_DRY_RUN: '${{ inputs.dry_run }}' - APPLE_APP_SPECIFIC_PASSWORD_SECRET: '${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}' - APPLE_ID_SECRET: '${{ secrets.APPLE_ID }}' + APPLE_NOTARY_API_KEY_P8_BASE64_SECRET: '${{ secrets.APPLE_NOTARY_API_KEY_P8_BASE64 }}' + APPLE_NOTARY_KEY_ID_SECRET: '${{ secrets.APPLE_NOTARY_KEY_ID }}' + APPLE_NOTARY_ISSUER_ID_SECRET: '${{ secrets.APPLE_NOTARY_ISSUER_ID }}' APPLE_TEAM_ID_SECRET: '${{ secrets.APPLE_TEAM_ID }}' MAC_CSC_KEY_PASSWORD_SECRET: '${{ secrets.MAC_CSC_KEY_PASSWORD }}' MAC_CSC_LINK_SECRET: '${{ secrets.MAC_CSC_LINK }}' @@ -424,17 +425,25 @@ jobs: fi if [ "$IS_DRY_RUN" = "false" ]; then - if [ -z "$APPLE_ID_SECRET" ] || [ -z "$APPLE_APP_SPECIFIC_PASSWORD_SECRET" ] || [ -z "$APPLE_TEAM_ID_SECRET" ]; then - echo "::error::Published macOS desktop releases require APPLE_ID, APPLE_APP_SPECIFIC_PASSWORD, and APPLE_TEAM_ID for notarization." + if [ -z "$APPLE_NOTARY_API_KEY_P8_BASE64_SECRET" ] || [ -z "$APPLE_NOTARY_KEY_ID_SECRET" ] || [ -z "$APPLE_NOTARY_ISSUER_ID_SECRET" ] || [ -z "$APPLE_TEAM_ID_SECRET" ]; then + echo "::error::Published macOS desktop releases require APPLE_NOTARY_API_KEY_P8_BASE64, APPLE_NOTARY_KEY_ID, APPLE_NOTARY_ISSUER_ID, and APPLE_TEAM_ID for notarization." exit 1 fi - append_env "NOTARIZE" "true" + fi + + # Materialize the App Store Connect API key (.p8) so electron-builder + # (>=24) notarizes via notarytool. It reads APPLE_API_KEY (a path to + # the .p8 file), APPLE_API_KEY_ID, and APPLE_API_ISSUER from the env. + if [ -n "$APPLE_NOTARY_API_KEY_P8_BASE64_SECRET" ] && [ -n "$APPLE_NOTARY_KEY_ID_SECRET" ] && [ -n "$APPLE_NOTARY_ISSUER_ID_SECRET" ]; then + api_key_path="${RUNNER_TEMP}/apple-notary-key.p8" + printf '%s' "$APPLE_NOTARY_API_KEY_P8_BASE64_SECRET" | base64 --decode > "$api_key_path" + append_env "APPLE_API_KEY" "$api_key_path" + append_env "APPLE_API_KEY_ID" "$APPLE_NOTARY_KEY_ID_SECRET" + append_env "APPLE_API_ISSUER" "$APPLE_NOTARY_ISSUER_ID_SECRET" fi append_env "CSC_LINK" "$mac_csc_link" append_env "CSC_KEY_PASSWORD" "$mac_csc_key_password" - append_env "APPLE_ID" "$APPLE_ID_SECRET" - append_env "APPLE_APP_SPECIFIC_PASSWORD" "$APPLE_APP_SPECIFIC_PASSWORD_SECRET" append_env "APPLE_TEAM_ID" "$APPLE_TEAM_ID_SECRET" echo "CSC_IDENTITY_AUTO_DISCOVERY=true" >> "$GITHUB_ENV" else diff --git a/packages/desktop/apps/electron/scripts/build-dmg.sh b/packages/desktop/apps/electron/scripts/build-dmg.sh index 9a91a0ce48..8127fd15f5 100755 --- a/packages/desktop/apps/electron/scripts/build-dmg.sh +++ b/packages/desktop/apps/electron/scripts/build-dmg.sh @@ -150,17 +150,15 @@ if [ -n "$APPLE_SIGNING_IDENTITY" ]; then export CSC_NAME="$CSC_NAME_CLEAN" fi -# Add notarization if all credentials are available +# Add notarization if all credentials are available. +# electron-builder (>=24) auto-notarizes via notarytool whenever APPLE_ID, +# APPLE_APP_SPECIFIC_PASSWORD, and APPLE_TEAM_ID are present in the env. +# No `notarize:` config block or NOTARIZE flag is required (or read). if [ -n "$APPLE_ID" ] && [ -n "$APPLE_TEAM_ID" ] && [ -n "$APPLE_APP_SPECIFIC_PASSWORD" ]; then echo "Notarization enabled" export APPLE_ID="$APPLE_ID" export APPLE_TEAM_ID="$APPLE_TEAM_ID" export APPLE_APP_SPECIFIC_PASSWORD="$APPLE_APP_SPECIFIC_PASSWORD" - - # Enable notarization in electron-builder by setting env vars - # The electron-builder.yml has notarize section commented out, - # but we can enable it via environment - export NOTARIZE=true fi # Run electron-builder diff --git a/packages/desktop/scripts/build/darwin.ts b/packages/desktop/scripts/build/darwin.ts index dce184c3f4..f5f86635f9 100644 --- a/packages/desktop/scripts/build/darwin.ts +++ b/packages/desktop/scripts/build/darwin.ts @@ -32,14 +32,16 @@ export async function packageDarwin(config: BuildConfig): Promise { process.env.CSC_NAME = cscName; } - // Add notarization if all credentials are available + // Add notarization if all credentials are available. + // electron-builder auto-notarizes via notarytool when APPLE_ID, + // APPLE_APP_SPECIFIC_PASSWORD, and APPLE_TEAM_ID are present in the env; + // no `notarize:` config block or NOTARIZE flag is required (or read). if ( process.env.APPLE_ID && process.env.APPLE_TEAM_ID && process.env.APPLE_APP_SPECIFIC_PASSWORD ) { console.log(' Notarization enabled'); - process.env.NOTARIZE = 'true'; } // Run electron-builder