@@ -81,6 +81,168 @@ jobs:
81
81
certificate-profile-name : ${{ vars.AZURE_SIGNING_CERT_NAME }}
82
82
files-folder : ${{ github.workspace }}\installer
83
83
files-folder-filter : exe
84
+ - name : sign Mac
85
+ if : ${{ github.event_name == 'push' && matrix.os == 'macos-latest' }}
86
+ env :
87
+ APPLE_ID : ${{ secrets.APPLE_ID }}
88
+ APPLE_ID_PASSWORD : ${{ secrets.APPLE_ID_PASSWORD }}
89
+ APPLE_TEAM_ID : ${{ secrets.APPLE_TEAM_ID }}
90
+ APPLE_CERTIFICATE_P12 : ${{ secrets.APPLE_CERTIFICATE_P12 }}
91
+ APPLE_CERTIFICATE_PASSWORD : ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
92
+ run : |
93
+ set -euxo pipefail
94
+
95
+ # Create and configure keychain
96
+ security create-keychain -p temp_password build.keychain
97
+ security default-keychain -s build.keychain
98
+ security unlock-keychain -p temp_password build.keychain
99
+ security list-keychains -d user -s build.keychain
100
+
101
+ # Decode and save the certificate from the environment variable
102
+ echo "$APPLE_CERTIFICATE_P12" | base64 --decode > certificate.p12
103
+
104
+ # Import certificate
105
+ security import certificate.p12 -k build.keychain -P "$APPLE_CERTIFICATE_PASSWORD" -T /usr/bin/codesign -T /usr/bin/security
106
+
107
+ # Set key partition list for codesign access with specific certificate targeting
108
+ security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k temp_password -D "Developer ID Application" -t private build.keychain
109
+
110
+ # Extract identity from build.keychain only
111
+ IDENTITY=$(security find-identity -v -p codesigning build.keychain | grep "Developer ID Application" | head -1 | sed 's/.*) \([^"]*\).*/\1/' | xargs)
112
+ echo "Signing with identity: $IDENTITY"
113
+ if [[ -z "$IDENTITY" ]]; then
114
+ echo "No codesigning identity found in build.keychain!"
115
+ exit 1
116
+ fi
117
+
118
+ cd installer/mac
119
+
120
+ # Set up app bundle and entitlements
121
+ APP_BUNDLE="OSARAInstaller.app"
122
+
123
+ # Create a temporary entitlements file for runtime (consistent with local build.sh)
124
+ runtime_entitlements="$APP_BUNDLE/Contents/Resources/runtime.entitlements"
125
+ cp OSARAInstaller.entitlements "$runtime_entitlements"
126
+
127
+ # Deep sign all components in the app bundle with entitlements
128
+ echo "=== Deep signing app bundle with entitlements ==="
129
+ find $APP_BUNDLE -type f \( -name "*.dylib" -o -name "*.so" -o -name "*.framework" \) -exec codesign --force --options runtime --entitlements OSARAInstaller.entitlements --sign "$IDENTITY" {} \; || echo "No additional libraries found to sign"
130
+
131
+ # Sign the main executable with timestamp and entitlements
132
+ codesign --force --options runtime --timestamp --entitlements OSARAInstaller.entitlements --sign "$IDENTITY" "$APP_BUNDLE/Contents/MacOS/applet"
133
+
134
+ # Sign the app bundle with timestamp and entitlements
135
+ codesign --force --options runtime --timestamp --entitlements OSARAInstaller.entitlements --sign "$IDENTITY" $APP_BUNDLE
136
+
137
+ # Verify signing with detailed output
138
+ echo "=== Verifying code signature ==="
139
+ codesign --verify --verbose=4 $APP_BUNDLE
140
+ codesign --display --verbose=4 $APP_BUNDLE
141
+
142
+ # Pre-flight validation using spctl
143
+ echo "=== Pre-flight validation with spctl ==="
144
+ spctl --assess --verbose=4 --type execute $APP_BUNDLE || echo "spctl assessment failed - this is expected before notarization"
145
+
146
+ # Validate bundle structure
147
+ echo "=== Validating bundle structure ==="
148
+ if [[ ! -f "$APP_BUNDLE/Contents/Info.plist" ]]; then
149
+ echo "ERROR: Missing Info.plist"
150
+ exit 1
151
+ fi
152
+ if [[ ! -f "$APP_BUNDLE/Contents/MacOS/applet" ]]; then
153
+ echo "ERROR: Missing main executable"
154
+ exit 1
155
+ fi
156
+ echo "Bundle structure validation passed"
157
+
158
+ # Create zip for notarization (just the app bundle)
159
+ zip -r "osara_temp.zip" $APP_BUNDLE
160
+
161
+ # Submit for notarization
162
+ echo "=== Submit for notarization ==="
163
+
164
+ # Submit without verbose to get clean JSON output
165
+ if xcrun notarytool submit osara_temp.zip \
166
+ --apple-id "$APPLE_ID" \
167
+ --password "$APPLE_ID_PASSWORD" \
168
+ --team-id "$APPLE_TEAM_ID" \
169
+ --wait \
170
+ --output-format json > notarization_output.json 2>&1; then
171
+
172
+ echo "=== Notarization submission completed ==="
173
+ cat notarization_output.json
174
+
175
+ # Check if notarization was successful
176
+ if command -v jq >/dev/null 2>&1; then
177
+ STATUS=$(jq -r '.status // "Unknown"' notarization_output.json)
178
+ echo "Notarization status: $STATUS"
179
+
180
+ if [[ "$STATUS" == "Accepted" ]]; then
181
+ echo "✅ Notarization successful!"
182
+ else
183
+ echo "❌ Notarization failed with status: $STATUS"
184
+
185
+ # Try to get detailed log
186
+ SUBMISSION_ID=$(jq -r '.id // empty' notarization_output.json)
187
+ if [[ -n "$SUBMISSION_ID" ]]; then
188
+ echo "=== Fetching detailed notarization log for submission $SUBMISSION_ID ==="
189
+ if xcrun notarytool log "$SUBMISSION_ID" \
190
+ --apple-id "$APPLE_ID" \
191
+ --password "$APPLE_ID_PASSWORD" \
192
+ --team-id "$APPLE_TEAM_ID" > notarization_log.txt 2>&1; then
193
+ echo "=== Notarization Log ==="
194
+ cat notarization_log.txt
195
+ else
196
+ echo "Failed to fetch notarization log"
197
+ fi
198
+ fi
199
+ exit 1
200
+ fi
201
+ else
202
+ echo "jq not available - cannot parse notarization response"
203
+ exit 1
204
+ fi
205
+ else
206
+ echo "❌ Notarization submission failed"
207
+ cat notarization_output.json || echo "No output file generated"
208
+ exit 1
209
+ fi
210
+
211
+ # Staple notarization to app
212
+ echo "=== Stapling notarization ticket ==="
213
+ if xcrun stapler staple $APP_BUNDLE; then
214
+ echo "✅ Stapling successful"
215
+ else
216
+ echo "❌ Stapling failed - but continuing as this might be a timing issue"
217
+ # Don't exit here as stapling can sometimes fail due to timing
218
+ fi
219
+
220
+ # Verify stapling
221
+ echo "=== Verifying stapled notarization ==="
222
+ if xcrun stapler validate $APP_BUNDLE; then
223
+ echo "✅ Stapling validation successful"
224
+ else
225
+ echo "⚠️ Stapling validation failed"
226
+ fi
227
+
228
+ # Final validation with spctl
229
+ echo "=== Final validation with spctl ==="
230
+ if spctl --assess --verbose=4 --type execute $APP_BUNDLE; then
231
+ echo "✅ Final spctl validation passed"
232
+ else
233
+ echo "⚠️ Final spctl validation failed"
234
+ fi
235
+
236
+ # Create final signed and notarized zip with app bundle and license
237
+ rm -f ../osara_${{ env.version }}.zip
238
+ zip -r ../osara_${{ env.version }}.zip $APP_BUNDLE
239
+ cd ../..
240
+
241
+ # Cleanup
242
+ rm installer/mac/osara_temp.zip certificate.p12
243
+ security delete-keychain build.keychain
244
+
245
+ echo "Mac app signed and notarized successfully!"
84
246
# We only need to upload the pot on one OS. We arbitrarily pick Windows.
85
247
- name : pot
86
248
if : ${{ github.event_name == 'push' && matrix.os == 'windows-latest' }}
0 commit comments