diff --git a/.github/actions/notarize-macos-app/action.yml b/.github/actions/notarize-macos-app/action.yml new file mode 100644 index 000000000..b1e83d878 --- /dev/null +++ b/.github/actions/notarize-macos-app/action.yml @@ -0,0 +1,109 @@ +name: 'Notarize macOS App' +description: 'Complete macOS app code signing and notarization with certificate setup' +inputs: + app_path: + description: 'The app bundle zip file path' + required: true + p12_base64: + description: 'Base64 encoded P12 certificate file' + required: true + p12_password: + description: 'Password for the P12 certificate' + required: true + apple_id: + description: 'Apple ID for notarization' + required: true + apple_id_password: + description: 'App-specific password for Apple ID' + required: true + team_id: + description: 'Apple Developer Team ID' + required: true + certificate_identity: + description: 'Code signing certificate identity' + required: true + +runs: + using: 'composite' + steps: + - name: Check Prerequisites + shell: bash + run: | + echo "Checking if Apple Developer credentials are available..." + + if [ -z "${{ inputs.apple_id }}" ]; then + echo "No Apple ID provided - skipping code signing and notarization." + echo "The app build will continue without notarization." + echo "SKIP_NOTARIZATION=true" >> $GITHUB_ENV + else + echo "Apple ID found - proceeding with code signing and notarization." + echo "SKIP_NOTARIZATION=false" >> $GITHUB_ENV + fi + + - name: Setup Code Signing Certificate + if: env.SKIP_NOTARIZATION != 'true' + shell: bash + run: | + echo "Create temporary keychain" + security create-keychain -p temp_password build.keychain + security default-keychain -s build.keychain + security unlock-keychain -p temp_password build.keychain + + echo "Import certificate" + echo "${{ inputs.p12_base64 }}" | base64 --decode > certificate.p12 + security import certificate.p12 -k build.keychain -P "${{ inputs.p12_password }}" -A + rm certificate.p12 + + echo "Set keychain settings" + security set-key-partition-list -S apple-tool:,apple: -s -k temp_password build.keychain + + echo "Available signing identities:" + security find-identity -v -p codesigning build.keychain + + - name: Code Sign App + if: env.SKIP_NOTARIZATION != 'true' + shell: bash + run: | + echo "Extracting and debugging app bundle..." + ditto -x -k ${{ inputs.app_path }} ./app_notarization + + echo "Code signing app..." + codesign --force --deep --options runtime --sign "${{ inputs.certificate_identity }}" "./app_notarization/Pencil2D.app" + + echo "Verifying code signature" + codesign --verify --verbose=4 "./app_notarization/Pencil2D.app" + echo "Code signature verification successful!" + + ditto -c -k --rsrc --keepParent "./app_notarization/Pencil2D.app" "./app_notarization.zip" + + - name: Submit for Notarization + if: env.SKIP_NOTARIZATION != 'true' + shell: bash + run: | + echo "Submitting to Apple for notarization..." + xcrun notarytool submit "./app_notarization.zip" \ + --apple-id "${{ inputs.apple_id }}" \ + --password "${{ inputs.apple_id_password }}" \ + --team-id "${{ inputs.team_id }}" \ + --wait \ + --timeout 15m + + - name: Staple & Verify Notarization + if: env.SKIP_NOTARIZATION != 'true' + shell: bash + run: | + echo "Stapling notarization ticket to app..." + xcrun stapler staple "./app_notarization/Pencil2D.app" + + echo "Verifying notarization..." + spctl -a -v "./app_notarization/Pencil2D.app" + echo "App is properly notarized and ready for distribution!" + + - name: Finalize + if: env.SKIP_NOTARIZATION != 'true' + shell: bash + run: | + echo "Replacing the original app bundle with notarized app bundle" + rm -rf "${{ inputs.app_path }}" + ditto -c -k --rsrc --keepParent "./app_notarization/Pencil2D.app" "${{ inputs.app_path }}" + echo "Notarized app bundle is now at ${{ inputs.app_path }}" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 00f6f2ba8..452b96da8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -72,6 +72,7 @@ jobs: steps: - name: Check out repository uses: actions/checkout@v3 + - name: Set up container (Linux) if: runner.os == 'Linux' # XXX: --privileged is sort of a brute-force solution to get FUSE @@ -116,6 +117,18 @@ jobs: arch: ${{matrix.arch}} qt: ${{matrix.qt}} + - name: Code Sign and Notarize App + if: runner.os == 'macOS' + uses: ./.github/actions/notarize-macos-app + with: + app_path: "build/${{steps.package.outputs.output-basename}}.zip" + p12_base64: ${{ secrets.P12_BASE64 }} + p12_password: ${{ secrets.P12_PASSWORD }} + apple_id: ${{ secrets.APPLE_ID }} + apple_id_password: ${{ secrets.APPLE_ID_PASSWORD }} + team_id: ${{ secrets.APPLE_TEAM_ID }} + certificate_identity: ${{ secrets.CODESIGN_CERT_IDENTITY }} + - name: Upload package if: runner.os != 'Linux' || matrix.qt == 5 uses: actions/upload-artifact@v4