Conversation
Fixes #23. push_gem.yml already published through trusted publishing with rubygems/release-gem, but only by hand, and it had never run. It now runs after CI Test passes on main, and publishes only when singed.gemspec's version isn't on RubyGems yet, so bumping the version is the release, as with the rubyatscale gems that use shared-config's cd.yml. It still works by hand for retries, and skips a version that's already published. - The check job only lets a push to this repo through, since a fork's pull request can come from a branch named main. - `rake release` pushes the current branch along with the tag, so the release job checks out main itself, rather than a detached HEAD, and first confirms main is still the commit CI tested. - The release job runs `bundle install` without a cache, since it publishes. - Bumps rubygems/release-gem from v1.1.0 to v1.4.1, which fetches tags before releasing and keeps credentials off disk. - Creates the GitHub release, and posts to Slack on failure, like cd.yml. The workflow's filename and the rubygems.org environment stay as they are, since the trusted publisher on RubyGems.org is registered against them.
If `gh release create` failed after the gem was already on RubyGems, a retry skipped everything, since the version was published, so the GitHub release never got created. The check job now also looks for a GitHub release for the version, and a separate job creates it whenever it's missing, whether the gem was just published or already had been.
rubygems/release-gem v1.4.1 stores the token in git's credential cache for the tag push and clears it afterwards, so the checkout doesn't need to leave one behind.
CodeQL flagged actions/cache-poisoning/poisonable-step: the check job checked out the workflow_run head SHA and then ran code from it, since Gem::Specification.load evaluates the gemspec. The job's `if` already limits it to pushes to this repo, but the analysis can't see that. The job now fetches singed.gemspec at that SHA through the API and reads spec.version with a strict pattern, so nothing from the commit runs and the job no longer needs Ruby. If the gemspec ever stops using a string literal for the version, the job fails with an error instead of guessing.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #23. Thanks to @technicalpickles for the groundwork in #20 and #22, and for the write-up in #23.
Summary
push_gem.ymlalready publishes through RubyGems trusted publishing (OIDC) withrubygems/release-gem, but only when run by hand, and it has never run. This makes it automatic, in the same way the rubyatscale gems on shared-config'scd.ymlwork: bumping the version insinged.gemspecis the release.main, a check job comparessinged.gemspec's version with RubyGems. If the version isn't there yet, the release job publishes it with trusted publishing, which tagsv<version>and pushes the gem. A separate job then creates the GitHub release with generated notes.SLACK_WEBHOOK_URL, likecd.yml.It keeps trusted publishing rather than switching to shared-config's
cd.yml, which uses the org-wideRUBYGEMS_API_KEY. The workflow's filename and therubygems.orgenvironment are unchanged, because the trusted publisher on RubyGems.org is registered against them.Details
pushto this repo gets past the check job. A fork's pull request can come from a branch namedmain, whichworkflow_run'sbranchesfilter would otherwise match. zizmor flagsworkflow_runin general, so it's suppressed inline with that reason.singed.gemspecat the tested commit through the API and pulls outspec.versionwith a strict pattern, rather than checking out the commit and evaluating the gemspec. That way no code from the triggering commit runs in a privileged context; CodeQL flagged the checkout as a cache-poisoning risk. If the gemspec ever stops using a string literal for the version, the job fails with an error rather than guessing.rake releasepushes the current branch along with the tag, so the release job checks outmainitself rather than a detached HEAD, and first confirmsmainis still the commit CI tested.bundle installwithout one, since it publishes. zizmor flagged the cache as a poisoning risk.rubygems/release-gemgoes from v1.1.0 to v1.4.1. That release fetches tags before releasing, and it keeps the push token in git's credential cache instead of on disk, which is why the checkout usespersist-credentials: false.vendor/bundle,pkg/and the vendored speedscope are all gitignored now. I ranrake buildand thenrake release:guard_cleanlocally on a clean checkout, and it passes.release-gemsets the identity itself, and the job hascontents: write.Before the first release
techpicklesandgusto-open-source, and it's configured at https://rubygems.org/gems/singed/trusted_publishers. It should be repositoryrubyatscale/singed, workflowpush_gem.yml, environmentrubygems.org. Since this workflow has never run, it's unverified. If it's missing, the release job fails at the credentials step with "No trusted publisher configured", and nothing is published.GEM_HOST_API_KEYisn't used by trusted publishing and can be deleted once a release has gone through.Test plan
--persona pedantic) are clean.v0.3.0release both exist, so nothing runs. For an unpublished version, the gem gets published and the release created.rake buildthenrake release:guard_cleanpasses on a clean checkout.