Skip to content

Commit a7e49fc

Browse files
revmischaclaude
andcommitted
Add code signing and notarization for macOS releases
Signs the app bundle and .pkg installer with Developer ID certificates, then notarizes both with Apple's notary service for Gatekeeper approval. Uses App Store Connect API key for notarization credentials. Replaces CPack with direct pkgbuild/productbuild for better signing control. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 0231108 commit a7e49fc

File tree

5 files changed

+131
-10
lines changed

5 files changed

+131
-10
lines changed

.github/workflows/release-macos.yaml

Lines changed: 110 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -112,19 +112,123 @@ jobs:
112112
"-DCMAKE_PREFIX_PATH=${GITHUB_WORKSPACE}/install-libprojectm;${GITHUB_WORKSPACE}/install-poco;${GITHUB_WORKSPACE}/install-libsdl2" \
113113
"-DPRESET_DIRS=${{ github.workspace }}/presets-cream-of-the-crop" \
114114
"-DTEXTURE_DIRS=${{ github.workspace }}/presets-milkdrop-texture-pack/textures" \
115-
'-DDEFAULT_CONFIG_PATH=${application.dir}/../share/projectMSDL/' \
116-
'-DDEFAULT_PRESETS_PATH=${application.dir}/../share/projectMSDL/presets/' \
117-
'-DDEFAULT_TEXTURES_PATH=${application.dir}/../share/projectMSDL/textures/' \
118115
-DENABLE_INSTALL_BDEPS=ON
119116
cmake --build cmake-build-frontend-sdl2 --parallel
117+
cmake --install cmake-build-frontend-sdl2 --prefix "${{ github.workspace }}/install"
118+
119+
- name: Import Code Signing Certificates
120+
env:
121+
MACOS_CERTIFICATE_APPLICATION: ${{ secrets.MACOS_CERTIFICATE_APPLICATION }}
122+
MACOS_CERTIFICATE_INSTALLER: ${{ secrets.MACOS_CERTIFICATE_INSTALLER }}
123+
MACOS_CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PASSWORD }}
124+
run: |
125+
echo "$MACOS_CERTIFICATE_APPLICATION" | base64 --decode > app_cert.p12 && chmod 600 app_cert.p12
126+
echo "$MACOS_CERTIFICATE_INSTALLER" | base64 --decode > installer_cert.p12 && chmod 600 installer_cert.p12
127+
128+
KEYCHAIN_PASSWORD=$(openssl rand -base64 32)
129+
security create-keychain -p "$KEYCHAIN_PASSWORD" build.keychain
130+
security default-keychain -s build.keychain
131+
security unlock-keychain -p "$KEYCHAIN_PASSWORD" build.keychain
132+
133+
security import app_cert.p12 -k build.keychain -P "$MACOS_CERTIFICATE_PASSWORD" -T /usr/bin/codesign
134+
security import installer_cert.p12 -k build.keychain -P "$MACOS_CERTIFICATE_PASSWORD" -T /usr/bin/productsign
135+
136+
security set-key-partition-list -S apple-tool:,apple:,codesign:,productbuild: -s -k "$KEYCHAIN_PASSWORD" build.keychain
137+
138+
rm app_cert.p12 installer_cert.p12
139+
140+
- name: Sign Application Bundle
141+
run: |
142+
APP_PATH="${{ github.workspace }}/install/projectM.app"
143+
IDENTITY="Developer ID Application: Mischa Spiegelmock (5926VBQM6Y)"
144+
145+
# Sign all dylibs first (if PlugIns directory exists)
146+
if [ -d "$APP_PATH/Contents/PlugIns" ]; then
147+
find "$APP_PATH/Contents/PlugIns" -name "*.dylib" -exec \
148+
codesign --force --options runtime --sign "$IDENTITY" {} \;
149+
fi
150+
151+
# Sign the main executable
152+
codesign --force --options runtime --sign "$IDENTITY" \
153+
"$APP_PATH/Contents/MacOS/projectM"
154+
155+
# Sign the entire bundle
156+
codesign --force --options runtime --sign "$IDENTITY" "$APP_PATH"
157+
158+
# Verify
159+
codesign --verify --deep --strict "$APP_PATH"
160+
161+
- name: Notarize Application
162+
env:
163+
API_KEY_BASE64: ${{ secrets.MACOS_NOTARY_API_KEY }}
164+
API_KEY_ID: ${{ secrets.MACOS_NOTARY_KEY_ID }}
165+
API_ISSUER_ID: ${{ secrets.MACOS_NOTARY_ISSUER_ID }}
166+
run: |
167+
mkdir -p ~/.private_keys
168+
echo "$API_KEY_BASE64" | base64 --decode > ~/.private_keys/AuthKey_${API_KEY_ID}.p8
169+
chmod 600 ~/.private_keys/AuthKey_${API_KEY_ID}.p8
170+
171+
ditto -c -k --keepParent \
172+
"${{ github.workspace }}/install/projectM.app" \
173+
"projectM-notarize.zip"
174+
175+
xcrun notarytool submit "projectM-notarize.zip" \
176+
--key ~/.private_keys/AuthKey_${API_KEY_ID}.p8 \
177+
--key-id "$API_KEY_ID" \
178+
--issuer "$API_ISSUER_ID" \
179+
--wait
180+
181+
xcrun stapler staple "${{ github.workspace }}/install/projectM.app"
120182
121183
- name: Package projectMSDL
122184
run: |
123-
cd cmake-build-frontend-sdl2
124-
cpack -G productbuild
185+
# Get version from CMake
186+
VERSION=$(grep "project(projectMSDL" frontend-sdl2/CMakeLists.txt | sed -E 's/.*VERSION ([0-9.]+).*/\1/')
187+
188+
# Build component package from signed app
189+
pkgbuild \
190+
--root "${{ github.workspace }}/install" \
191+
--identifier "org.projectm-visualizer.projectmsdl" \
192+
--version "$VERSION" \
193+
--install-location "/Applications" \
194+
--component-plist "frontend-sdl2/src/resources/projectMSDL-component.plist" \
195+
"projectMSDL-component.pkg"
196+
197+
# Build unsigned product archive
198+
productbuild \
199+
--distribution "frontend-sdl2/src/resources/distribution.xml" \
200+
--package-path "." \
201+
--resources "frontend-sdl2/src/resources" \
202+
"projectM-${VERSION}-macOS-universal-unsigned.pkg"
203+
204+
# Sign the package with productsign
205+
productsign \
206+
--sign "Developer ID Installer: Mischa Spiegelmock (5926VBQM6Y)" \
207+
"projectM-${VERSION}-macOS-universal-unsigned.pkg" \
208+
"projectM-${VERSION}-macOS-universal.pkg"
209+
210+
rm "projectM-${VERSION}-macOS-universal-unsigned.pkg"
211+
212+
- name: Notarize Package
213+
env:
214+
API_KEY_ID: ${{ secrets.MACOS_NOTARY_KEY_ID }}
215+
API_ISSUER_ID: ${{ secrets.MACOS_NOTARY_ISSUER_ID }}
216+
run: |
217+
PKG_FILE=$(ls projectM-*.pkg | head -1)
218+
219+
xcrun notarytool submit "$PKG_FILE" \
220+
--key ~/.private_keys/AuthKey_${API_KEY_ID}.p8 \
221+
--key-id "$API_KEY_ID" \
222+
--issuer "$API_ISSUER_ID" \
223+
--wait
224+
225+
xcrun stapler staple "$PKG_FILE"
226+
227+
# Clean up API key
228+
rm -f ~/.private_keys/AuthKey_${API_KEY_ID}.p8
125229
126230
- name: Upload Artifact
127231
uses: actions/upload-artifact@v4
128232
with:
129233
name: projectMSDL-macOS-Universal
130-
path: cmake-build-frontend-sdl2/*.pkg
234+
path: projectM-*.pkg

packaging-macos.cmake

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/src/resources/gpl-3
1010
set(CPACK_STRIP_FILES TRUE)
1111

1212
### Productbuild configuration
13-
set(CPACK_PKGBUILD_IDENTITY_NAME "${CODESIGN_IDENTITY_INSTALLER}")
14-
set(CPACK_PRODUCTBUILD_IDENTITY_NAME "${CODESIGN_IDENTITY_INSTALLER}")
13+
set(CPACK_PKGBUILD_IDENTITY_NAME "$ENV{CODESIGN_IDENTITY_INSTALLER}")
14+
set(CPACK_PRODUCTBUILD_IDENTITY_NAME "$ENV{CODESIGN_IDENTITY_INSTALLER}")
1515
set(CPACK_PRODUCTBUILD_IDENTIFIER "org.projectm-visualizer.projectmsdl")
1616

1717
string(REPLACE ";" "," INSTALL_ARCHITECTURES "${CMAKE_OSX_ARCHITECTURES}")

src/resources/distribution.xml

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+
<installer-gui-script minSpecVersion="2">
3+
<title>projectM</title>
4+
<organization>org.projectm-visualizer</organization>
5+
<welcome file="macos-welcome.txt"/>
6+
<readme file="macos-readme.txt"/>
7+
<license file="gpl-3.0.rtf"/>
8+
<options customize="never" require-scripts="false" hostArchitectures="x86_64,arm64"/>
9+
<domains enable_anywhere="false" enable_currentUserHome="false" enable_localSystem="true"/>
10+
<choices-outline>
11+
<line choice="default"/>
12+
</choices-outline>
13+
<choice id="default" title="projectM">
14+
<pkg-ref id="org.projectm-visualizer.projectmsdl"/>
15+
</choice>
16+
<pkg-ref id="org.projectm-visualizer.projectmsdl" version="0" onConclusion="none">projectMSDL-component.pkg</pkg-ref>
17+
</installer-gui-script>

src/resources/projectMSDL-component.plist

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
<key>BundleOverwriteAction</key>
1313
<string>upgrade</string>
1414
<key>RootRelativeBundlePath</key>
15-
<string>Applications/projectM.app</string>
15+
<string>projectM.app</string>
1616
</dict>
1717
</array>
1818
</plist>

vendor/imgui

Submodule imgui updated 157 files

0 commit comments

Comments
 (0)