Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 27 additions & 4 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -1,46 +1,69 @@
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
steps:
- 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
uses: rust-lang/crates-io-auth-action@v1
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
Expand Down
Loading