Skip to content

Publish via trusted publishing without rubygems/release-gem#59

Draft
lloeki wants to merge 2 commits into
mainfrom
lloeki/trusted-publishing
Draft

Publish via trusted publishing without rubygems/release-gem#59
lloeki wants to merge 2 commits into
mainfrom
lloeki/trusted-publishing

Conversation

@lloeki

@lloeki lloeki commented Jun 17, 2026

Copy link
Copy Markdown
Member

Why?

rubygems/release-gem bundles behavior we don't want and can't configure away (git identity config + tagging via rake release, git credential cache, tag fetch, await-release polling), and it pulls sigstore-cli in implicitly via gem exec at push time -- a hidden, unpinned transient dependency. This repo doesn't tag on release, so most of that machinery is dead weight.

Stacked on top of #58 (the quick fix that moves the publish job onto the host).

What does this PR do?

Replaces release-gem in build.yml's publish job with a minimal, fully-owned flow:

  • rubygems/configure-rubygems-credentials performs the OIDC token exchange for trusted publishing and exposes the short-lived key via GEM_HOST_API_KEY.
  • A vendored patch (.github/scripts/rubygems-attestation-patch.rb) makes gem push sign each gem with sigstore-cli and attach the Sigstore attestation, so provenance attestations are kept.
  • sigstore-cli is installed explicitly and pinned (gem install sigstore-cli -v 0.2.3) instead of being resolved implicitly.

It drops the octo-sts step too (it only fed a git token to release-gem for tagging).

The vendored patch is adapted from rubygems/release-gem@6317d8d (MIT) with two deliberate changes: it calls the explicitly-installed sigstore-cli binary rather than gem exec sigstore-cli:<ver>, and it removes the silent "retry without attestation" fallback so a signing failure fails the push loudly.

publish.yml is intentionally left untouched.

How to test the change?

Run the Build workflow with push enabled on main; the Publish job should obtain a trusted-publishing key, sign each gem with sigstore, and push with the attestation attached. (A successful run is a real release to RubyGems.org.) Requires the RubyGems trusted publisher to be registered for this repo's build.yml workflow.

Additional Notes:

Depends on #58 -- review/merge that first, then this rebases onto main.

AI was used to accelerate implementation; all code was reviewed and understood.

Base automatically changed from lloeki/fix-publish-git-ownership to main June 17, 2026 10:30
@lloeki lloeki force-pushed the lloeki/trusted-publishing branch from d6e9d03 to 03822f1 Compare June 17, 2026 10:32
Replace the rubygems/release-gem action in the publish job with a
minimal flow that we fully control:

- configure-rubygems-credentials performs the OIDC token exchange for
  trusted publishing and exposes the short-lived key via GEM_HOST_API_KEY
- a vendored patch makes `gem push` sign each gem with sigstore-cli and
  attach the attestation, keeping provenance attestations
- rubygems-await waits for the pushed gems to become available on
  RubyGems.org before the job completes
- sigstore-cli and rubygems-await are installed explicitly and pinned,
  rather than being resolved implicitly at run time

This drops release-gem's git identity/tagging, credential cache, tag
fetch and rake release wrapper -- none of which this repo needs (it does
not tag) -- and removes the octo-sts token, which only existed to
authenticate those git operations.
@lloeki lloeki force-pushed the lloeki/trusted-publishing branch from 03822f1 to 1b86304 Compare June 17, 2026 10:41
Run the gem install, push and await steps inside a pinned, runtime-only
ghcr.io/datadog/images-rb/engines/ruby:4.0-musl image, spawned with
`docker run --detach` and driven with `docker exec`, mirroring the
build and validate jobs. This pins the Ruby/RubyGems used for publishing
instead of relying on the host toolchain.

The workspace is mounted at the same path so the vendored attestation
patch and the pkg/ gems resolve identically inside the container. The
trusted-publishing credential exchange stays on the host (it is a
JavaScript action); its GEM_HOST_API_KEY, along with the OIDC request
variables sigstore-cli needs, are passed into the container. None of the
publishing dependencies have native extensions, so the runtime-only
image (no compiler) is sufficient.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant