From 70986607178247d6214a588f687a1de1ceabb0fb Mon Sep 17 00:00:00 2001 From: Alex Moreton Date: Thu, 16 Jul 2026 12:25:16 +0100 Subject: [PATCH] ci(native): add force input to rebuild a drifted artifact key The `Already published?` guard only checks that the asset exists, so once a key's published asset drifts from the committed manifest there is no way to republish it: every dispatch sees the object, skips the build, and the EAS `eas-build-pre-install` hook keeps failing its checksum verify. That drift happened for chat_mls_coreFFI-ios-7e4fdcc9abc3f190: a locally built xcframework was uploaded over the CI-published one. Same source key, different bytes (the binaries are non-reproducible), so the consumer can never verify. Dispatch with force=true to bypass the guard and rebuild + republish, which also refreshes the committed manifest back into lockstep with the asset. Non-dispatch events leave `inputs.force` null, so push/PR behaviour is unchanged. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_018bbPAiJXZSrCaGTMZERmKX --- .github/workflows/native-artifacts.yml | 28 ++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/.github/workflows/native-artifacts.yml b/.github/workflows/native-artifacts.yml index 6b2ddd9..5e601f2 100644 --- a/.github/workflows/native-artifacts.yml +++ b/.github/workflows/native-artifacts.yml @@ -10,6 +10,9 @@ # # Idempotent: if the asset for the current source key already exists on R2, the # expensive Rust build is skipped — reruns and non-Rust PR syncs are cheap. +# Dispatch with force=true to override that skip and rebuild + republish a key +# whose published asset has drifted from the committed manifest (e.g. a local +# build was uploaded over a CI-published one — the consumer can't verify then). # # ── Required config ─────────────────────────────────────────────────────────── # secrets.R2_ACCOUNT_ID Cloudflare account id (R2 S3 endpoint host) @@ -21,6 +24,11 @@ name: Native artifacts on: workflow_dispatch: + inputs: + force: + description: "Rebuild + republish even if the asset for this key already exists. Use to repair a key whose published asset no longer matches the committed manifest." + type: boolean + default: false push: branches: [main] paths: @@ -67,9 +75,15 @@ jobs: - name: Already published? id: exists + env: + FORCE: ${{ inputs.force }} + ASSET: ${{ steps.key.outputs.asset }} run: | - URL="${R2_PUBLIC_BASE_URL%/}/${{ steps.key.outputs.asset }}" - if curl -fsI "$URL" >/dev/null 2>&1; then + URL="${R2_PUBLIC_BASE_URL%/}/${ASSET}" + if [ "$FORCE" = "true" ]; then + echo "found=false" >> "$GITHUB_OUTPUT" + echo "⟳ force — rebuilding + republishing $URL" + elif curl -fsI "$URL" >/dev/null 2>&1; then echo "found=true" >> "$GITHUB_OUTPUT" echo "✓ $URL already published — skipping build" else @@ -157,9 +171,15 @@ jobs: - name: Already published? id: exists + env: + FORCE: ${{ inputs.force }} + ASSET: ${{ steps.key.outputs.asset }} run: | - URL="${R2_PUBLIC_BASE_URL%/}/${{ steps.key.outputs.asset }}" - if curl -fsI "$URL" >/dev/null 2>&1; then + URL="${R2_PUBLIC_BASE_URL%/}/${ASSET}" + if [ "$FORCE" = "true" ]; then + echo "found=false" >> "$GITHUB_OUTPUT" + echo "⟳ force — rebuilding + republishing $URL" + elif curl -fsI "$URL" >/dev/null 2>&1; then echo "found=true" >> "$GITHUB_OUTPUT" echo "✓ $URL already published — skipping build" else