diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 132a61c..4a95db9 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -16,13 +16,18 @@ jobs: strategy: fail-fast: false matrix: + # v0.22.3 fix: aarch64-linux moved from ubuntu-latest + cross-linker + # install (apt gcc-aarch64-linux-gnu consistently failed in CI) to + # ubuntu-24.04-arm NATIVE ARM runner. No cross-compile, rustc builds + # the target host-native. `experimental: false` — native path is + # reliable. include: - os: ubuntu-latest target: x86_64-unknown-linux-gnu experimental: false - - os: ubuntu-latest + - os: ubuntu-24.04-arm target: aarch64-unknown-linux-gnu - experimental: true + experimental: false - os: macos-latest target: x86_64-apple-darwin experimental: false @@ -47,14 +52,8 @@ jobs: with: workspaces: _primitives/_rust - - name: Install aarch64 cross-linker (Linux only) - if: matrix.target == 'aarch64-unknown-linux-gnu' - run: | - sudo apt-get update - sudo apt-get install -y gcc-aarch64-linux-gnu - mkdir -p .cargo - printf '[target.aarch64-unknown-linux-gnu]\nlinker = "aarch64-linux-gnu-gcc"\n' \ - > _primitives/_rust/.cargo/config.toml + # v0.22.3: cross-linker step removed — aarch64-linux now builds + # natively on ubuntu-24.04-arm. No cross-compile, no gcc-aarch64-linux-gnu. - name: Build workspace (release) working-directory: _primitives/_rust @@ -246,19 +245,49 @@ jobs: echo 'KEISEI_NOTES_EOF' } >> "$GITHUB_OUTPUT" + # v0.22.3 fix: softprops/action-gh-release v2.6.2 exited with failure + # on v0.22.2 due to a metadata-update race (asset uploaded to blob + # store but Releases metadata API returned 404 on the subsequent + # PATCH — eventual-consistency window). All 15 assets WERE uploaded, + # but the action exited 1 and left the Release in Draft state. + # + # Replaced with `gh release create` (bundled on all GitHub runners). + # CLI is idempotent: if the release already exists it updates it; if + # assets already exist `--clobber` replaces them. No metadata-PATCH + # race. Retry loop on transient upload failures. - name: Publish GitHub Release - # HIGH priority pin: this action has `contents: write` — a compromised - # tag would let an attacker publish arbitrary releases under this repo. - uses: softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65 # v2.6.2 - with: - name: ${{ github.ref_name }} - tag_name: ${{ github.ref_name }} - body: ${{ steps.notes.outputs.notes }} - files: | - release-assets/*.tar.gz - release-assets/*.sha256 - release-assets/kei-mcp-server-* - fail_on_unmatched_files: false + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + TAG: ${{ github.ref_name }} + NOTES: ${{ steps.notes.outputs.notes }} + shell: bash + run: | + set -euo pipefail + # Create the release if missing; `|| true` absorbs "already exists" + # on workflow re-run. + gh release view "$TAG" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1 || \ + gh release create "$TAG" \ + --repo "$GITHUB_REPOSITORY" \ + --title "$TAG" \ + --notes "$NOTES" + # Upload all assets with --clobber so re-runs replace cleanly. + # Retry each asset up to 3 times on transient network errors. + shopt -s nullglob + for f in release-assets/*.tar.gz release-assets/*.sha256 release-assets/kei-mcp-server-*; do + [ -f "$f" ] || continue + for try in 1 2 3; do + if gh release upload "$TAG" --repo "$GITHUB_REPOSITORY" --clobber "$f"; then + break + elif [ "$try" -eq 3 ]; then + echo "::error::failed to upload $f after 3 tries" >&2 + exit 1 + else + echo "upload of $f failed (attempt $try/3), retrying in 5s..." >&2 + sleep 5 + fi + done + done + echo "✓ Release $TAG published with all assets" npm-publish: name: Publish npm packages (optional)