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+=("$@")