Repository navigation
Harden the release and site workflows, add a security policy, and update dependencies with security fixes - #26
Merged
Merged
Conversation
Every action is pinned to the commit of its latest release in the major version we used (a tag can be moved to other code), checkouts don't keep the token in .git/config, and the CI, Rails main and Terraform example workflows get a read-only token instead of the repository default.
- A release runs only for a pushed v* tag (only admins can push them). The release: published trigger is gone, so a release no longer publishes twice. - Publishing moves to its own jobs in the release environment, which needs an approval and gets the built gem and the provider changes as artifacts: no job that has a credential runs the repository's code or restores a cache. - The gem is pushed with a short-lived key from RubyGems trusted publishing (OIDC) instead of the long-lived RUBYGEMS_API_KEY secret. - The provider repository is public, so it's cloned without a token. The token is passed to the two pushes only, not stored in the clone's config.
The supported versions page throws for a gemspec dependency it has no description for, so the site stopped building when the gemspec listed actionpack, activesupport, globalid and railties instead of rails. CI's docs job only type-checks and runs the tests, so nothing caught it. The descriptions move to docs/lib/gem-descriptions.ts with a test that every gemspec dependency has one, and a new CI job builds the site the way the deploy does, with the run's coverage report and YARD docs.
The deploy downloaded coverage-ruby-rails-latest from the newest successful CI run of any branch, forks included (dawidd6/action-download-artifact v3, whose allow_forks defaults to true, GHSA-5xr6-xhww-33m4), and served it under logstruct.com/coverage/. A fork's pull request could upload its own HTML under that name. CI now calls the deploy as its last job on a push to main, and the deploy downloads that run's artifact and checks out that run's commit. A manual deployment uses the latest successful CI run of a push to main, which a pull request's run never is. Only the deploy job can write to Pages.
The Playwright static server listened on every interface and served any file the request path reached with ../ (encoded or not) or through a symlink. It now binds 127.0.0.1, resolves each path inside out/ and answers 404 otherwise. The home page test expected the old heading.
SECURITY.md asks for private reports through GitHub's vulnerability reporting. Dependabot checks the gems, both pnpm projects and the workflow actions weekly, with minor and patch updates grouped into one pull request each.
Relaxes the rails pin to 8.0.5 and updates only the gems with open Dependabot alerts (rack, nokogiri, the Rails gems, loofah, rails-html-sanitizer, json, net-imap, mail and others), regenerating their RBIs. The concurrent-ruby <= 1.3.4 pin was only for Rails 7.0, whose test app pins it itself, so it goes. json stays below 3: ActiveSupport 8.0 passes quirks_mode, which json 3 rejects. net-imap stays on 0.5.x, and two of its classes' new parents are allowed in sorbet/config.
Next 15.5.27, react-syntax-highlighter 16 (prismjs 1.30) and sharp 0.35, plus pnpm update within each range. Removes packages nothing imports: gray-matter, next-mdx-remote, remark, remark-html, rehype-highlight, rehype-pretty-code, shiki, copy-to-clipboard and framer-motion, and the optional Linux binaries pinned to latest for npm (pnpm installs the matching ones itself; checked with a linux/amd64 install and build). Biome 2.5 sorts export lists and flags an index key and a missed optional chain. Jest 30.5 exits 0 without running tests when watchman is broken, so the tests don't use it.
jscpd stays on 4.0.7: 4.3 needs Node 22.12 or later.
Dir[] picked up any untracked file under lib/ in a local build. The gem now takes the same patterns from git ls-files, and uses Dir only without git.
Gives a compromised release time to be noticed and pulled first. Security updates aren't delayed.
Next 15.5 pins postcss 8.4.31, which has open advisories (they need attacker-controlled CSS or source maps; the site builds only its own CSS). Next 16 moved to 8.5.
|
Note Currently processing new changes in this PR. This may take a few minutes, please wait... ⚙️ Run configuration
⛔ Files ignored due to path filters: 31
📒 Files selected for processing: 29
✨ Finishing Touches
Comment |
This was referenced Oct 17, 2026
Merged
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.
Eleventh of twelve stacked PRs for 0.2.0.
Releases
v*tag, which only admins can push. Therelease: publishedtrigger is gone, soa release no longer publishes twice.
releaseenvironment, which needs an approval. They get the built gem and theprovider changes as artifacts, so no job that holds a credential runs the repository's code or restores a cache.
RUBYGEMS_API_KEYsecret.Workflows and the site
.git/config, and theCI, Rails main and Terraform example workflows get read-only tokens.
successful CI run of any branch, forks included (
dawidd6/action-download-artifactv3, whoseallow_forksdefaults to true, GHSA-5xr6-xhww-33m4), and served it under
logstruct.com/coverage/. CI now calls the deploy asits last job on a push to main, with that run's artifact and commit. Only the deploy job can write to Pages.
CI didn't build it. CI builds the site the way the deploy does, and a test checks every gemspec dependency has a
description.
../path reached. It binds127.0.0.1and serves only files insideout/.Dir[]picked up untracked files underlib/in a local build).Security policy and dependencies
SECURITY.mdasks for private reports through GitHub's vulnerability reporting.release (security updates aren't delayed), and groups minor and patch updates.
net-imap, mail and others), with their RBIs.
jsonstays below 3: ActiveSupport 8.0 passesquirks_mode, whichjson 3 rejects.
pins 8.4.31, which has open advisories). Removed nine packages nothing imports.
Before the first release from this workflow
Repository and RubyGems settings this needs (none of them are in the code):
logstruct: this repository,release.yml, environmentrelease.releaseenvironment with required reviewers, andTF_PROVIDER_GITHUB_TOKENas its secret.v*tags.RUBYGEMS_API_KEYsecret.Testing
Sorbet and the unit suite (367 tests) pass at this branch's tip.
actionlintpasses on everyworkflow. The deploy and release jobs run only on main and on tags, so they're first exercised by the merge and the
0.2.0 release (the release workflow's
dry_runinput runs everything but the publishing jobs).Stack for 0.2.0, merged in order: #16 → #17 → #18 → #19 → #20 → #21 → #22 → #23 → #24 → #25 → #26 → #27