From 85cf04e305f793dd3abea978494e95810250e0b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A8=8B=E5=BA=8F=E5=91=98=E9=98=BF=E6=B1=9F=28Relakkes?= =?UTF-8?q?=29?= Date: Wed, 3 Jun 2026 13:57:22 +0800 Subject: [PATCH] fix(desktop): make macOS signing+notarization explicit and Windows signing optional - mac.notarize=true + hardenedRuntime + entitlements so a signed CI release actually notarizes (gatekeeper smoke + Squirrel.Mac auto-update need it) - entitlements grant disable-library-validation for the Bun sidecar/node-pty - local unsigned build passes -c.mac.notarize=false so electron:package still works without an Apple account - release signing-preflight now hard-requires only the Apple secrets; Windows cert is optional (unsigned NSIS still auto-updates, just SmartScreen warning) Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/release-desktop.yml | 15 ++++++++++++--- desktop/build/entitlements.mac.inherit.plist | 17 +++++++++++++++++ desktop/build/entitlements.mac.plist | 19 +++++++++++++++++++ desktop/package.json | 7 ++++++- desktop/scripts/build-macos-arm64.sh | 4 ++++ 5 files changed, 58 insertions(+), 4 deletions(-) create mode 100644 desktop/build/entitlements.mac.inherit.plist create mode 100644 desktop/build/entitlements.mac.plist diff --git a/.github/workflows/release-desktop.yml b/.github/workflows/release-desktop.yml index 0cc03021..81d64189 100644 --- a/.github/workflows/release-desktop.yml +++ b/.github/workflows/release-desktop.yml @@ -63,18 +63,27 @@ jobs: WIN_CSC_LINK: ${{ secrets.WINDOWS_CERTIFICATE }} WIN_CSC_KEY_PASSWORD: ${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }} run: | + # macOS signing + notarization is mandatory: Squirrel.Mac auto-update and + # first-launch Gatekeeper approval both require a notarized Developer ID build. missing=() [ -n "$CSC_LINK" ] || missing+=("MACOS_CERTIFICATE") [ -n "$CSC_KEY_PASSWORD" ] || missing+=("MACOS_CERTIFICATE_PASSWORD") [ -n "$APPLE_ID" ] || missing+=("APPLE_ID") [ -n "$APPLE_APP_SPECIFIC_PASSWORD" ] || missing+=("APPLE_APP_SPECIFIC_PASSWORD") [ -n "$APPLE_TEAM_ID" ] || missing+=("APPLE_TEAM_ID") - [ -n "$WIN_CSC_LINK" ] || missing+=("WINDOWS_CERTIFICATE") - [ -n "$WIN_CSC_KEY_PASSWORD" ] || missing+=("WINDOWS_CERTIFICATE_PASSWORD") if [ "${#missing[@]}" -gt 0 ]; then - printf '::error::Missing required release signing/notarization secrets: %s\n' "${missing[*]}" + printf '::error::Missing required macOS signing/notarization secrets: %s\n' "${missing[*]}" exit 1 fi + # Windows signing is optional: an unsigned NSIS installer still auto-updates + # (electron-updater), it only triggers SmartScreen warnings. Warn, do not block, + # so releases can ship with an Apple Developer ID alone. + win_missing=() + [ -n "$WIN_CSC_LINK" ] || win_missing+=("WINDOWS_CERTIFICATE") + [ -n "$WIN_CSC_KEY_PASSWORD" ] || win_missing+=("WINDOWS_CERTIFICATE_PASSWORD") + if [ "${#win_missing[@]}" -gt 0 ]; then + printf '::warning::Windows signing secrets missing (%s): the Windows build will be unsigned. Auto-update still works, but users will see SmartScreen warnings.\n' "${win_missing[*]}" + fi build: needs: diff --git a/desktop/build/entitlements.mac.inherit.plist b/desktop/build/entitlements.mac.inherit.plist new file mode 100644 index 00000000..353721da --- /dev/null +++ b/desktop/build/entitlements.mac.inherit.plist @@ -0,0 +1,17 @@ + + + + + + com.apple.security.cs.allow-jit + + com.apple.security.cs.allow-unsigned-executable-memory + + com.apple.security.cs.allow-dyld-environment-variables + + com.apple.security.cs.disable-library-validation + + com.apple.security.inherit + + + diff --git a/desktop/build/entitlements.mac.plist b/desktop/build/entitlements.mac.plist new file mode 100644 index 00000000..b76445eb --- /dev/null +++ b/desktop/build/entitlements.mac.plist @@ -0,0 +1,19 @@ + + + + + + com.apple.security.cs.allow-jit + + com.apple.security.cs.allow-unsigned-executable-memory + + + com.apple.security.cs.allow-dyld-environment-variables + + + com.apple.security.cs.disable-library-validation + + + diff --git a/desktop/package.json b/desktop/package.json index 6c7cc496..5f770f08 100644 --- a/desktop/package.json +++ b/desktop/package.json @@ -33,7 +33,12 @@ "dmg", "zip" ], - "icon": "src-tauri/icons/icon.icns" + "icon": "src-tauri/icons/icon.icns", + "hardenedRuntime": true, + "gatekeeperAssess": false, + "entitlements": "build/entitlements.mac.plist", + "entitlementsInherit": "build/entitlements.mac.inherit.plist", + "notarize": true }, "win": { "target": "nsis", diff --git a/desktop/scripts/build-macos-arm64.sh b/desktop/scripts/build-macos-arm64.sh index 70ea0b1b..e8f207e0 100755 --- a/desktop/scripts/build-macos-arm64.sh +++ b/desktop/scripts/build-macos-arm64.sh @@ -113,6 +113,10 @@ echo "[build-macos-arm64] Cleaning empty dmg-builder cache directories..." BUILDER_ARGS=(bunx electron-builder --mac "${MAC_TARGET_ARRAY[@]}" --arm64 --publish never) if [[ "${SIGN_BUILD:-0}" != "1" ]]; then export CSC_IDENTITY_AUTO_DISCOVERY=false + # package.json sets mac.notarize=true for the signed CI release path. A local + # unsigned build has no Developer ID credentials, so explicitly disable + # notarization here to keep `electron:package` working without an Apple account. + BUILDER_ARGS+=(-c.mac.notarize=false) fi if [[ "$#" -gt 0 ]]; then BUILDER_ARGS+=("$@")