Skip to content

Commit 9565baa

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 9565baa

8 files changed

Lines changed: 208 additions & 13 deletions

File tree

.github/workflows/release-linux.yaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
# while POCO will be linked statically.
55
name: Build Release Package for Linux
66

7-
on: workflow_dispatch
7+
on:
8+
workflow_dispatch:
9+
workflow_call:
810

911
jobs:
1012
build-deb:

.github/workflows/release-macos.yaml

Lines changed: 126 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,22 @@
22
# Builds a universal binary on macOS.
33
name: Build Release Package for macOS
44

5-
on: workflow_dispatch
5+
on:
6+
workflow_dispatch:
7+
workflow_call:
8+
secrets:
9+
MACOS_CERTIFICATE_APPLICATION:
10+
required: true
11+
MACOS_CERTIFICATE_INSTALLER:
12+
required: true
13+
MACOS_CERTIFICATE_PASSWORD:
14+
required: true
15+
MACOS_NOTARY_API_KEY:
16+
required: true
17+
MACOS_NOTARY_KEY_ID:
18+
required: true
19+
MACOS_NOTARY_ISSUER_ID:
20+
required: true
621

722
jobs:
823
build-deb:
@@ -112,19 +127,123 @@ jobs:
112127
"-DCMAKE_PREFIX_PATH=${GITHUB_WORKSPACE}/install-libprojectm;${GITHUB_WORKSPACE}/install-poco;${GITHUB_WORKSPACE}/install-libsdl2" \
113128
"-DPRESET_DIRS=${{ github.workspace }}/presets-cream-of-the-crop" \
114129
"-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/' \
118130
-DENABLE_INSTALL_BDEPS=ON
119131
cmake --build cmake-build-frontend-sdl2 --parallel
132+
cmake --install cmake-build-frontend-sdl2 --prefix "${{ github.workspace }}/install"
133+
134+
- name: Import Code Signing Certificates
135+
env:
136+
MACOS_CERTIFICATE_APPLICATION: ${{ secrets.MACOS_CERTIFICATE_APPLICATION }}
137+
MACOS_CERTIFICATE_INSTALLER: ${{ secrets.MACOS_CERTIFICATE_INSTALLER }}
138+
MACOS_CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PASSWORD }}
139+
run: |
140+
echo "$MACOS_CERTIFICATE_APPLICATION" | base64 --decode > app_cert.p12 && chmod 600 app_cert.p12
141+
echo "$MACOS_CERTIFICATE_INSTALLER" | base64 --decode > installer_cert.p12 && chmod 600 installer_cert.p12
142+
143+
KEYCHAIN_PASSWORD=$(openssl rand -base64 32)
144+
security create-keychain -p "$KEYCHAIN_PASSWORD" build.keychain
145+
security default-keychain -s build.keychain
146+
security unlock-keychain -p "$KEYCHAIN_PASSWORD" build.keychain
147+
148+
security import app_cert.p12 -k build.keychain -P "$MACOS_CERTIFICATE_PASSWORD" -T /usr/bin/codesign
149+
security import installer_cert.p12 -k build.keychain -P "$MACOS_CERTIFICATE_PASSWORD" -T /usr/bin/productsign
150+
151+
security set-key-partition-list -S apple-tool:,apple:,codesign:,productbuild: -s -k "$KEYCHAIN_PASSWORD" build.keychain
152+
153+
rm app_cert.p12 installer_cert.p12
154+
155+
- name: Sign Application Bundle
156+
run: |
157+
APP_PATH="${{ github.workspace }}/install/projectM.app"
158+
IDENTITY="Developer ID Application: Mischa Spiegelmock (5926VBQM6Y)"
159+
160+
# Sign all dylibs first (if PlugIns directory exists)
161+
if [ -d "$APP_PATH/Contents/PlugIns" ]; then
162+
find "$APP_PATH/Contents/PlugIns" -name "*.dylib" -exec \
163+
codesign --force --options runtime --sign "$IDENTITY" {} \;
164+
fi
165+
166+
# Sign the main executable
167+
codesign --force --options runtime --sign "$IDENTITY" \
168+
"$APP_PATH/Contents/MacOS/projectM"
169+
170+
# Sign the entire bundle
171+
codesign --force --options runtime --sign "$IDENTITY" "$APP_PATH"
172+
173+
# Verify
174+
codesign --verify --deep --strict "$APP_PATH"
175+
176+
- name: Notarize Application
177+
env:
178+
API_KEY_BASE64: ${{ secrets.MACOS_NOTARY_API_KEY }}
179+
API_KEY_ID: ${{ secrets.MACOS_NOTARY_KEY_ID }}
180+
API_ISSUER_ID: ${{ secrets.MACOS_NOTARY_ISSUER_ID }}
181+
run: |
182+
mkdir -p ~/.private_keys
183+
echo "$API_KEY_BASE64" | base64 --decode > ~/.private_keys/AuthKey_${API_KEY_ID}.p8
184+
chmod 600 ~/.private_keys/AuthKey_${API_KEY_ID}.p8
185+
186+
ditto -c -k --keepParent \
187+
"${{ github.workspace }}/install/projectM.app" \
188+
"projectM-notarize.zip"
189+
190+
xcrun notarytool submit "projectM-notarize.zip" \
191+
--key ~/.private_keys/AuthKey_${API_KEY_ID}.p8 \
192+
--key-id "$API_KEY_ID" \
193+
--issuer "$API_ISSUER_ID" \
194+
--wait
195+
196+
xcrun stapler staple "${{ github.workspace }}/install/projectM.app"
120197
121198
- name: Package projectMSDL
122199
run: |
123-
cd cmake-build-frontend-sdl2
124-
cpack -G productbuild
200+
# Get version from CMake
201+
VERSION=$(grep "project(projectMSDL" frontend-sdl2/CMakeLists.txt | sed -E 's/.*VERSION ([0-9.]+).*/\1/')
202+
203+
# Build component package from signed app
204+
pkgbuild \
205+
--root "${{ github.workspace }}/install" \
206+
--identifier "org.projectm-visualizer.projectmsdl" \
207+
--version "$VERSION" \
208+
--install-location "/Applications" \
209+
--component-plist "frontend-sdl2/src/resources/projectMSDL-component.plist" \
210+
"projectMSDL-component.pkg"
211+
212+
# Build unsigned product archive
213+
productbuild \
214+
--distribution "frontend-sdl2/src/resources/distribution.xml" \
215+
--package-path "." \
216+
--resources "frontend-sdl2/src/resources" \
217+
"projectM-${VERSION}-macOS-universal-unsigned.pkg"
218+
219+
# Sign the package with productsign
220+
productsign \
221+
--sign "Developer ID Installer: Mischa Spiegelmock (5926VBQM6Y)" \
222+
"projectM-${VERSION}-macOS-universal-unsigned.pkg" \
223+
"projectM-${VERSION}-macOS-universal.pkg"
224+
225+
rm "projectM-${VERSION}-macOS-universal-unsigned.pkg"
226+
227+
- name: Notarize Package
228+
env:
229+
API_KEY_ID: ${{ secrets.MACOS_NOTARY_KEY_ID }}
230+
API_ISSUER_ID: ${{ secrets.MACOS_NOTARY_ISSUER_ID }}
231+
run: |
232+
PKG_FILE=$(ls projectM-*.pkg | head -1)
233+
234+
xcrun notarytool submit "$PKG_FILE" \
235+
--key ~/.private_keys/AuthKey_${API_KEY_ID}.p8 \
236+
--key-id "$API_KEY_ID" \
237+
--issuer "$API_ISSUER_ID" \
238+
--wait
239+
240+
xcrun stapler staple "$PKG_FILE"
241+
242+
# Clean up API key
243+
rm -f ~/.private_keys/AuthKey_${API_KEY_ID}.p8
125244
126245
- name: Upload Artifact
127246
uses: actions/upload-artifact@v4
128247
with:
129248
name: projectMSDL-macOS-Universal
130-
path: cmake-build-frontend-sdl2/*.pkg
249+
path: projectM-*.pkg

.github/workflows/release-windows.yaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
# including projectM.
44
name: Build Release Package for Windows
55

6-
on: workflow_dispatch
6+
on:
7+
workflow_dispatch:
8+
workflow_call:
79

810
jobs:
911
build:

.github/workflows/release.yaml

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# Unified release workflow
2+
# Triggers on version tags, builds all platforms, and creates a GitHub release
3+
name: Release
4+
5+
on:
6+
push:
7+
tags:
8+
- 'v*'
9+
10+
jobs:
11+
build-linux:
12+
name: Build Linux
13+
uses: ./.github/workflows/release-linux.yaml
14+
15+
build-windows:
16+
name: Build Windows
17+
uses: ./.github/workflows/release-windows.yaml
18+
19+
build-macos:
20+
name: Build macOS
21+
uses: ./.github/workflows/release-macos.yaml
22+
secrets:
23+
MACOS_CERTIFICATE_APPLICATION: ${{ secrets.MACOS_CERTIFICATE_APPLICATION }}
24+
MACOS_CERTIFICATE_INSTALLER: ${{ secrets.MACOS_CERTIFICATE_INSTALLER }}
25+
MACOS_CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PASSWORD }}
26+
MACOS_NOTARY_API_KEY: ${{ secrets.MACOS_NOTARY_API_KEY }}
27+
MACOS_NOTARY_KEY_ID: ${{ secrets.MACOS_NOTARY_KEY_ID }}
28+
MACOS_NOTARY_ISSUER_ID: ${{ secrets.MACOS_NOTARY_ISSUER_ID }}
29+
30+
create-release:
31+
name: Create Release
32+
needs: [build-linux, build-windows, build-macos]
33+
runs-on: ubuntu-latest
34+
permissions:
35+
contents: write
36+
37+
steps:
38+
- name: Download all artifacts
39+
uses: actions/download-artifact@v4
40+
with:
41+
path: artifacts
42+
43+
- name: Display artifacts
44+
run: ls -R artifacts
45+
46+
- name: Create Release
47+
uses: softprops/action-gh-release@v2
48+
with:
49+
generate_release_notes: true
50+
files: |
51+
artifacts/**/*.pkg
52+
artifacts/**/*.deb
53+
artifacts/**/*.tar.gz
54+
artifacts/**/*.zip
55+
artifacts/**/*.msi

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)