|
62 | 62 | if: runner.os == 'Windows' |
63 | 63 | run: cp target/${{ matrix.target }}/release/ralph.exe ${{ matrix.artifact }}.exe |
64 | 64 |
|
| 65 | + - name: Sign and notarize (macOS) |
| 66 | + if: runner.os == 'macOS' |
| 67 | + env: |
| 68 | + APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }} |
| 69 | + APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} |
| 70 | + APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }} |
| 71 | + APPLE_API_KEY: ${{ secrets.APPLE_API_KEY }} |
| 72 | + APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }} |
| 73 | + APPLE_API_KEY_BASE64: ${{ secrets.APPLE_API_KEY_BASE64 }} |
| 74 | + ARTIFACT: ${{ matrix.artifact }} |
| 75 | + run: | |
| 76 | + set -euo pipefail |
| 77 | +
|
| 78 | + # Create a temporary keychain and import the signing certificate |
| 79 | + KEYCHAIN_PATH="$RUNNER_TEMP/signing.keychain-db" |
| 80 | + KEYCHAIN_PASSWORD=$(uuidgen) |
| 81 | + security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" |
| 82 | + security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH" |
| 83 | + security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" |
| 84 | +
|
| 85 | + CERT_PATH="$RUNNER_TEMP/cert.p12" |
| 86 | + echo "$APPLE_CERTIFICATE" | base64 --decode > "$CERT_PATH" |
| 87 | + security import "$CERT_PATH" -k "$KEYCHAIN_PATH" -P "$APPLE_CERTIFICATE_PASSWORD" -T /usr/bin/codesign |
| 88 | + security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" |
| 89 | + security list-keychains -d user -s "$KEYCHAIN_PATH" $(security list-keychains -d user | tr -d '"') |
| 90 | +
|
| 91 | + # Sign the binary with hardened runtime and a secure timestamp |
| 92 | + codesign --force --options runtime --timestamp \ |
| 93 | + --sign "$APPLE_SIGNING_IDENTITY" "$ARTIFACT" |
| 94 | + codesign --verify --verbose "$ARTIFACT" |
| 95 | +
|
| 96 | + # Notarize: zip, submit, wait. Bare binaries can't be stapled, so |
| 97 | + # Gatekeeper does an online check on first run instead. |
| 98 | + API_KEY_PATH="$RUNNER_TEMP/AuthKey.p8" |
| 99 | + echo "$APPLE_API_KEY_BASE64" | base64 --decode > "$API_KEY_PATH" |
| 100 | + ZIP_PATH="$RUNNER_TEMP/$ARTIFACT.zip" |
| 101 | + /usr/bin/ditto -c -k --keepParent "$ARTIFACT" "$ZIP_PATH" |
| 102 | + xcrun notarytool submit "$ZIP_PATH" \ |
| 103 | + --key "$API_KEY_PATH" \ |
| 104 | + --key-id "$APPLE_API_KEY" \ |
| 105 | + --issuer "$APPLE_API_ISSUER" \ |
| 106 | + --wait |
| 107 | +
|
| 108 | + # Cleanup |
| 109 | + security delete-keychain "$KEYCHAIN_PATH" |
| 110 | + rm -f "$CERT_PATH" "$API_KEY_PATH" "$ZIP_PATH" |
| 111 | +
|
65 | 112 | - name: Upload artifact |
66 | 113 | uses: actions/upload-artifact@v4 |
67 | 114 | with: |
@@ -106,9 +153,25 @@ jobs: |
106 | 153 | sudo apt-get update |
107 | 154 | sudo apt-get install -y libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf |
108 | 155 |
|
| 156 | + - name: Write App Store Connect API key (macOS) |
| 157 | + if: runner.os == 'macOS' |
| 158 | + env: |
| 159 | + APPLE_API_KEY_BASE64: ${{ secrets.APPLE_API_KEY_BASE64 }} |
| 160 | + run: | |
| 161 | + mkdir -p ~/private_keys |
| 162 | + echo "$APPLE_API_KEY_BASE64" | base64 --decode > ~/private_keys/AuthKey.p8 |
| 163 | + echo "APPLE_API_KEY_PATH=$HOME/private_keys/AuthKey.p8" >> $GITHUB_ENV |
| 164 | +
|
109 | 165 | - name: Build Tauri app |
110 | 166 | id: tauri |
111 | 167 | uses: tauri-apps/tauri-action@v0 |
| 168 | + env: |
| 169 | + APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }} |
| 170 | + APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} |
| 171 | + APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }} |
| 172 | + APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }} |
| 173 | + APPLE_API_KEY: ${{ secrets.APPLE_API_KEY }} |
| 174 | + KEYCHAIN_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} |
112 | 175 | with: |
113 | 176 | args: --target ${{ matrix.target }} |
114 | 177 | includeUpdaterJson: false |
@@ -144,9 +207,8 @@ jobs: |
144 | 207 | name: v${{ steps.version.outputs.version }} |
145 | 208 | generate_release_notes: true |
146 | 209 | body: | |
147 | | - ## macOS CLI notice |
148 | | - macOS may block the CLI binary with a Gatekeeper warning. To fix, run: |
149 | | - ``` |
150 | | - xattr -d com.apple.quarantine <path-to-binary> |
151 | | - ``` |
| 210 | + ## macOS notes |
| 211 | + The desktop app (`.dmg`) and CLI binaries are signed and notarized |
| 212 | + with a Developer ID. macOS will check Apple's notary service |
| 213 | + online on first launch — no manual `xattr` workaround needed. |
152 | 214 | files: artifacts/**/* |
0 commit comments