Skip to content

ci: publish to RubyGems from version tags - #6

Merged
drkjc merged 2 commits into
mainfrom
publish-workflow
Oct 26, 2026
Merged

drkjc merged 2 commits into
mainfrom
publish-workflow

Conversation

@drkjc

@drkjc drkjc commented Oct 23, 2026

Copy link
Copy Markdown
Collaborator

Changes

  • publish.yml: on a v* tag, checks the tag matches Composer::VERSION, the commit is on main, and CHANGELOG.md has a released section for the version
  • Build job (no id-token): runs the tests, builds the gem, audits its runtime dependencies with bundler-audit, writes a CycloneDX SBOM with syft from an install of the gem alone, writes SHA-256 checksums, and scans the gem with gitleaks
  • Publish job (release environment, id-token: write and contents: read only): verifies the checksum, fails if the version is already on RubyGems, gets a trusted publishing token with rubygems/configure-rubygems-credentials (pinned by commit SHA), and runs gem push
  • Release job: creates the GitHub Release with the CHANGELOG notes, gem, SHA256SUMS and SBOM

@drkjc
drkjc requested review from Samy-O7 and a balanced review from Copilot October 23, 2026 21:52

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The release-environment protections and RubyGems trusted-publisher binding require human verification before enabling publication.

No open issues 🎉

What changed in this PR

Adds a tag-driven workflow to publish the Ruby gem and create a corresponding GitHub Release, separating build-time dependency execution from publishing credentials.

Changes:

  • Validates the version tag, main ancestry, and released changelog entry before testing and building.
  • Audits runtime dependencies, generates an SBOM and checksum, and scans the packaged gem for secrets.
  • Publishes through RubyGems trusted publishing, then attaches artifacts and changelog notes to a GitHub Release.
File Description
.github/​workflows/​publish.yml Adds validation, build, security checks, RubyGems publishing, and GitHub Release jobs.

Review effort: Balanced

@Samy-O7 Samy-O7 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving. Checked:

  • I ran the "Check tag, version and CHANGELOG.md" step against this branch: with a dated ## 1.0.0 heading on main, a v1.0.0 tag passes and writes 24 lines of release notes, while a wrong tag, the current (unreleased) heading and a commit that isn't on main all fail.
  • Locally, gem build gives a gem with only lib/ and the README, CHANGELOG, LICENSE, NOTICE and THIRD-PARTY-LICENSES files, and with rubygems_mfa_required set.
  • Run locally (Ruby 4.0), the audit and SBOM step works against an install of the built gem: bundle lock --local resolves the SDK and its 8 runtime gems, bundler-audit 0.9.3 finds no vulnerabilities, and syft 1.55.0 (the pinned hash matches the release's checksums file) lists those 9 gems and no development gems. RubyGems 3.5, which Ruby 3.3.11 ships, also installs every dependency into --install-dir even when Ruby already has it, so the SBOM won't miss default gems.
  • gitleaks 8.30.1 finds no leaks in the extracted gem.
  • The publish job has only id-token: write and contents: read and runs no checkout, Bundler or Ruby setup. configure-rubygems-credentials is pinned to the v2.1.0 commit and uses trusted publishing by default. The RubyGems version check returns 404 for an unpublished version and 200 for a published one. The runner's RubyGems (3.4 on Ubuntu 24.04, 3.6 on 26.04) predates the automatic attestation in 4.1.

Optional: ruby/setup-ruby@v1 is a branch that moves with every release, and here it runs in the job that builds the published gem. Pinning it to a release commit like configure-rubygems-credentials would fix that, for example ruby/setup-ruby@e1bd6146574da5e0795075b5319b300edb30c5b0 # v1.333.0, and Dependabot's weekly updates would keep it current.

Before tagging, CHANGELOG.md needs a dated ## 1.0.0 heading, the README needs the RubyGems install instructions back since the gem ships README.md, and the RubyGems pending trusted publisher (this repo, publish.yml, the release environment) should be created shortly before the tag, since it expires after 12 hours.

@drkjc
drkjc merged commit f667329 into main Oct 26, 2026
7 checks passed
@drkjc
drkjc deleted the publish-workflow branch October 26, 2026 16:03
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.

3 participants