ci: macOS 签名公证

This commit is contained in:
Chenx Dust
2026-02-10 16:58:31 +08:00
parent 22df9db903
commit 2afbf54bd9
3 changed files with 132 additions and 0 deletions

View File

@@ -158,6 +158,30 @@ jobs:
run: |
./scripts/deploy-macos.sh "${{ env.TARGET_NAME }}" "build" "amd64"
- name: Import macOS signing certificate
if: (github.event_name == 'release' || github.event_name == 'workflow_dispatch') && secrets.MACOS_CERT_IDENTITY != '' && secrets.MACOS_CERT_P12 != '' && secrets.MACOS_CERT_PASSWORD != ''
env:
MACOS_CERT_P12: ${{ secrets.MACOS_CERT_P12 }}
MACOS_CERT_PASSWORD: ${{ secrets.MACOS_CERT_PASSWORD }}
KEYCHAIN_PASSWORD: ${{ github.run_id }}-${{ github.run_attempt }}-keychain
run: |
CERTIFICATE_PATH="$RUNNER_TEMP/macos_signing_certificate.p12"
KEYCHAIN_PATH="$RUNNER_TEMP/macos-signing.keychain-db"
echo "$MACOS_CERT_P12" | base64 --decode > "$CERTIFICATE_PATH" || echo "$MACOS_CERT_P12" | base64 -D > "$CERTIFICATE_PATH"
security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH"
security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
security import "$CERTIFICATE_PATH" -P "$MACOS_CERT_PASSWORD" -A -t cert -f pkcs12 -k "$KEYCHAIN_PATH"
security set-key-partition-list -S apple-tool:,apple: -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
security list-keychains -d user -s "$KEYCHAIN_PATH"
- name: Sign app bundle
if: (github.event_name == 'release' || github.event_name == 'workflow_dispatch') && secrets.MACOS_CERT_IDENTITY != '' && secrets.MACOS_CERT_P12 != '' && secrets.MACOS_CERT_PASSWORD != ''
env:
CODESIGN_IDENTITY: ${{ secrets.MACOS_CERT_IDENTITY }}
run: |
./scripts/macos-sign-app.sh "./${{ env.TARGET_NAME }}.app"
- name: Package dmg file
if: github.event_name == 'release' || github.event_name == 'workflow_dispatch'
run: |
@@ -172,6 +196,15 @@ jobs:
--filesystem APFS \
${{ env.ARCHIVE_NAME }}.dmg dmg-build
- name: Notarize and staple dmg
if: (github.event_name == 'release' || github.event_name == 'workflow_dispatch') && secrets.MACOS_CERT_IDENTITY != '' && secrets.MACOS_CERT_P12 != '' && secrets.MACOS_CERT_PASSWORD != '' && secrets.APPLE_ID != '' && secrets.APPLE_APP_SPECIFIC_PASSWORD != '' && secrets.APPLE_TEAM_ID != ''
env:
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
run: |
./scripts/macos-notarize-dmg.sh "${{ env.ARCHIVE_NAME }}.dmg"
- name: Upload artifact (dmg)
if: github.event_name == 'release' || github.event_name == 'workflow_dispatch'
uses: actions/upload-artifact@v4
@@ -230,6 +263,30 @@ jobs:
run: |
./scripts/deploy-macos.sh "${{ env.TARGET_NAME }}" "build" "arm64"
- name: Import macOS signing certificate
if: (github.event_name == 'release' || github.event_name == 'workflow_dispatch') && secrets.MACOS_CERT_IDENTITY != '' && secrets.MACOS_CERT_P12 != '' && secrets.MACOS_CERT_PASSWORD != ''
env:
MACOS_CERT_P12: ${{ secrets.MACOS_CERT_P12 }}
MACOS_CERT_PASSWORD: ${{ secrets.MACOS_CERT_PASSWORD }}
KEYCHAIN_PASSWORD: ${{ github.run_id }}-${{ github.run_attempt }}-keychain
run: |
CERTIFICATE_PATH="$RUNNER_TEMP/macos_signing_certificate.p12"
KEYCHAIN_PATH="$RUNNER_TEMP/macos-signing.keychain-db"
echo "$MACOS_CERT_P12" | base64 --decode > "$CERTIFICATE_PATH" || echo "$MACOS_CERT_P12" | base64 -D > "$CERTIFICATE_PATH"
security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH"
security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
security import "$CERTIFICATE_PATH" -P "$MACOS_CERT_PASSWORD" -A -t cert -f pkcs12 -k "$KEYCHAIN_PATH"
security set-key-partition-list -S apple-tool:,apple: -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
security list-keychains -d user -s "$KEYCHAIN_PATH"
- name: Sign app bundle
if: (github.event_name == 'release' || github.event_name == 'workflow_dispatch') && secrets.MACOS_CERT_IDENTITY != '' && secrets.MACOS_CERT_P12 != '' && secrets.MACOS_CERT_PASSWORD != ''
env:
CODESIGN_IDENTITY: ${{ secrets.MACOS_CERT_IDENTITY }}
run: |
./scripts/macos-sign-app.sh "./${{ env.TARGET_NAME }}.app"
- name: Package dmg file
if: github.event_name == 'release' || github.event_name == 'workflow_dispatch'
run: |
@@ -244,6 +301,15 @@ jobs:
--filesystem APFS \
${{ env.ARCHIVE_NAME }}.dmg dmg-build
- name: Notarize and staple dmg
if: (github.event_name == 'release' || github.event_name == 'workflow_dispatch') && secrets.MACOS_CERT_IDENTITY != '' && secrets.MACOS_CERT_P12 != '' && secrets.MACOS_CERT_PASSWORD != '' && secrets.APPLE_ID != '' && secrets.APPLE_APP_SPECIFIC_PASSWORD != '' && secrets.APPLE_TEAM_ID != ''
env:
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
run: |
./scripts/macos-notarize-dmg.sh "${{ env.ARCHIVE_NAME }}.dmg"
- name: Upload artifact (dmg)
if: github.event_name == 'release' || github.event_name == 'workflow_dispatch'
uses: actions/upload-artifact@v4

24
scripts/macos-notarize-dmg.sh Executable file
View File

@@ -0,0 +1,24 @@
#!/bin/bash
# Usage: ./scripts/macos-notarize-dmg.sh "<dmg_path>"
set -euo pipefail
DMG_PATH="${1:-}"
if [[ -z "${APPLE_ID:-}" || -z "${APPLE_APP_SPECIFIC_PASSWORD:-}" || -z "${APPLE_TEAM_ID:-}" ]]; then
echo "APPLE_ID, APPLE_APP_SPECIFIC_PASSWORD and APPLE_TEAM_ID are required"
exit 1
fi
if [[ -z "$DMG_PATH" || ! -f "$DMG_PATH" ]]; then
echo "DMG not found: $DMG_PATH"
exit 1
fi
xcrun notarytool submit "$DMG_PATH" \
--apple-id "$APPLE_ID" \
--password "$APPLE_APP_SPECIFIC_PASSWORD" \
--team-id "$APPLE_TEAM_ID" \
--wait
xcrun stapler staple "$DMG_PATH"

42
scripts/macos-sign-app.sh Executable file
View File

@@ -0,0 +1,42 @@
#!/bin/bash
# Usage: ./scripts/macos-sign-app.sh "<app_path>"
set -euo pipefail
APP_PATH="${1:-}"
FRAMEWORKS_PATH="$APP_PATH/Contents/Frameworks"
if [[ -z "${CODESIGN_IDENTITY:-}" ]]; then
echo "CODESIGN_IDENTITY is required"
exit 1
fi
if [[ -z "$APP_PATH" || ! -d "$APP_PATH" ]]; then
echo "App not found: $APP_PATH"
exit 1
fi
# Align with resource/macos-fix.sh order:
# sign framework versions first, then helper apps, then main app.
if [[ -d "$FRAMEWORKS_PATH" ]]; then
for framework in "$FRAMEWORKS_PATH"/*.framework; do
[[ -d "$framework" ]] || continue
if [[ -d "$framework/Versions" ]]; then
for version in "$framework/Versions"/*; do
if [[ -d "$version" && ! -L "$version" ]]; then
codesign --verbose --force --timestamp --options runtime --sign "$CODESIGN_IDENTITY" "$version"
fi
done
else
codesign --verbose --force --timestamp --options runtime --sign "$CODESIGN_IDENTITY" "$framework"
fi
done
for helper_app in "$FRAMEWORKS_PATH"/*.app; do
[[ -d "$helper_app" ]] || continue
codesign --verbose --force --timestamp --options runtime --sign "$CODESIGN_IDENTITY" "$helper_app"
done
fi
codesign --verbose --force --timestamp --options runtime --deep --sign "$CODESIGN_IDENTITY" "$APP_PATH"
codesign --verify --deep --strict --verbose=2 "$APP_PATH"