@@ -156,6 +156,30 @@ jobs:
156156 - name : Install create-dmg
157157 run : brew install create-dmg
158158
159+ - name : Import code signing certificate
160+ env :
161+ MACOS_CERT_P12 : ${{ secrets.MACOS_CERT_P12 }}
162+ MACOS_CERT_PASSWORD : ${{ secrets.MACOS_CERT_PASSWORD }}
163+ MACOS_KEYCHAIN_PASSWORD : ${{ secrets.MACOS_KEYCHAIN_PASSWORD }}
164+ run : |
165+ CERT_PATH="$RUNNER_TEMP/cert.p12"
166+ KEYCHAIN_PATH="$RUNNER_TEMP/app-signing.keychain-db"
167+
168+ echo "$MACOS_CERT_P12" | base64 --decode > "$CERT_PATH"
169+
170+ # Create a temporary keychain and import the Developer ID cert
171+ security create-keychain -p "$MACOS_KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
172+ security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH"
173+ security unlock-keychain -p "$MACOS_KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
174+ security import "$CERT_PATH" -P "$MACOS_CERT_PASSWORD" -A -t cert -f pkcs12 -k "$KEYCHAIN_PATH"
175+ security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$MACOS_KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
176+
177+ # Make the temp keychain searchable so codesign can find the identity
178+ security list-keychain -d user -s "$KEYCHAIN_PATH" $(security list-keychains -d user | sed s/\"//g)
179+
180+ security find-identity -v -p codesigning "$KEYCHAIN_PATH"
181+ rm -f "$CERT_PATH"
182+
159183 - name : Get version
160184 id : version
161185 run : echo "VERSION=$(grep '^version' Cargo.toml | head -1 | sed 's/.*\"\(.*\)\".*/\1/')" >> $GITHUB_OUTPUT
@@ -170,6 +194,10 @@ jobs:
170194 BUNDLE_ID : ${{ needs.check-tag.outputs.bundle_id }}
171195 DMG_VOLNAME : ${{ needs.check-tag.outputs.dmg_volname }}
172196 SUFFIX : ${{ needs.check-tag.outputs.suffix }}
197+ MACOS_SIGN_IDENTITY : ${{ secrets.MACOS_SIGN_IDENTITY }}
198+ AC_API_KEY_ID : ${{ secrets.AC_API_KEY_ID }}
199+ AC_API_ISSUER_ID : ${{ secrets.AC_API_ISSUER_ID }}
200+ AC_API_KEY_P8 : ${{ secrets.AC_API_KEY_P8 }}
173201 run : |
174202 ASSET_NAME="ultralog-macos-${{ matrix.arch }}${SUFFIX}"
175203 mkdir -p output
@@ -253,8 +281,26 @@ jobs:
253281 ICNS_PATH="$APP_DIR/Contents/Resources/AppIcon.icns"
254282 fi
255283
256- # Ad-hoc sign the app bundle
257- codesign --force --deep --sign - "$APP_DIR"
284+ # Decode the App Store Connect API key for notarytool
285+ API_KEY_PATH="$RUNNER_TEMP/AuthKey.p8"
286+ echo "$AC_API_KEY_P8" | base64 --decode > "$API_KEY_PATH"
287+
288+ # Sign with Developer ID + hardened runtime (inner binary first, then bundle)
289+ codesign --force --options runtime --timestamp \
290+ --sign "$MACOS_SIGN_IDENTITY" "$APP_DIR/Contents/MacOS/ultralog"
291+ codesign --force --options runtime --timestamp \
292+ --sign "$MACOS_SIGN_IDENTITY" "$APP_DIR"
293+ codesign --verify --strict --verbose=2 "$APP_DIR"
294+
295+ # Notarize the app, then staple the ticket so it opens offline
296+ ditto -c -k --keepParent "$APP_DIR" "$RUNNER_TEMP/app.zip"
297+ xcrun notarytool submit "$RUNNER_TEMP/app.zip" \
298+ --key "$API_KEY_PATH" \
299+ --key-id "$AC_API_KEY_ID" \
300+ --issuer "$AC_API_ISSUER_ID" \
301+ --wait
302+ xcrun stapler staple "$APP_DIR"
303+ rm -f "$RUNNER_TEMP/app.zip"
258304
259305 # Create DMG with volume icon if available
260306 if [ -n "$ICNS_PATH" ]; then
@@ -284,6 +330,17 @@ jobs:
284330 hdiutil create -volname "${DMG_VOLNAME}" -srcfolder "$APP_DIR" -ov -format UDZO "output/${ASSET_NAME}.dmg"
285331 fi
286332
333+ # Sign, notarize, and staple the DMG so the download itself is trusted
334+ codesign --force --timestamp --sign "$MACOS_SIGN_IDENTITY" "output/${ASSET_NAME}.dmg"
335+ xcrun notarytool submit "output/${ASSET_NAME}.dmg" \
336+ --key "$API_KEY_PATH" \
337+ --key-id "$AC_API_KEY_ID" \
338+ --issuer "$AC_API_ISSUER_ID" \
339+ --wait
340+ xcrun stapler staple "output/${ASSET_NAME}.dmg"
341+ xcrun stapler validate "output/${ASSET_NAME}.dmg"
342+ rm -f "$API_KEY_PATH"
343+
287344 - name : Upload artifact
288345 uses : actions/upload-artifact@v4
289346 with :
@@ -362,7 +419,7 @@ jobs:
362419 - **Intel Mac**: `ultralog-macos-intel-beta.dmg`
363420 - **Apple Silicon (M1/M2/M3/M4)**: `ultralog-macos-arm64-beta.dmg`
364421 2. Open the DMG and drag UltraLog to your Applications folder
365- 3. On first run, right-click the app and select "Open" to bypass Gatekeeper
422+ 3. Launch UltraLog from Applications. Beta builds are signed and notarized by Apple, so they open without a Gatekeeper warning.
366423
367424 ### Windows
368425 1. Download `ultralog-windows-beta.zip`
0 commit comments