Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
version: 2
updates:
- package-ecosystem: github-actions
directory: /
schedule:
interval: weekly
Copy link
Copy Markdown
Collaborator

@mkasberg mkasberg Apr 24, 2026

Choose a reason for hiding this comment

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

I don't actually want to review dependabot PRs weekly though, and we really have no reason to for a static site. I'd rather bump everything (manually, without dependabot) once a year.

Copy link
Copy Markdown
Contributor Author

@JohnRDOrazio JohnRDOrazio Apr 24, 2026

Choose a reason for hiding this comment

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

Bump manually without dependabot, for minor version bumps? The problem with bumping it manually without dependabot opening a PR, is that it won't get bumped manually and then things start to break (as is currently the case). We all have lots of projects on our hands, and something that needs looking into once a year probably means nobody will look into it. But if dependabot opens the PR, then you at least get notified "hey there's something to look into here". Setting up a workflow to auto-merge minor version bumps means we wouldn't even have to look at it weekly: minor version bumps just get merged and you hardly notice. For GitHub actions, that won't break anything. Major version bumps can be merged manually: dependabot will check weekly but of course there won't be a weekly major version bump, it'll still only happen maybe once a year. And at least you get notified...

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Setting up a workflow to auto-merge minor version bumps means we wouldn't even have to look at it weekly: minor version bumps just get merged and you hardly notice. For GitHub actions, that won't break anything.

That's why I usually like pinning to major versions, and each build will automatically have the latest release in that version (e.g. v1, v2, etc.).

Can Dependabot pin to major versions instead of to commit hashes? That would be easiest for me. You start to see failures immediately if a minor fix in the major version causes it—though for GitHub Actions, there was only one time in the 300+ repos I maintain that a minor action change caused any grief.

Copy link
Copy Markdown
Contributor Author

@JohnRDOrazio JohnRDOrazio Apr 24, 2026

Choose a reason for hiding this comment

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

the best way to prevent a failure, is to add a build job to any PR that touches anything that determines the build (see PR #65 for that). So a dependabot PR that attempts to bump the minor version of an action, will still have to await a successful build action before it can be merged, and that's the best way of knowing whether a bumped action could break a build, you catch it before it is even merged to the codebase.

I don't feel very strongly about this and I am happy to revert to major version strings instead of SHAs, but SHAs are now recommended as the best security practice. I think ChatGPT will sum it up better than I could explain:

1) What SHA pinning actually gives you (and why it’s strongly recommended)

Pinning a GitHub Action to a full commit SHA instead of a tag like @v3 is fundamentally about supply-chain security and determinism:

Security (the real reason)

  • Tags are mutable: an attacker (or compromised maintainer account) can retarget v3 to malicious code.
  • A commit SHA is immutable → you are guaranteed to run exactly the code you reviewed. ([Well-Architected]1)
  • This directly mitigates “poisoned release/tag” attacks and secret exfiltration risks. ([The GitHub Blog]2)

Reproducibility

  • Your CI runs the same code every time, no surprises from upstream changes.
  • Builds become deterministic (same inputs → same result).

Stability

  • No accidental breaking changes from upstream minor/major releases.
  • You control when upgrades happen instead of being surprised by them.

Policy enforcement

  • GitHub can now enforce SHA pinning at org/repo level; workflows fail if not pinned. ([The GitHub Blog]2)

👉 Bottom line: SHA pinning trades automatic updates for control + security. That’s not optional anymore in serious pipelines.


2) The downside (and why you need automation)

Pinned SHAs do not move automatically, so:

  • You will go stale if you don’t update them.
  • You can miss bug fixes or security patches.

That’s why GitHub explicitly recommends pairing pinning with an updater (Dependabot or similar). ([Well-Architected]1)


3) Will Dependabot still open PRs with SHA pinning?

Yes — but with an important nuance:

✔ Yes, Dependabot still works with SHA-pinned actions

  • It scans workflows, resolves tags → SHAs, and opens PRs updating the pinned commit. ([Adaptive Enforcement Lab]3)
  • It can also include/update the version comment (# v4.1.7) alongside the SHA. ([GitHub Docs]4)

✔ It still detects new releases

  • Version updates: PRs when a new version is released
  • Security updates: PRs when a vulnerability is fixed ([GitHub Docs]5)

❗ But: semver semantics become less visible

  • You’re pinning a commit, not v3 / v4, so:

    • Dependabot doesn “bump v3 → v4” in the YAML.
    • It updates the underlying SHA to one corresponding to a newer release.

In practice:

- uses: actions/checkout@<old-sha> # v4.1.0

→ Dependabot PR:

- uses: actions/checkout@<new-sha> # v4.2.0

4) Minor vs major bumps specifically

Yes, Dependabot will still open PRs for both minor and major updates, but:

  • It’s not “bumping a version string” anymore
  • It’s proposing a new SHA tied to a newer release (minor or major)

You can still control behavior:

  • Ignore majors, allow only minor/patch via config (update-types) ([GitHub Docs]6)
  • Group updates, schedule them, etc.

5) The correct mental model

Think of it this way:

  • Without pinning:
    “Always run latest matching version” (unsafe, non-deterministic)

  • With SHA pinning + Dependabot:
    “Run a frozen version, and let a bot propose upgrades explicitly”

That’s the winning combination.


Final verdict

  • SHA pinning is non-negotiable for security-critical workflows
  • Dependabot still works perfectly with it
  • You don’t lose updates — you just review them instead of silently consuming them

If anything, SHA pinning + Dependabot is the best practice baseline today.

And then enabling an auto-merge workflow for minor version bumps, results basically in the same situation as pinning to a major version. Pinning to a major version, you don't have control over any of the minor version bumps, they are transparent. Pinning to a SHA and allowing auto-merge of minor version bumps, they're basically still transparent but with the added security that there is no poisoning, AND you can add the test build workflow that guarantees it won't break anything.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

There may be a way to configure dependabot to keep things up to date without too much regular interaction. I guess I'd be open to exploring that, but I still don't think we need it. If we do explore it, I'd prefer it in a separate, isolated PR.

I do want version tags for workflows, not SHAs. I understand the argument ChatGPT is making. The advice is reasonable, and in a different context SHAs might be the preferred approach. It's not my preferred approach here:

  • We don't have any secrets to protect. This is a static site in an open source repo. We're not even running any servers.
  • SHA pinning is only valuable to the extent that you trust the SHA. If dependabot is updating automatically, you're vulnerable to a supply chain attack again anyway, so by automatically updating SHAs (without any other kind of review or validation) you've lost the value of SHA pinning.

I have a more minimal PR here that gets the build working. It makes the minimal changes needed to fix the build - update actions/cache, and add a PR test workflow to validate the change. We can also update other things (ruby version, jekyll version, etc), but I'd prefer to do so in separate, smaller, isolated PRs.

Copy link
Copy Markdown
Contributor Author

@JohnRDOrazio JohnRDOrazio Apr 25, 2026

Choose a reason for hiding this comment

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

SHA pinning is only valuable to the extent that you trust the SHA.

That is true, but my understanding of dependabot is that it doesn't do any blind version bumps, but does some security checks to ensure that the bump is valid and not poisoned, considering it also takes care of opening PRs for security fixes on dependencies. I think some trust can be placed in Dependabot? Having that extra security check on the pinned SHA makes it nearly impossible to get a bad bump; whereas linking to major versions means neither we nor dependabot has any control over the version bumps.

In any case, not a big deal, one way or the other, as long as we get the build working again.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

#68 is merged, so the build should be working again!

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Yeah, main thing is getting the build working.

I mainly like not having 'noise' in the commits (e.g. keeping up with commits, Dependabot going a bit crazy there), especially for a project that's mostly in maintenance mode (at least architecturally).

And security through commit hashes instead of tags is a dubious argument, I'd seriously argue the point with ChatGPT, but then in the end it would probably tell me I'm right, because it just loves making me feel good about whatever I decide haha.

Copy link
Copy Markdown
Contributor Author

@JohnRDOrazio JohnRDOrazio Apr 25, 2026

Choose a reason for hiding this comment

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

I notice that when people ask AI an opinion on an issue, and they already have a bit of an opinion themselves, AI will often tend to let them hear what they want to hear. But if instead of asking for an opinion or an argument in favor of or against something, you ask simply to summarize the situation with the latest best practices based on documentation, it does a pretty good job at that.

The main reference document here is:
https://docs.github.com/en/actions/reference/security/secure-use#using-third-party-actions

But this really does matter more when you are dealing with third party actions. The actions curated by GitHub can generally be considered secure.

commit-message:
prefix: ci
labels:
- dependencies
- github-actions

- package-ecosystem: bundler
directory: /
schedule:
interval: weekly
commit-message:
prefix: deps
labels:
- dependencies
- ruby
12 changes: 6 additions & 6 deletions .github/workflows/github-pages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,24 +13,24 @@ on:
jobs:
github-pages:
runs-on: ubuntu-latest
container: ruby:3.2.2-bookworm
container: ruby:3.4.9-bookworm
steps:
- uses: actions/checkout@v2
- uses: actions/cache@v1
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'd rather not hit a specific commit, because that makes it a little more annoying to 'follow master' — future versions of checkout/cache could break things, and we wouldn't know until at some point we're forced to update dependencies.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I see dependabot maybe manages the deps though?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

yes dependabot will automatically open PRs for version bumps, following this same schema of pinning to the SHA and adding a human readable comment for the corresponding version (major.minor.patch). Basically it's the same as pinning to the version number except it's more secure, and dependabot takes care of keeping them up to date.

A good followup (which I can open later, if "auto-merge" is enabled in the repo settings), is a workflow that will automatically merge minor version bumps from dependabot (minor version bumps won't break anything), while for major version bumps dependabot would open the PR but it wouldn't automatically merge, we would merge it manually to ensure nothing breaks.

But even better is to have an automatic build step on dependabot major bumps PRs that ensures the build is clean, and only if that build test passes would we merge (or auto-merge).

Copy link
Copy Markdown
Contributor Author

@JohnRDOrazio JohnRDOrazio Apr 23, 2026

Choose a reason for hiding this comment

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

basically I had never touched the "enable auto-merge" setting on any of my projects until recently, because I was afraid that it would automatically merge open PRs without being able to review them. But I just discovered in the past week or two that it actually just enables the possibility of auto-merge, it doesn't actually auto-merge; if enabled though, you can add another workflow that will auto-merge dependabot PRs, and you can choose if it auto-merges all dependabot PRs or only minor version bump PRs. And you can place conditions such as "does this build cleanly?"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I guess I'm fine with either approach; actions/foo is managed by GitHub so I'm not terribly worried about the sha changing, especially on a static site like this.

- uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: vendor/bundle
key: ${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock') }}
key: ${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock', '.ruby-version') }}

- name: Install Ruby dependencies.
run: |
gem install bundler
bundle install --path vendor/bundle
bundle install --path vendor/bundle

- name: Build static site with Jekyll.
run: bundle exec jekyll build

- name: Deploy static site to gh-pages branch.
uses: peaceiris/actions-gh-pages@v3
uses: peaceiris/actions-gh-pages@4f9cc6602d3f66b9c108549d475ec49e8ef4d45e # v4.0.0
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./_site
2 changes: 1 addition & 1 deletion .ruby-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.2.2
3.4.9
130 changes: 100 additions & 30 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,31 +1,64 @@
GEM
remote: https://rubygems.org/
specs:
addressable (2.8.5)
public_suffix (>= 2.0.2, < 6.0)
addressable (2.9.0)
public_suffix (>= 2.0.2, < 8.0)
base64 (0.3.0)
bigdecimal (4.1.2)
colorator (1.1.0)
concurrent-ruby (1.2.2)
concurrent-ruby (1.3.6)
csv (3.3.5)
em-websocket (0.5.3)
eventmachine (>= 0.12.9)
http_parser.rb (~> 0)
eventmachine (1.2.7)
ffi (1.16.2)
ffi (1.17.4-aarch64-linux-gnu)
ffi (1.17.4-aarch64-linux-musl)
ffi (1.17.4-arm-linux-gnu)
ffi (1.17.4-arm-linux-musl)
ffi (1.17.4-arm64-darwin)
ffi (1.17.4-x86_64-darwin)
ffi (1.17.4-x86_64-linux-gnu)
ffi (1.17.4-x86_64-linux-musl)
forwardable-extended (2.6.0)
google-protobuf (3.24.3)
http_parser.rb (0.8.0)
i18n (1.14.1)
google-protobuf (4.34.1)
bigdecimal
rake (~> 13.3)
google-protobuf (4.34.1-aarch64-linux-gnu)
bigdecimal
rake (~> 13.3)
google-protobuf (4.34.1-aarch64-linux-musl)
bigdecimal
rake (~> 13.3)
google-protobuf (4.34.1-arm64-darwin)
bigdecimal
rake (~> 13.3)
google-protobuf (4.34.1-x86_64-darwin)
bigdecimal
rake (~> 13.3)
google-protobuf (4.34.1-x86_64-linux-gnu)
bigdecimal
rake (~> 13.3)
google-protobuf (4.34.1-x86_64-linux-musl)
bigdecimal
rake (~> 13.3)
http_parser.rb (0.8.1)
i18n (1.14.8)
concurrent-ruby (~> 1.0)
jekyll (4.3.2)
jekyll (4.4.1)
addressable (~> 2.4)
base64 (~> 0.2)
colorator (~> 1.0)
csv (~> 3.0)
em-websocket (~> 0.5)
i18n (~> 1.0)
jekyll-sass-converter (>= 2.0, < 4.0)
jekyll-watch (~> 2.0)
json (~> 2.6)
kramdown (~> 2.3, >= 2.3.1)
kramdown-parser-gfm (~> 1.0)
liquid (~> 4.0)
mercenary (>= 0.3.6, < 0.5)
mercenary (~> 0.3, >= 0.3.6)
pathutil (~> 0.9)
rouge (>= 3.0, < 5.0)
safe_yaml (~> 1.0)
Expand All @@ -34,47 +67,84 @@ GEM
jekyll-paginate (1.1.0)
jekyll-redirect-from (0.16.0)
jekyll (>= 3.3, < 5.0)
jekyll-sass-converter (3.0.0)
sass-embedded (~> 1.54)
jekyll-sass-converter (3.1.0)
sass-embedded (~> 1.75)
jekyll-watch (2.2.1)
listen (~> 3.0)
jekyll_html_truncatewords (0.1.2)
liquid
nokogiri
kramdown (2.4.0)
rexml
json (2.19.4)
kramdown (2.5.2)
rexml (>= 3.4.4)
kramdown-parser-gfm (1.1.0)
kramdown (~> 2.0)
liquid (4.0.4)
listen (3.8.0)
listen (3.10.0)
logger
rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10)
logger (1.7.0)
mercenary (0.4.0)
mini_portile2 (2.8.4)
nokogiri (1.15.4)
mini_portile2 (~> 2.8.2)
nokogiri (1.19.2-aarch64-linux-gnu)
racc (~> 1.4)
nokogiri (1.19.2-aarch64-linux-musl)
racc (~> 1.4)
nokogiri (1.19.2-arm-linux-gnu)
racc (~> 1.4)
nokogiri (1.19.2-arm-linux-musl)
racc (~> 1.4)
nokogiri (1.19.2-arm64-darwin)
racc (~> 1.4)
nokogiri (1.19.2-x86_64-darwin)
racc (~> 1.4)
nokogiri (1.19.2-x86_64-linux-gnu)
racc (~> 1.4)
nokogiri (1.19.2-x86_64-linux-musl)
racc (~> 1.4)
pathutil (0.16.2)
forwardable-extended (~> 2.6)
public_suffix (5.0.3)
racc (1.7.1)
rake (13.0.6)
public_suffix (7.0.5)
racc (1.8.1)
rake (13.4.2)
rb-fsevent (0.11.2)
rb-inotify (0.10.1)
rb-inotify (0.11.1)
ffi (~> 1.0)
rexml (3.2.6)
rouge (4.1.3)
rexml (3.4.4)
rouge (4.7.0)
safe_yaml (1.0.5)
sass-embedded (1.68.0)
google-protobuf (~> 3.23)
rake (>= 13.0.0)
sass-embedded (1.99.0-aarch64-linux-gnu)
google-protobuf (~> 4.31)
sass-embedded (1.99.0-aarch64-linux-musl)
google-protobuf (~> 4.31)
sass-embedded (1.99.0-arm-linux-gnueabihf)
google-protobuf (~> 4.31)
sass-embedded (1.99.0-arm-linux-musleabihf)
google-protobuf (~> 4.31)
sass-embedded (1.99.0-arm64-darwin)
google-protobuf (~> 4.31)
sass-embedded (1.99.0-x86_64-darwin)
google-protobuf (~> 4.31)
sass-embedded (1.99.0-x86_64-linux-gnu)
google-protobuf (~> 4.31)
sass-embedded (1.99.0-x86_64-linux-musl)
google-protobuf (~> 4.31)
terminal-table (3.0.2)
unicode-display_width (>= 1.1.1, < 3)
unicode-display_width (2.5.0)
webrick (1.8.1)
unicode-display_width (2.6.0)
webrick (1.9.2)

PLATFORMS
ruby
aarch64-linux-gnu
aarch64-linux-musl
arm-linux-gnu
arm-linux-gnueabihf
arm-linux-musl
arm-linux-musleabihf
arm64-darwin
x86_64-darwin
x86_64-linux-gnu
x86_64-linux-musl

DEPENDENCIES
jekyll (~> 4.1)
Expand All @@ -84,4 +154,4 @@ DEPENDENCIES
webrick (~> 1.7)

BUNDLED WITH
2.2.22
2.6.9