- Updated the notarization workflow to correctly reference the "Release macOS" workflow. - Enhanced version and run ID resolution logic to ensure accurate detection from the latest release or inputs. - Improved asset verification process on R2 with a retry mechanism to handle potential delays in asset availability. - Removed the deprecated unified release workflow, streamlining the release process for macOS and Linux. - Adjusted CDN update prerequisites to reflect the new workflow structure.
211 lines
7.9 KiB
YAML
211 lines
7.9 KiB
YAML
name: Notarize macOS
|
|
|
|
on:
|
|
workflow_run:
|
|
workflows: ["Release macOS"]
|
|
types: [completed]
|
|
workflow_dispatch:
|
|
inputs:
|
|
version:
|
|
description: "Version (auto-detected from latest release if empty)"
|
|
required: false
|
|
run_id:
|
|
description: "Release macOS workflow run ID (auto-detected if empty)"
|
|
required: false
|
|
|
|
permissions:
|
|
contents: write
|
|
actions: write
|
|
|
|
concurrency:
|
|
group: notarize-${{ github.event.workflow_run.head_branch || github.run_id }}
|
|
cancel-in-progress: true
|
|
|
|
jobs:
|
|
# ===================================================================
|
|
# Resolve version + macOS build run_id automatically
|
|
# ===================================================================
|
|
resolve:
|
|
runs-on: ubuntu-latest
|
|
if: >
|
|
github.event_name == 'workflow_dispatch' ||
|
|
(github.event.workflow_run.conclusion == 'success' &&
|
|
startsWith(github.event.workflow_run.head_branch, 'v'))
|
|
outputs:
|
|
version: ${{ steps.resolve.outputs.version }}
|
|
run_id: ${{ steps.resolve.outputs.run_id }}
|
|
steps:
|
|
- name: Resolve version and run_id
|
|
id: resolve
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
run: |
|
|
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
|
|
VERSION="${{ github.event.inputs.version }}"
|
|
RUN_ID="${{ github.event.inputs.run_id }}"
|
|
if [ -z "$VERSION" ]; then
|
|
TAG=$(gh release view --repo "$GITHUB_REPOSITORY" --json tagName -q '.tagName')
|
|
VERSION="${TAG#v}"
|
|
fi
|
|
if [ -z "$RUN_ID" ]; then
|
|
RUN_ID=$(gh run list --repo "$GITHUB_REPOSITORY" \
|
|
--workflow="Release macOS" --branch="v${VERSION}" --limit=1 \
|
|
--json databaseId,conclusion --jq '.[] | select(.conclusion=="success") | .databaseId')
|
|
fi
|
|
else
|
|
TAG="${{ github.event.workflow_run.head_branch }}"
|
|
VERSION="${TAG#v}"
|
|
RUN_ID="${{ github.event.workflow_run.id }}"
|
|
fi
|
|
|
|
if [ -z "$VERSION" ] || [ -z "$RUN_ID" ]; then
|
|
echo "::error::Failed to resolve version='${VERSION}' run_id='${RUN_ID}'"
|
|
exit 1
|
|
fi
|
|
|
|
echo "version=${VERSION}" >> $GITHUB_OUTPUT
|
|
echo "run_id=${RUN_ID}" >> $GITHUB_OUTPUT
|
|
echo "Resolved: version=${VERSION} run_id=${RUN_ID}"
|
|
|
|
# ===================================================================
|
|
# Notarize Yao binaries (arm64 + amd64)
|
|
# ===================================================================
|
|
notarize:
|
|
needs: resolve
|
|
runs-on: macos-latest
|
|
strategy:
|
|
matrix:
|
|
arch: [arm64, amd64]
|
|
steps:
|
|
- name: Download Yao Binary
|
|
uses: actions/download-artifact@v4
|
|
with:
|
|
name: yao-darwin-${{ matrix.arch }}
|
|
path: bin
|
|
run-id: ${{ needs.resolve.outputs.run_id }}
|
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
- name: Install Certificates
|
|
env:
|
|
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
|
|
run: |
|
|
mkdir -p certs
|
|
echo "${{ secrets.APPLE_DEVELOPERIDG2CA }}" | base64 --decode > certs/DeveloperIDG2CA.cer
|
|
echo "${{ secrets.APPLE_DISTRIBUTION }}" | base64 --decode > certs/distribution.cer
|
|
echo "${{ secrets.APPLE_PRIVATE_KEY }}" | base64 --decode > certs/private_key.p12
|
|
security verify-cert -c certs/DeveloperIDG2CA.cer
|
|
security verify-cert -c certs/distribution.cer
|
|
|
|
- name: Import Certificates
|
|
env:
|
|
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
|
|
run: |
|
|
KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
|
|
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 ./certs/DeveloperIDG2CA.cer -k $KEYCHAIN_PATH -T /usr/bin/codesign
|
|
security import ./certs/distribution.cer -k $KEYCHAIN_PATH -T /usr/bin/codesign
|
|
security import ./certs/private_key.p12 -k $KEYCHAIN_PATH -P "${{ secrets.APPLE_PRIVATE_KEY_PASSWORD }}" -T /usr/bin/codesign
|
|
security list-keychain -d user -s $KEYCHAIN_PATH
|
|
|
|
- name: Verify Signature
|
|
run: codesign --verify --deep --strict --verbose=2 bin/yao
|
|
|
|
- name: Notarize Yao ${{ matrix.arch }}
|
|
timeout-minutes: 15
|
|
env:
|
|
APPLE_ID: ${{ secrets.APPLE_ID }}
|
|
APPLE_TEAME_ID: ${{ secrets.APPLE_TEAME_ID }}
|
|
APPLE_APP_SPEC_PASS: ${{ secrets.APPLE_APP_SPEC_PASS }}
|
|
run: |
|
|
zip -j bin/yao.zip bin/yao
|
|
|
|
SUBMIT_OUT=$(xcrun notarytool submit bin/yao.zip \
|
|
--apple-id "$APPLE_ID" \
|
|
--team-id "$APPLE_TEAME_ID" \
|
|
--password "$APPLE_APP_SPEC_PASS" \
|
|
--wait --timeout 10m --output-format json 2>&1) || true
|
|
echo "$SUBMIT_OUT"
|
|
|
|
STATUS=$(echo "$SUBMIT_OUT" | python3 -c "import sys,json; print(json.load(sys.stdin).get('status',''))" 2>/dev/null || true)
|
|
SUB_ID=$(echo "$SUBMIT_OUT" | python3 -c "import sys,json; print(json.load(sys.stdin).get('id',''))" 2>/dev/null || true)
|
|
|
|
if [ "$STATUS" != "Accepted" ]; then
|
|
echo "::error::Yao ${{ matrix.arch }} notarization failed (status: $STATUS)"
|
|
[ -n "$SUB_ID" ] && xcrun notarytool log "$SUB_ID" \
|
|
--apple-id "$APPLE_ID" \
|
|
--team-id "$APPLE_TEAME_ID" \
|
|
--password "$APPLE_APP_SPEC_PASS" || true
|
|
exit 1
|
|
fi
|
|
echo "Yao ${{ matrix.arch }} notarization accepted."
|
|
|
|
# ===================================================================
|
|
# After both architectures finish: wait for Linux R2, then trigger CDN
|
|
# ===================================================================
|
|
finalize:
|
|
needs: [resolve, notarize]
|
|
runs-on: ubuntu-latest
|
|
if: success()
|
|
env:
|
|
AWS_ACCESS_KEY_ID: ${{ secrets.R2_ACCESS_KEY_ID }}
|
|
AWS_SECRET_ACCESS_KEY: ${{ secrets.R2_SECRET_ACCESS_KEY }}
|
|
R2_ENDPOINTS: ${{ secrets.R2_ENDPOINTS }}
|
|
R2_BUCKET: ${{ secrets.R2_BUCKET || 'releases' }}
|
|
steps:
|
|
- name: Checkout (for gh CLI context)
|
|
uses: actions/checkout@v4
|
|
with:
|
|
sparse-checkout: .github
|
|
|
|
- name: Configure AWS CLI
|
|
run: |
|
|
aws configure set default.region us-east-1
|
|
aws configure set default.s3.signature_version s3v4
|
|
|
|
- name: Wait for all platform assets on R2
|
|
run: |
|
|
VERSION="${{ needs.resolve.outputs.version }}"
|
|
PREFIX="yao/${VERSION}"
|
|
|
|
PLATFORMS=(
|
|
"darwin-arm64"
|
|
"darwin-amd64"
|
|
"linux-amd64"
|
|
"linux-arm64"
|
|
)
|
|
|
|
for ATTEMPT in $(seq 1 30); do
|
|
MISSING=0
|
|
for P in "${PLATFORMS[@]}"; do
|
|
KEY="${PREFIX}/yao-${VERSION}-${P}"
|
|
if ! aws s3 ls "s3://${R2_BUCKET}/${KEY}" --endpoint-url "$R2_ENDPOINTS" >/dev/null 2>&1; then
|
|
MISSING=$((MISSING+1))
|
|
fi
|
|
if ! aws s3 ls "s3://${R2_BUCKET}/${KEY}.sha256" --endpoint-url "$R2_ENDPOINTS" >/dev/null 2>&1; then
|
|
MISSING=$((MISSING+1))
|
|
fi
|
|
done
|
|
|
|
if [ "$MISSING" -eq 0 ]; then
|
|
echo "All 4 platform assets verified on R2."
|
|
exit 0
|
|
fi
|
|
|
|
echo "Attempt $ATTEMPT: $MISSING asset(s) still missing, waiting 30s..."
|
|
sleep 30
|
|
done
|
|
|
|
echo "::error::Timed out waiting for all platform assets on R2."
|
|
exit 1
|
|
|
|
- name: Trigger CDN latest.json update
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
run: |
|
|
VERSION="${{ needs.resolve.outputs.version }}"
|
|
gh workflow run update-cdn-latest.yml \
|
|
-f version="${VERSION}" \
|
|
-f mark_latest="true"
|
|
echo "Triggered update-cdn-latest.yml for ${VERSION}"
|