Update FCS Keys #371
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Update FCS Keys | |
| on: | |
| schedule: | |
| - cron: "0 19 * * *" # daily at 11:00 PST (19:00 UTC) | |
| workflow_dispatch: | |
| permissions: | |
| contents: write | |
| jobs: | |
| update-all-fcs-keys: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Set up Go | |
| uses: actions/setup-go@v6 | |
| with: | |
| go-version: "1.26" | |
| - name: Build ipsw CLI | |
| run: | | |
| go build -o ipsw ./cmd/ipsw | |
| - name: Get all latest builds | |
| id: get-builds | |
| run: | | |
| set -euo pipefail | |
| echo "Getting all latest build numbers..." | |
| get_latest_build() { | |
| platform="$1" | |
| device="$2" | |
| track="$3" | |
| if [ "$track" = "beta" ]; then | |
| build=$(./ipsw download ota --platform "$platform" --beta --show-latest-build --device "$device" --insecure) | |
| else | |
| build=$(./ipsw download ota --platform "$platform" --show-latest-build --device "$device" --insecure) | |
| fi | |
| build=$(printf '%s' "$build" | tr -d '\r\n') | |
| if [ -z "$build" ]; then | |
| echo "::error::No build returned for platform=$platform device=$device track=$track" >&2 | |
| exit 1 | |
| fi | |
| if ! printf '%s' "$build" | grep -Eq '^[0-9A-Za-z]+$'; then | |
| echo "::error::Invalid build identifier '$build' for platform=$platform device=$device track=$track" >&2 | |
| exit 1 | |
| fi | |
| printf '%s' "$build" | |
| } | |
| # Get stable builds (use same probe devices as Makefile defaults) | |
| STABLE_IOS=$(get_latest_build ios iPhone17,1 stable) | |
| STABLE_MACOS=$(get_latest_build macos Mac14,7 stable) | |
| STABLE_VISIONOS=$(get_latest_build visionos RealityDevice14,1 stable) | |
| # Get beta builds | |
| BETA_IOS=$(get_latest_build ios iPhone17,1 beta) | |
| BETA_MACOS=$(get_latest_build macos Mac14,7 beta) | |
| BETA_VISIONOS=$(get_latest_build visionos RealityDevice14,1 beta) | |
| # RC builds use same endpoint as stable for now | |
| RC_IOS="$STABLE_IOS" | |
| RC_MACOS="$STABLE_MACOS" | |
| RC_VISIONOS="$STABLE_VISIONOS" | |
| # Create fingerprints | |
| STABLE_FP="${STABLE_IOS}_${STABLE_MACOS}_${STABLE_VISIONOS}" | |
| RC_FP="${RC_IOS}_${RC_MACOS}_${RC_VISIONOS}" | |
| BETA_FP="${BETA_IOS}_${BETA_MACOS}_${BETA_VISIONOS}" | |
| # Output all builds | |
| echo "stable_ios=$STABLE_IOS" >> $GITHUB_OUTPUT | |
| echo "stable_macos=$STABLE_MACOS" >> $GITHUB_OUTPUT | |
| echo "stable_visionos=$STABLE_VISIONOS" >> $GITHUB_OUTPUT | |
| echo "stable_fingerprint=$STABLE_FP" >> $GITHUB_OUTPUT | |
| echo "rc_ios=$RC_IOS" >> $GITHUB_OUTPUT | |
| echo "rc_macos=$RC_MACOS" >> $GITHUB_OUTPUT | |
| echo "rc_visionos=$RC_VISIONOS" >> $GITHUB_OUTPUT | |
| echo "rc_fingerprint=$RC_FP" >> $GITHUB_OUTPUT | |
| echo "beta_ios=$BETA_IOS" >> $GITHUB_OUTPUT | |
| echo "beta_macos=$BETA_MACOS" >> $GITHUB_OUTPUT | |
| echo "beta_visionos=$BETA_VISIONOS" >> $GITHUB_OUTPUT | |
| echo "beta_fingerprint=$BETA_FP" >> $GITHUB_OUTPUT | |
| echo "Current fingerprints:" | |
| echo " Stable: $STABLE_FP" | |
| echo " RC: $RC_FP" | |
| echo " Beta: $BETA_FP" | |
| - name: Check for new builds | |
| id: check-builds | |
| run: | | |
| set -euo pipefail | |
| [ -n "${{ steps.get-builds.outputs.stable_ios }}" ] || { echo "::error::stable_ios output is empty" >&2; exit 1; } | |
| [ -n "${{ steps.get-builds.outputs.stable_macos }}" ] || { echo "::error::stable_macos output is empty" >&2; exit 1; } | |
| [ -n "${{ steps.get-builds.outputs.stable_visionos }}" ] || { echo "::error::stable_visionos output is empty" >&2; exit 1; } | |
| [ -n "${{ steps.get-builds.outputs.beta_ios }}" ] || { echo "::error::beta_ios output is empty" >&2; exit 1; } | |
| [ -n "${{ steps.get-builds.outputs.beta_macos }}" ] || { echo "::error::beta_macos output is empty" >&2; exit 1; } | |
| [ -n "${{ steps.get-builds.outputs.beta_visionos }}" ] || { echo "::error::beta_visionos output is empty" >&2; exit 1; } | |
| # Get cached fingerprints from the nested FcsKeys structure | |
| LAST_STABLE=$(jq -r '.fcs_keys_stable.fcs_keys.release.fingerprint // ""' hack/.watch_cache) | |
| LAST_RC=$(jq -r '.fcs_keys_rc.fcs_keys.rc.fingerprint // ""' hack/.watch_cache) | |
| LAST_BETA=$(jq -r '.fcs_keys_beta.fcs_keys.beta.fingerprint // ""' hack/.watch_cache) | |
| # Check what needs updating | |
| UPDATE_STABLE=false | |
| UPDATE_RC=false | |
| UPDATE_BETA=false | |
| UPDATE_ANY=false | |
| if [ "$LAST_STABLE" != "${{ steps.get-builds.outputs.stable_fingerprint }}" ]; then | |
| echo "New stable builds found" | |
| UPDATE_STABLE=true | |
| UPDATE_ANY=true | |
| fi | |
| if [ "$LAST_RC" != "${{ steps.get-builds.outputs.rc_fingerprint }}" ]; then | |
| echo "New RC builds found" | |
| UPDATE_RC=true | |
| UPDATE_ANY=true | |
| fi | |
| if [ "$LAST_BETA" != "${{ steps.get-builds.outputs.beta_fingerprint }}" ]; then | |
| echo "New beta builds found" | |
| UPDATE_BETA=true | |
| UPDATE_ANY=true | |
| fi | |
| echo "update_stable=$UPDATE_STABLE" >> $GITHUB_OUTPUT | |
| echo "update_rc=$UPDATE_RC" >> $GITHUB_OUTPUT | |
| echo "update_beta=$UPDATE_BETA" >> $GITHUB_OUTPUT | |
| echo "update_any=$UPDATE_ANY" >> $GITHUB_OUTPUT | |
| - name: Update stable FCS keys | |
| if: steps.check-builds.outputs.update_stable == 'true' | |
| run: | | |
| echo "Running FCS keys update for stable..." | |
| make update_fcs_keys_release \ | |
| FCS_IOS_BUILD="${{ steps.get-builds.outputs.stable_ios }}" \ | |
| FCS_MOS_BUILD="${{ steps.get-builds.outputs.stable_macos }}" \ | |
| FCS_VOS_BUILD="${{ steps.get-builds.outputs.stable_visionos }}" | |
| - name: Update RC FCS keys | |
| if: steps.check-builds.outputs.update_rc == 'true' | |
| run: | | |
| echo "Running FCS keys update for RC..." | |
| make update_fcs_keys_rc | |
| - name: Update beta FCS keys | |
| if: steps.check-builds.outputs.update_beta == 'true' | |
| run: | | |
| echo "Running FCS keys update for beta..." | |
| make update_fcs_keys_beta | |
| - name: Check for changes and commit | |
| if: steps.check-builds.outputs.update_any == 'true' | |
| run: | | |
| set -euo pipefail | |
| # Debug: Show file timestamps and git status | |
| echo "=== File timestamps ===" | |
| ls -la pkg/aea/data/fcs-keys* | |
| echo "=== Git status ===" | |
| git status pkg/aea/data/fcs-keys* | |
| echo "=== Git diff ===" | |
| git diff pkg/aea/data/fcs-keys.json pkg/aea/data/fcs-keys.gz || echo "No diff output" | |
| # Check if any files actually changed | |
| if git diff --quiet pkg/aea/data/fcs-keys.json pkg/aea/data/fcs-keys.gz; then | |
| echo "No changes to FCS keys files despite new builds" | |
| exit 0 | |
| fi | |
| # Update the cache file with all new fingerprints | |
| cp hack/.watch_cache hack/.watch_cache.tmp | |
| # Update stable if needed | |
| if [ "${{ steps.check-builds.outputs.update_stable }}" = "true" ]; then | |
| jq -c --sort-keys --arg fp "${{ steps.get-builds.outputs.stable_fingerprint }}" \ | |
| --arg ios "${{ steps.get-builds.outputs.stable_ios }}" \ | |
| --arg macos "${{ steps.get-builds.outputs.stable_macos }}" \ | |
| --arg visionos "${{ steps.get-builds.outputs.stable_visionos }}" \ | |
| --arg timestamp "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \ | |
| '.fcs_keys_stable = { | |
| "fcs_keys": { | |
| "release": { | |
| "fingerprint": $fp, | |
| "ios_build": $ios, | |
| "macos_build": $macos, | |
| "visionos_build": $visionos, | |
| "updated_at": $timestamp | |
| } | |
| } | |
| }' hack/.watch_cache.tmp > hack/.watch_cache.tmp2 | |
| mv hack/.watch_cache.tmp2 hack/.watch_cache.tmp | |
| fi | |
| # Update RC if needed | |
| if [ "${{ steps.check-builds.outputs.update_rc }}" = "true" ]; then | |
| jq -c --sort-keys --arg fp "${{ steps.get-builds.outputs.rc_fingerprint }}" \ | |
| --arg ios "${{ steps.get-builds.outputs.rc_ios }}" \ | |
| --arg macos "${{ steps.get-builds.outputs.rc_macos }}" \ | |
| --arg visionos "${{ steps.get-builds.outputs.rc_visionos }}" \ | |
| --arg timestamp "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \ | |
| '.fcs_keys_rc = { | |
| "fcs_keys": { | |
| "rc": { | |
| "fingerprint": $fp, | |
| "ios_build": $ios, | |
| "macos_build": $macos, | |
| "visionos_build": $visionos, | |
| "updated_at": $timestamp | |
| } | |
| } | |
| }' hack/.watch_cache.tmp > hack/.watch_cache.tmp2 | |
| mv hack/.watch_cache.tmp2 hack/.watch_cache.tmp | |
| fi | |
| # Update beta if needed | |
| if [ "${{ steps.check-builds.outputs.update_beta }}" = "true" ]; then | |
| jq -c --sort-keys --arg fp "${{ steps.get-builds.outputs.beta_fingerprint }}" \ | |
| --arg ios "${{ steps.get-builds.outputs.beta_ios }}" \ | |
| --arg macos "${{ steps.get-builds.outputs.beta_macos }}" \ | |
| --arg visionos "${{ steps.get-builds.outputs.beta_visionos }}" \ | |
| --arg timestamp "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \ | |
| '.fcs_keys_beta = { | |
| "fcs_keys": { | |
| "beta": { | |
| "fingerprint": $fp, | |
| "ios_build": $ios, | |
| "macos_build": $macos, | |
| "visionos_build": $visionos, | |
| "updated_at": $timestamp | |
| } | |
| } | |
| }' hack/.watch_cache.tmp > hack/.watch_cache.tmp2 | |
| mv hack/.watch_cache.tmp2 hack/.watch_cache.tmp | |
| fi | |
| # Final sort of the cache file for idempotency | |
| jq --sort-keys . hack/.watch_cache.tmp > hack/.watch_cache | |
| rm hack/.watch_cache.tmp | |
| # Also sort the main FCS keys JSON file before commit (if it exists) | |
| if [ -f pkg/aea/data/fcs-keys.json ]; then | |
| jq --sort-keys . pkg/aea/data/fcs-keys.json > pkg/aea/data/fcs-keys.json.tmp && mv pkg/aea/data/fcs-keys.json.tmp pkg/aea/data/fcs-keys.json | |
| jq -e 'type == "object" and length > 0' pkg/aea/data/fcs-keys.json >/dev/null | |
| gzip -cn pkg/aea/data/fcs-keys.json > pkg/aea/data/fcs-keys.gz | |
| fi | |
| # Configure git | |
| git config --local user.name "github-actions[bot]" | |
| git config --local user.email "github-actions[bot]@users.noreply.github.com" | |
| # Build commit message | |
| COMMIT_MSG="chore(fcs-keys): update FCS keys" | |
| UPDATES=() | |
| if [ "${{ steps.check-builds.outputs.update_stable }}" = "true" ]; then | |
| UPDATES+=("stable") | |
| fi | |
| if [ "${{ steps.check-builds.outputs.update_rc }}" = "true" ]; then | |
| UPDATES+=("RC") | |
| fi | |
| if [ "${{ steps.check-builds.outputs.update_beta }}" = "true" ]; then | |
| UPDATES+=("beta") | |
| fi | |
| # Join updates with commas | |
| UPDATE_STR=$(IFS=', '; echo "${UPDATES[*]}") | |
| COMMIT_MSG="$COMMIT_MSG ($UPDATE_STR) [skip ci]" | |
| # Commit all changes at once | |
| git add pkg/aea/data/fcs-keys.json pkg/aea/data/fcs-keys.gz hack/.watch_cache | |
| git commit -m "$COMMIT_MSG" | |
| git push |