forked from UNIkeEN/SJMCL
-
Notifications
You must be signed in to change notification settings - Fork 0
261 lines (218 loc) Β· 8.69 KB
/
sign-macos.yml
File metadata and controls
261 lines (218 loc) Β· 8.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
name: Sign macOS Artifacts
permissions:
contents: read
on:
workflow_call:
inputs:
version:
description: 'Version to sign'
required: true
type: string
secrets:
MACOS_CERT_P12_BASE64:
description: 'Base64 encoded p12 certificate'
required: false
MACOS_CERT_P12_PASSWORD:
description: 'Password for p12 certificate'
required: false
MACOS_SIGNING_IDENTITY:
description: 'Code signing identity'
required: false
MACOS_NOTARY_APPLE_ID:
description: 'Apple ID for notarization'
required: false
MACOS_NOTARY_PASSWORD:
description: 'App-specific password for notarization'
required: false
MACOS_NOTARY_TEAM_ID:
description: 'Team ID for notarization'
required: false
jobs:
sign-macos:
runs-on: macos-latest
strategy:
matrix:
arch: [aarch64, x86_64]
steps:
- name: Validate signing secrets
id: validate
run: |
MISSING_SECRETS=()
if [ -z "${{ secrets.MACOS_CERT_P12_BASE64 }}" ]; then
MISSING_SECRETS+=("MACOS_CERT_P12_BASE64")
fi
if [ -z "${{ secrets.MACOS_CERT_P12_PASSWORD }}" ]; then
MISSING_SECRETS+=("MACOS_CERT_P12_PASSWORD")
fi
if [ -z "${{ secrets.MACOS_SIGNING_IDENTITY }}" ]; then
MISSING_SECRETS+=("MACOS_SIGNING_IDENTITY")
fi
if [ -z "${{ secrets.MACOS_NOTARY_APPLE_ID }}" ]; then
MISSING_SECRETS+=("MACOS_NOTARY_APPLE_ID")
fi
if [ -z "${{ secrets.MACOS_NOTARY_PASSWORD }}" ]; then
MISSING_SECRETS+=("MACOS_NOTARY_PASSWORD")
fi
if [ -z "${{ secrets.MACOS_NOTARY_TEAM_ID }}" ]; then
MISSING_SECRETS+=("MACOS_NOTARY_TEAM_ID")
fi
if [ ${#MISSING_SECRETS[@]} -gt 0 ]; then
echo "::warning::β οΈ macOS code signing will be skipped - missing secrets: ${MISSING_SECRETS[*]}"
echo "The release will continue with unsigned macOS artifacts."
exit 1
fi
echo "β
All required secrets are present"
- uses: actions/checkout@v4
- name: Download macOS artifacts
uses: actions/download-artifact@v4
with:
name: SJMCL_${{ inputs.version }}_macos_${{ matrix.arch }}
path: artifacts
- name: Setup signing environment
env:
CERT_P12_BASE64: ${{ secrets.MACOS_CERT_P12_BASE64 }}
CERT_P12_PASSWORD: ${{ secrets.MACOS_CERT_P12_PASSWORD }}
run: |
# Decode p12 file
echo "$CERT_P12_BASE64" | base64 -d > /tmp/cert.p12
# Create temporary keychain
KEYCHAIN_PATH=$HOME/temp-signing.keychain-db
security create-keychain -p "password" "$KEYCHAIN_PATH"
security unlock-keychain -p "password" "$KEYCHAIN_PATH"
security set-keychain-settings "$KEYCHAIN_PATH"
# Import certificate
security import /tmp/cert.p12 -k "$KEYCHAIN_PATH" -P "$CERT_P12_PASSWORD" -T /usr/bin/codesign
# Set default keychain
security list-keychains -s "$KEYCHAIN_PATH"
# Clean up certificate file
rm /tmp/cert.p12
- name: Install appdmg
run: |
npm install -g appdmg
- name: Extract and sign .app
env:
SIGNING_IDENTITY: ${{ secrets.MACOS_SIGNING_IDENTITY }}
run: |
cd artifacts
# Extract the .app from tar.gz
tar -xzf SJMCL_${{ inputs.version }}_macos_${{ matrix.arch }}.app.tar.gz
# Sign the .app bundle
codesign --deep --force --options runtime \
--sign "$SIGNING_IDENTITY" \
"SJMCL.app"
# Verify signing
codesign --verify --deep --strict --verbose=2 SJMCL.app
# Re-compress the signed .app
rm SJMCL_${{ inputs.version }}_macos_${{ matrix.arch }}.app.tar.gz
tar -czf SJMCL_${{ inputs.version }}_macos_${{ matrix.arch }}.app.tar.gz SJMCL.app
- name: Create DMG configuration
run: |
cd artifacts
# Create appdmg configuration file
cat > dmg-config.json << EOF
{
"title": "SJMCL Installer",
"icon": "../src-tauri/assets/icons/dmg/volume.icns",
"background": "../src-tauri/assets/misc/dmg_bg.png",
"format": "UDZO",
"icon-size": 120,
"window": {
"size": {
"width": 640,
"height": 418
}
},
"contents": [
{
"x": 180,
"y": 170,
"type": "file",
"path": "SJMCL.app"
},
{
"x": 480,
"y": 170,
"type": "link",
"path": "/Applications"
}
]
}
EOF
- name: Create and sign DMG
env:
SIGNING_IDENTITY: ${{ secrets.MACOS_SIGNING_IDENTITY }}
run: |
cd artifacts
# Remove the original DMG if it exists (build workflow no longer creates DMG)
rm -f SJMCL_${{ inputs.version }}_macos_${{ matrix.arch }}.dmg
# Create a new DMG with the signed app using appdmg
appdmg dmg-config.json SJMCL_${{ inputs.version }}_macos_${{ matrix.arch }}.dmg
# Sign the new DMG
codesign --force --sign "$SIGNING_IDENTITY" \
SJMCL_${{ inputs.version }}_macos_${{ matrix.arch }}.dmg
# Verify DMG signing
codesign --verify --deep --strict --verbose=2 SJMCL_${{ inputs.version }}_macos_${{ matrix.arch }}.dmg
# Clean up extracted .app and config file
rm -rf SJMCL.app dmg-config.json
- name: Notarize .app
env:
NOTARY_APPLE_ID: ${{ secrets.MACOS_NOTARY_APPLE_ID }}
NOTARY_PASSWORD: ${{ secrets.MACOS_NOTARY_PASSWORD }}
NOTARY_TEAM_ID: ${{ secrets.MACOS_NOTARY_TEAM_ID }}
run: |
cd artifacts
# Extract .app for notarization
tar -xzf SJMCL_${{ inputs.version }}_macos_${{ matrix.arch }}.app.tar.gz
# Create zip for notarization
ditto -c -k --keepParent SJMCL.app SJMCL.zip
# Submit for notarization
xcrun notarytool submit SJMCL.zip \
--apple-id "$NOTARY_APPLE_ID" \
--password "$NOTARY_PASSWORD" \
--team-id "$NOTARY_TEAM_ID" \
--wait
# Staple the notarization
xcrun stapler staple SJMCL.app
# Re-compress the notarized .app
rm SJMCL_${{ inputs.version }}_macos_${{ matrix.arch }}.app.tar.gz SJMCL.zip
tar -czf SJMCL_${{ inputs.version }}_macos_${{ matrix.arch }}.app.tar.gz SJMCL.app
rm -rf SJMCL.app
- name: Notarize DMG
env:
NOTARY_APPLE_ID: ${{ secrets.MACOS_NOTARY_APPLE_ID }}
NOTARY_PASSWORD: ${{ secrets.MACOS_NOTARY_PASSWORD }}
NOTARY_TEAM_ID: ${{ secrets.MACOS_NOTARY_TEAM_ID }}
run: |
cd artifacts
# Submit DMG for notarization
xcrun notarytool submit SJMCL_${{ inputs.version }}_macos_${{ matrix.arch }}.dmg \
--apple-id "$NOTARY_APPLE_ID" \
--password "$NOTARY_PASSWORD" \
--team-id "$NOTARY_TEAM_ID" \
--wait
# Staple the notarization to DMG
xcrun stapler staple SJMCL_${{ inputs.version }}_macos_${{ matrix.arch }}.dmg
- name: Verify notarization
run: |
cd artifacts
# Extract the notarized .app for verification
tar -xzf SJMCL_${{ inputs.version }}_macos_${{ matrix.arch }}.app.tar.gz
echo "=== Testing Gatekeeper assessment on notarized app ==="
spctl --verbose=4 --assess --type execute SJMCL.app
echo "=== Final signature verification ==="
codesign --verify --deep --strict --verbose=2 SJMCL.app
# Clean up extracted .app
rm -rf SJMCL.app
- name: Cleanup keychain
if: always()
run: |
KEYCHAIN_PATH=$HOME/temp-signing.keychain-db
if [ -f "$KEYCHAIN_PATH" ]; then
security delete-keychain "$KEYCHAIN_PATH"
fi
- name: Upload signed artifacts
uses: actions/upload-artifact@v4
with:
name: SJMCL_${{ inputs.version }}_macos_${{ matrix.arch }}_signed
path: artifacts/*
if-no-files-found: error