From c0d5e2acd8a1d877b008f01440a9153138e5175e Mon Sep 17 00:00:00 2001 From: ionite34 Date: Fri, 29 Dec 2023 11:17:27 +0800 Subject: [PATCH] Add macos sign notarize release CIs --- .github/workflows/release.yml | 109 +++++++++++++++++++++++++++++++++- Build/build_macos_app.sh | 26 ++++++++ Build/codesign_macos.sh | 21 +++++++ Build/notarize_macos.sh | 32 ++++++++++ 4 files changed, 187 insertions(+), 1 deletion(-) create mode 100755 Build/build_macos_app.sh create mode 100644 Build/codesign_macos.sh create mode 100644 Build/notarize_macos.sh diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 88b5eae3..d68aa480 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -171,7 +171,114 @@ jobs: with: name: StabilityMatrix-${{ env.platform-id }} path: ./out/${{ env.out-name }} - + + release-macos: + name: Release (macos-arm64) + env: + platform-id: osx-arm64 + app-name: "Stability Matrix.app" + out-name: "Stability Matrix.dmg" + runs-on: macos-13 + steps: + - uses: actions/checkout@v3 + + - uses: olegtarasov/get-tag@v2.1.2 + if: github.event_name == 'release' + id: tag_name + with: + tagRegex: "v(.*)" + + - name: Set Version from Tag + if: github.event_name == 'release' + run: | + echo "Using tag ${{ env.GIT_TAG_NAME }}" + echo "RELEASE_VERSION=${{ env.GIT_TAG_NAME }}" >> $env:GITHUB_ENV + + - name: Set Version from manual input + if: github.event_name == 'workflow_dispatch' + run: | + echo "Using version ${{ github.event.inputs.version }}" + echo "RELEASE_VERSION=${{ github.event.inputs.version }}" >> $env:GITHUB_ENV + + - name: Set up .NET 8 + uses: actions/setup-dotnet@v3 + with: + dotnet-version: '8.0.x' + + - name: Install dependencies + run: dotnet restore + + - name: .NET Msbuild (App) + env: + SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} + run: > + dotnet msbuild StabilityMatrix.Avalonia + -t:BundleApp -p:UseAppHost=true -p:SelfContained=true + -p:Configuration=Release -p:RuntimeIdentifier=${{ env.platform-id }} + -p:Version=$env:RELEASE_VERSION + -p:PublishDir=out + -p:PublishReadyToRun=true + -p:CFBundleShortVersionString=$env:RELEASE_VERSION + -p:CFBundleName="Stability Matrix" + -p:CFBundleDisplayName="Stability Matrix" + -p:CFBundleVersion=$env:RELEASE_VERSION + -p:SentryOrg=${{ secrets.SENTRY_ORG }} -p:SentryProject=${{ secrets.SENTRY_PROJECT }} + -p:SentryUploadSymbols=true -p:SentryUploadSources=true + + - name: Post Build (App) + run: > + mkdir -p signing + mv "./out/Stability Matrix.app" ./signing/${{ env.app-name }} + + - name: Codesign app bundle + env: + MACOS_CERTIFICATE: ${{ secrets.PROD_MACOS_CERTIFICATE }} + MACOS_CERTIFICATE_PWD: ${{ secrets.PROD_MACOS_CERTIFICATE_PWD }} + MACOS_CERTIFICATE_NAME: ${{ secrets.PROD_MACOS_CERTIFICATE_NAME }} + MACOS_CI_KEYCHAIN_PWD: ${{ secrets.PROD_MACOS_CI_KEYCHAIN_PWD }} + run: ./Build/codesign_macos.sh "./signing/${{ env.app-name }}" + + - name: Notarize app bundle + env: + MACOS_NOTARIZATION_APPLE_ID: ${{ secrets.PROD_MACOS_NOTARIZATION_APPLE_ID }} + MACOS_NOTARIZATION_TEAM_ID: ${{ secrets.PROD_MACOS_NOTARIZATION_TEAM_ID }} + MACOS_NOTARIZATION_PWD: ${{ secrets.PROD_MACOS_NOTARIZATION_PWD }} + run: ./Build/notarize_macos.sh "./signing/${{ env.app-name }}" + + - name: Upload Artifact (App) + uses: actions/upload-artifact@v2 + with: + name: StabilityMatrix-${{ env.platform-id }}-app + path: ./signing/${{ env.app-name }} + + - uses: actions/setup-node@v4 + with: + node-version: '20.x' + + - name: Install dependencies for dmg creation + run: > + npm install --global create-dmg + brew install graphicsmagick imagemagick + + - name: Create dmg + run: > + cd signing + create-dmg ${{ env.app-name }} --overwrite --identity ${{ secrets.PROD_MACOS_CERTIFICATE_NAME }} + # Rename to remove version number + for f in *.dmg; do mv "$f" "${{ env.out-name }}"; done + + - name: Notarize dmg + env: + MACOS_NOTARIZATION_APPLE_ID: ${{ secrets.PROD_MACOS_NOTARIZATION_APPLE_ID }} + MACOS_NOTARIZATION_TEAM_ID: ${{ secrets.PROD_MACOS_NOTARIZATION_TEAM_ID }} + MACOS_NOTARIZATION_PWD: ${{ secrets.PROD_MACOS_NOTARIZATION_PWD }} + run: ./Build/notarize_macos.sh "./signing/${{ env.out-name }}" + + - name: Upload Artifact (dmg) + uses: actions/upload-artifact@v2 + with: + name: StabilityMatrix-${{ env.platform-id }}-dmg + path: ./signing/${{ env.out-name }} publish-release: name: Publish GitHub Release diff --git a/Build/build_macos_app.sh b/Build/build_macos_app.sh new file mode 100755 index 00000000..acdfcd4b --- /dev/null +++ b/Build/build_macos_app.sh @@ -0,0 +1,26 @@ +#!/bin/sh + +while getopts v: flag +do + case "${flag}" in + v) version=${OPTARG};; + *) echo "Invalid option";; + esac +done + +dotnet \ +msbuild \ +StabilityMatrix.Avalonia \ +-t:BundleApp \ +-p:RuntimeIdentifier=osx-arm64 \ +-p:UseAppHost=true \ +-p:Configuration=Release \ +-p:CFBundleShortVersionString="$version" \ +-p:SelfContained=true \ +-p:CFBundleName="Stability Matrix" \ +-p:CFBundleDisplayName="Stability Matrix" \ +-p:CFBundleVersion="$version" \ +-p:PublishDir="$(pwd)/out/osx-arm64/bin" \ + +# Copy the app out of bin +cp -r ./out/osx-arm64/bin/Stability\ Matrix.app ./out/osx-arm64/Stability\ Matrix.app diff --git a/Build/codesign_macos.sh b/Build/codesign_macos.sh new file mode 100644 index 00000000..91698b39 --- /dev/null +++ b/Build/codesign_macos.sh @@ -0,0 +1,21 @@ +#!/bin/sh + +echo "Signing file: $1" + +# Turn our base64-encoded certificate back to a regular .p12 file + +echo "$MACOS_CERTIFICATE" | base64 --decode -o certificate.p12 + +# We need to create a new keychain, otherwise using the certificate will prompt +# with a UI dialog asking for the certificate password, which we can't +# use in a headless CI environment + +security create-keychain -p "$MACOS_CI_KEYCHAIN_PWD" build.keychain +security default-keychain -s build.keychain +security unlock-keychain -p "$MACOS_CI_KEYCHAIN_PWD" build.keychain +security import certificate.p12 -k build.keychain -P "$MACOS_CERTIFICATE_PWD" -T /usr/bin/codesign +security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$MACOS_CI_KEYCHAIN_PWD" build.keychain + +# We finally codesign our app bundle, specifying the Hardened runtime option + +/usr/bin/codesign --force -s "$MACOS_CERTIFICATE_NAME" --options runtime "$1" -v diff --git a/Build/notarize_macos.sh b/Build/notarize_macos.sh new file mode 100644 index 00000000..0b4d134a --- /dev/null +++ b/Build/notarize_macos.sh @@ -0,0 +1,32 @@ +#!/bin/sh + +echo "Notarizing file: $1" + +# Store the notarization credentials so that we can prevent a UI password dialog +# from blocking the CI + +echo "Create keychain profile" +xcrun notarytool store-credentials "notarytool-profile" \ +--apple-id "$PROD_MACOS_NOTARIZATION_APPLE_ID" \ +--team-id "$PROD_MACOS_NOTARIZATION_TEAM_ID" \ +--password "$PROD_MACOS_NOTARIZATION_PWD" + +# We can't notarize an app bundle directly, but we need to compress it as an archive. +# Therefore, we create a zip file containing our app bundle, so that we can send it to the +# notarization service + +echo "Creating temp notarization archive" +ditto -c -k --keepParent "$1" "notarization.zip" + +# Here we send the notarization request to the Apple's Notarization service, waiting for the result. +# This typically takes a few seconds inside a CI environment, but it might take more depending on the App +# characteristics. Visit the Notarization docs for more information and strategies on how to optimize it if +# you're curious + +echo "Notarize app" +xcrun notarytool submit "notarization.zip" --keychain-profile "notarytool-profile" --wait + +# Finally, we need to "attach the staple" to our executable, which will allow our app to be +# validated by macOS even when an internet connection is not available. +echo "Attach staple" +xcrun stapler staple "$1"