Repository navigation
ci: publish to RubyGems from version tags - #6
Conversation
There was a problem hiding this comment.
🔵 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,
mainancestry, 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
left a comment
There was a problem hiding this comment.
Approving. Checked:
- I ran the "Check tag, version and CHANGELOG.md" step against this branch: with a dated
## 1.0.0heading on main, av1.0.0tag 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 buildgives a gem with onlylib/and the README, CHANGELOG, LICENSE, NOTICE and THIRD-PARTY-LICENSES files, and withrubygems_mfa_requiredset. - Run locally (Ruby 4.0), the audit and SBOM step works against an install of the built gem:
bundle lock --localresolves 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-direven 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: writeandcontents: readand runs no checkout, Bundler or Ruby setup.configure-rubygems-credentialsis 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.
Changes
publish.yml: on av*tag, checks the tag matchesComposer::VERSION, the commit is onmain, andCHANGELOG.mdhas a released section for the versionid-token): runs the tests, builds the gem, audits its runtime dependencies withbundler-audit, writes a CycloneDX SBOM withsyftfrom an install of the gem alone, writes SHA-256 checksums, and scans the gem with gitleaksreleaseenvironment,id-token: writeandcontents: readonly): verifies the checksum, fails if the version is already on RubyGems, gets a trusted publishing token withrubygems/configure-rubygems-credentials(pinned by commit SHA), and runsgem pushSHA256SUMSand SBOM