@@ -266,6 +266,75 @@ jobs:
266266 with :
267267 astrbot_version : ${{ steps.desktop_version.outputs.normalized }}
268268
269+ - name : Import Apple Developer Certificate
270+ id : import_apple_certificate
271+ env :
272+ APPLE_CERTIFICATE : ${{ secrets.APPLE_CERTIFICATE }}
273+ APPLE_CERTIFICATE_PASSWORD : ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
274+ KEYCHAIN_PASSWORD : ${{ secrets.KEYCHAIN_PASSWORD }}
275+ shell : bash
276+ run : |
277+ set -euo pipefail
278+ if [ -z "${APPLE_CERTIFICATE:-}" ]; then
279+ echo "APPLE_CERTIFICATE is not configured; skipping certificate import."
280+ printf 'signing_identity=\n' >> "$GITHUB_OUTPUT"
281+ exit 0
282+ fi
283+ CERT_PATH="$RUNNER_TEMP/certificate.p12"
284+ KEYCHAIN_PATH="$RUNNER_TEMP/build.keychain"
285+
286+ echo "$APPLE_CERTIFICATE" | base64 --decode > "$CERT_PATH"
287+ security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
288+ security default-keychain -s "$KEYCHAIN_PATH"
289+ security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH"
290+ security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
291+ security import "$CERT_PATH" -P "$APPLE_CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k "$KEYCHAIN_PATH"
292+ security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
293+ rm -f "$CERT_PATH"
294+
295+ signing_identities=()
296+ while IFS= read -r identity; do
297+ signing_identities+=("$identity")
298+ done < <(security find-identity -v -p codesigning "$KEYCHAIN_PATH" | grep "Developer ID Application" || true)
299+ if [ "${#signing_identities[@]}" -eq 0 ]; then
300+ echo "::error::No Developer ID Application identity found in the imported keychain." >&2
301+ security find-identity -v -p codesigning "$KEYCHAIN_PATH" || true
302+ exit 1
303+ fi
304+ if [ "${#signing_identities[@]}" -ne 1 ]; then
305+ echo "::error::Expected exactly one Developer ID Application identity, found ${#signing_identities[@]}." >&2
306+ printf '%s\n' "${signing_identities[@]}" >&2
307+ exit 1
308+ fi
309+ CERT_ID=$(printf '%s\n' "${signing_identities[0]}" | awk -F'"' '{print $2}')
310+ if [ -z "$CERT_ID" ]; then
311+ echo "::error::Failed to parse the imported Developer ID Application identity." >&2
312+ exit 1
313+ fi
314+ printf 'APPLE_SIGNING_IDENTITY=%s\n' "$CERT_ID" >> "$GITHUB_ENV"
315+ printf 'signing_identity=%s\n' "$CERT_ID" >> "$GITHUB_OUTPUT"
316+ echo "Imported signing identity: $CERT_ID"
317+
318+ - name : Pre-sign backend resources (macOS)
319+ if : ${{ steps.import_apple_certificate.outputs.signing_identity != '' }}
320+ env :
321+ ASTRBOT_SOURCE_GIT_URL : ${{ needs.resolve_build_context.outputs.source_git_url }}
322+ ASTRBOT_SOURCE_GIT_REF : ${{ needs.resolve_build_context.outputs.source_git_ref }}
323+ ASTRBOT_DESKTOP_VERSION : ${{ steps.desktop_version.outputs.prefixed }}
324+ ASTRBOT_DESKTOP_UPDATER_PUBLIC_KEY : ${{ env.ASTRBOT_DESKTOP_UPDATER_PUBLIC_KEY }}
325+ GITHUB_TOKEN : ${{ github.token }}
326+ GH_TOKEN : ${{ github.token }}
327+ shell : bash
328+ run : |
329+ set -euo pipefail
330+ pnpm run prepare:resources
331+ if [ ! -d "resources/backend" ]; then
332+ echo "::error::resources/backend not found after prepare:resources." >&2
333+ exit 1
334+ fi
335+ echo "Pre-signing Mach-O binaries in resources/backend..."
336+ bash scripts/ci/codesign-macos-nested.sh "resources/backend" "src-tauri/entitlements.plist"
337+
269338 - name : Resolve macOS app bundle name
270339 id : resolve_macos_app_bundle
271340 env :
@@ -295,6 +364,11 @@ jobs:
295364 ASTRBOT_DESKTOP_CRYPTOGRAPHY_FALLBACK_VERSIONS : ${{ vars.ASTRBOT_DESKTOP_CRYPTOGRAPHY_FALLBACK_VERSIONS || '' }}
296365 ASTRBOT_MACOS_BUILD_MAX_ATTEMPTS : ${{ vars.ASTRBOT_MACOS_BUILD_MAX_ATTEMPTS || '3' }}
297366 ASTRBOT_MACOS_BUILD_RETRY_SLEEP_SECONDS : ${{ vars.ASTRBOT_MACOS_BUILD_RETRY_SLEEP_SECONDS || '8' }}
367+ APPLE_CERTIFICATE : ${{ secrets.APPLE_CERTIFICATE }}
368+ APPLE_CERTIFICATE_PASSWORD : ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
369+ APPLE_ID : ${{ secrets.APPLE_ID }}
370+ APPLE_PASSWORD : ${{ secrets.APPLE_PASSWORD }}
371+ APPLE_TEAM_ID : ${{ secrets.APPLE_TEAM_ID }}
298372 GITHUB_TOKEN : ${{ github.token }}
299373 GH_TOKEN : ${{ github.token }}
300374 shell : bash
@@ -306,6 +380,8 @@ jobs:
306380
307381 max_attempts="${ASTRBOT_MACOS_BUILD_MAX_ATTEMPTS}"
308382 retry_sleep_seconds="${ASTRBOT_MACOS_BUILD_RETRY_SLEEP_SECONDS}"
383+ # Resources are already prepared and pre-signed in the previous step.
384+ tauri_config_override='{"build":{"beforeBuildCommand":""}}'
309385 # Retry only for known transient cargo/crates network failures.
310386 # Spurious retry hints emitted by cargo.
311387 transient_retry_spurious='spurious network error|network failure seems to have happened'
@@ -330,7 +406,7 @@ jobs:
330406
331407 for attempt in $(seq 1 "${max_attempts}"); do
332408 build_log="$(mktemp -t tauri-macos-build.XXXXXX.log)"
333- if cargo tauri build --verbose --target ${{ matrix.target }} --bundles app 2>&1 | tee "${build_log}"; then
409+ if cargo tauri build --verbose --target ${{ matrix.target }} --bundles app --config "${tauri_config_override}" 2>&1 | tee "${build_log}"; then
334410 rm -f "${build_log}" || true
335411 break
336412 fi
0 commit comments