Compare commits

...

2 Commits

Author SHA1 Message Date
Alex Cheema ed3a974c61 fix: sign all Sparkle framework nested binaries inside-out
The previous change broke notarization because Sparkle's nested XPC services
(Downloader, Installer), Updater.app, and Autoupdate binary were not being
signed with Developer ID. Now signs all binaries inside Frameworks first,
then signs bundle wrappers (xpc, app, framework) from innermost to outermost.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 01:48:15 -08:00
Alex Cheema e90289635e fix: preserve entitlements and remove --deep codesign to fix local network permission on reboot
On macOS 26.3, the local network permission was silently lost on every reboot.
Diagnostics confirmed that `codesign --deep --force` was stripping entitlements
from the main binary, and `nehelper` (Network Extension Helper) could not resolve
the process identity on cold boot, causing mDNS connections to be silently blocked.

Changes:
- Replace `--deep` codesign with explicit inside-out signing that preserves entitlements
- Add `disable-library-validation` and `allow-unsigned-executable-memory` entitlements
  to both the main app and PyInstaller executables
- Sign PyInstaller executables separately from libraries, with entitlements
- Add post-sign verification step in CI

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 01:07:19 -08:00
3 changed files with 55 additions and 2 deletions
+41 -2
View File
@@ -285,12 +285,23 @@ jobs:
security unlock-keychain -p "$MACOS_CERTIFICATE_PASSWORD" "$BUILD_KEYCHAIN_PATH"
SIGNING_IDENTITY=$(security find-identity -v -p codesigning "$BUILD_KEYCHAIN_PATH" | awk -F '"' '{print $2}')
RUNTIME_DIR="EXO.app/Contents/Resources/exo"
find "$RUNTIME_DIR" -type f \( -perm -111 -o -name "*.dylib" -o -name "*.so" \) -print0 |
RUNTIME_ENTITLEMENTS="$GITHUB_WORKSPACE/packaging/entitlements/runtime.entitlements"
# Sign .so and .dylib files first (no entitlements needed for libraries)
find "$RUNTIME_DIR" -type f \( -name "*.dylib" -o -name "*.so" \) -print0 |
while IFS= read -r -d '' file; do
/usr/bin/codesign --force --timestamp --options runtime \
--sign "$SIGNING_IDENTITY" "$file"
done
# Sign executables with entitlements (they load libraries via dlopen)
find "$RUNTIME_DIR" -type f -perm -111 ! -name "*.dylib" ! -name "*.so" -print0 |
while IFS= read -r -d '' file; do
/usr/bin/codesign --force --timestamp --options runtime \
--entitlements "$RUNTIME_ENTITLEMENTS" \
--sign "$SIGNING_IDENTITY" "$file"
done
- name: Sign, notarize, and create DMG
env:
MACOS_CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PASSWORD }}
@@ -301,8 +312,36 @@ jobs:
cd output
security unlock-keychain -p "$MACOS_CERTIFICATE_PASSWORD" "$BUILD_KEYCHAIN_PATH"
SIGNING_IDENTITY=$(security find-identity -v -p codesigning "$BUILD_KEYCHAIN_PATH" | awk -F '"' '{print $2}')
/usr/bin/codesign --deep --force --timestamp --options runtime \
APP_ENTITLEMENTS="$GITHUB_WORKSPACE/app/EXO/EXO/EXO.entitlements"
# Sign all binaries inside Frameworks directory inside-out
# (Sparkle has nested XPC services, Updater.app, and Autoupdate that all need signing)
find EXO.app/Contents/Frameworks -type f \( -perm -111 -o -name "*.dylib" \) -print0 | \
while IFS= read -r -d '' file; do
/usr/bin/codesign --force --timestamp --options runtime \
--sign "$SIGNING_IDENTITY" "$file"
done
# Then sign framework bundles, XPC services, and .app bundles
find EXO.app/Contents/Frameworks -name "*.xpc" -o -name "*.app" -o -name "*.framework" | sort -r | \
while IFS= read -r bundle; do
/usr/bin/codesign --force --timestamp --options runtime \
--sign "$SIGNING_IDENTITY" "$bundle"
done
# Sign the main app binary with entitlements (no --deep!)
/usr/bin/codesign --force --timestamp --options runtime \
--entitlements "$APP_ENTITLEMENTS" \
--sign "$SIGNING_IDENTITY" EXO.app/Contents/MacOS/EXO
# Sign the outer app bundle with entitlements
/usr/bin/codesign --force --timestamp --options runtime \
--entitlements "$APP_ENTITLEMENTS" \
--sign "$SIGNING_IDENTITY" EXO.app
# Verify the complete signature chain
/usr/bin/codesign --verify --deep --strict --verbose=2 EXO.app
echo "Verifying entitlements are embedded:"
/usr/bin/codesign -d --entitlements - EXO.app/Contents/MacOS/EXO
mkdir -p dmg-root
cp -R EXO.app dmg-root/
ln -s /Applications dmg-root/Applications
+4
View File
@@ -8,5 +8,9 @@
<true/>
<key>com.apple.security.files.user-selected.read-only</key>
<true/>
<key>com.apple.security.cs.disable-library-validation</key>
<true/>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
</dict>
</plist>
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.cs.disable-library-validation</key>
<true/>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
</dict>
</plist>