From 8a31d072852b9197544fc3c3ea1192e593fc2164 Mon Sep 17 00:00:00 2001 From: Cuihtlauac ALVARADO Date: Fri, 19 Jun 2026 19:57:57 +0200 Subject: [PATCH] fix(ci): send User-Agent in crates.io poll; make publish re-runnable The crates.io API returns HTTP 403 without a User-Agent, so the "wait for crate to be live" poll in publish.yml failed every attempt and aborted the job before the MCP Registry steps ran (the v1.0.0 crate published fine; only the registry listing was skipped). - Send a User-Agent on all crates.io API requests. - Add a workflow_dispatch trigger and derive the version from Cargo.toml so the workflow can be run manually (e.g. to register the server when the crate is already published). - Skip `cargo publish` when the version is already on crates.io, so dispatch re-runs don't fail on an existing version. Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/publish.yml | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 193c956..577a8aa 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -1,20 +1,29 @@ name: Publish -# Cut a release by pushing a `v*` tag (see CLAUDE.md). This publishes the crate +# Cut a release by pushing a `v*` tag (see CLAUDE.md): this publishes the crate # to crates.io via Trusted Publishing (OIDC, no stored token) and then registers # the server in the official MCP Registry via GitHub Actions OIDC, which grants # the `io.github.tarides` namespace from the repo owner. release.yml builds the # static tarball + GitHub release on the same tag, in parallel. +# +# Also runnable via workflow_dispatch (e.g. to (re)register the server when the +# crate is already published). The crate publish is skipped when the version in +# Cargo.toml is already on crates.io, so re-runs are safe. on: push: tags: - "v*" + workflow_dispatch: permissions: id-token: write # OIDC for both crates.io Trusted Publishing and mcp-publisher contents: read +env: + # crates.io rejects API requests without a User-Agent (HTTP 403). + CRATES_UA: "sudo-proxy-ci (+https://github.com/tarides/sudo-proxy)" + jobs: publish: runs-on: ubuntu-latest @@ -22,6 +31,13 @@ jobs: - uses: actions/checkout@v6 - uses: Swatinem/rust-cache@v2 + - name: Determine crate version + id: ver + run: | + VERSION=$(grep -m1 '^version' Cargo.toml | sed -E 's/.*"([^"]+)".*/\1/') + echo "version=$VERSION" >> "$GITHUB_OUTPUT" + echo "Releasing sudo-proxy $VERSION" + # crates.io Trusted Publishing: exchange the OIDC token for a short-lived # publish token (configured at crates.io -> sudo-proxy -> Trusted Publishing). - name: Authenticate to crates.io @@ -29,18 +45,25 @@ jobs: id: auth - name: Publish crate to crates.io - run: cargo publish env: CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }} + VERSION: ${{ steps.ver.outputs.version }} + run: | + if curl -fsS -A "$CRATES_UA" "https://crates.io/api/v1/crates/sudo-proxy/${VERSION}" >/dev/null 2>&1; then + echo "sudo-proxy ${VERSION} already on crates.io — skipping cargo publish" + else + cargo publish + fi # The MCP Registry validates ownership by reading the `mcp-name:` marker # and the version from the crate on crates.io, so the crate must be served # before we publish the server. Poll until the index catches up. - name: Wait for crate to be live on crates.io + env: + VERSION: ${{ steps.ver.outputs.version }} run: | - VERSION="${GITHUB_REF_NAME#v}" for i in $(seq 1 30); do - if curl -fsS "https://crates.io/api/v1/crates/sudo-proxy/${VERSION}" >/dev/null; then + if curl -fsS -A "$CRATES_UA" "https://crates.io/api/v1/crates/sudo-proxy/${VERSION}" >/dev/null; then echo "sudo-proxy ${VERSION} is live" exit 0 fi