Skip to content

Commit 41bb593

Browse files
committed
feat: implement macOS code signing and notarization pipeline with entitlements
1 parent 602b215 commit 41bb593

2 files changed

Lines changed: 72 additions & 3 deletions

File tree

.github/workflows/macos.yml

Lines changed: 55 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,26 @@ jobs:
2626
CARGO_PROFILE_RELEASE_CODEGEN_UNITS: "1"
2727
CARGO_PROFILE_RELEASE_STRIP: "true"
2828
run: cargo build --release
29-
29+
30+
- name: Import Apple Certificate
31+
if: ${{ secrets.MACOS_CERTIFICATE != '' }}
32+
env:
33+
BUILD_CERTIFICATE_BASE64: ${{ secrets.MACOS_CERTIFICATE }}
34+
P12_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PWD }}
35+
run: |
36+
CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12
37+
KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
38+
KEYCHAIN_PASSWORD=$(openssl rand -base64 12)
39+
40+
echo -n "$BUILD_CERTIFICATE_BASE64" | base64 --decode -o $CERTIFICATE_PATH
41+
42+
security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
43+
security default-keychain -s $KEYCHAIN_PATH
44+
security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
45+
46+
security import $CERTIFICATE_PATH -k $KEYCHAIN_PATH -P "$P12_PASSWORD" -T /usr/bin/codesign -T /usr/bin/productsign
47+
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
48+
3049
- name: Package Application
3150
run: |
3251
VERSION=$(grep -m1 '^version =' Cargo.toml | cut -d '"' -f2)
@@ -87,8 +106,16 @@ jobs:
87106
cp assets/soundfont.sf2 RustTracker.app/Contents/Resources/
88107
dylibbundler -od -b -x RustTracker.app/Contents/MacOS/rusttracker -d RustTracker.app/Contents/Frameworks/ -p @executable_path/../Frameworks/
89108
90-
# Ad-hoc codesign the entire bundle recursively to satisfy security requirements (especially Apple Silicon)
91-
codesign --force --deep --sign - RustTracker.app
109+
# Codesign the application
110+
if [ -n "${{ secrets.MACOS_CERTIFICATE }}" ]; then
111+
echo "Signing with Developer ID Certificate..."
112+
find RustTracker.app/Contents/Frameworks -type f \( -name "*.dylib" -or -name "*.so" \) -exec codesign --force --options runtime --sign "Developer ID Application" {} \;
113+
codesign --force --options runtime --entitlements entitlements.plist --sign "Developer ID Application" RustTracker.app/Contents/MacOS/rusttracker
114+
codesign --force --options runtime --entitlements entitlements.plist --sign "Developer ID Application" RustTracker.app
115+
else
116+
echo "No Developer ID Certificate found. Performing ad-hoc signing..."
117+
codesign --force --deep --sign - RustTracker.app
118+
fi
92119
93120
- name: Create DMG
94121
run: |
@@ -101,6 +128,31 @@ jobs:
101128
--app-drop-link 400 190 \
102129
"RustTracker-MacOS-Installer.dmg" \
103130
"RustTracker.app"
131+
132+
- name: Notarize DMG
133+
if: ${{ secrets.APPLE_ID != '' }}
134+
env:
135+
APPLE_ID: ${{ secrets.APPLE_ID }}
136+
APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
137+
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
138+
run: |
139+
echo "Submitting DMG for notarization..."
140+
xcrun notarytool submit RustTracker-MacOS-Installer.dmg \
141+
--apple-id "$APPLE_ID" \
142+
--password "$APPLE_ID_PASSWORD" \
143+
--team-id "$APPLE_TEAM_ID" \
144+
--wait
145+
146+
echo "Stapling notarization ticket to DMG..."
147+
xcrun stapler staple RustTracker-MacOS-Installer.dmg
148+
149+
- name: Clean up Keychain
150+
if: always() && secrets.MACOS_CERTIFICATE != ''
151+
run: |
152+
KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
153+
if [ -f "$KEYCHAIN_PATH" ]; then
154+
security delete-keychain $KEYCHAIN_PATH
155+
fi
104156
105157
- name: Upload Artifact
106158
uses: actions/upload-artifact@v5

entitlements.plist

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+
<plist version="1.0">
4+
<dict>
5+
<!-- Essential for audio-reactive features (microphone input) -->
6+
<key>com.apple.security.device.audio-input</key>
7+
<true/>
8+
9+
<!-- Needed for GPU-accelerated rendering and dynamic memory mapping -->
10+
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
11+
<true/>
12+
13+
<!-- Necessary because we bundle dynamic libraries (FFmpeg, libopenmpt) via dylibbundler -->
14+
<key>com.apple.security.cs.disable-library-validation</key>
15+
<true/>
16+
</dict>
17+
</plist>

0 commit comments

Comments
 (0)