Keep Your Pins Fresh: Dependabot, Renovate and the UnJS Preset

2026-11-13来源 dev.to GitHubEnglish
Keep Your Pins Fresh: Dependabot, Renovate and the UnJS Preset

The problem

Pinning is the easy half of supply-chain hygiene. You replace actions/checkout@v4 with a 40-character commit SHA, commit your lockfiles, and your builds stop changing behind your back.

Then the other half arrives. A pinned dependency never updates itself, so six months later you're running actions with known vulnerabilities and nobody remembers what df4cb1c0… even is. Pinning without automation trades one risk for another.

The answer is a bot that opens pull requests for you: it updates the SHA and the version comment next to it, and waits a few days before proposing a brand-new release, so that a compromised version has time to be caught and pulled. Two bots do this well. Dependabot is built into GitHub. Renovate is the more configurable alternative, and the open-source UnJS organization publishes a shared Renovate preset that's worth reading line by line.

Dependabot for GitHub Actions

Dependabot needs one file, .github/dependabot.yml. For actions, three keys are mandatory: the ecosystem, the directory and a schedule.

version: 2 updates: - package-ecosystem: "github-actions" directory: "/" schedule: interval: "weekly" 

The directory value trips people up. It must be "/", not .github/workflows. With /, Dependabot searches /.github/workflows and the action.yml file in the repository root. It also keeps reusable workflows referenced from your workflows up to date.

That minimal file works, but a production setup wants three more things.

version: 2 updates: - package-ecosystem: "github-actions" directory: "/" schedule: interval: "weekly" cooldown: default-days: 7 groups: actions: patterns: ["*"] commit-message: prefix: "ci" - package-ecosystem: "npm" directory: "/" schedule: interval: "weekly" cooldown: default-days: 7 semver-major-days: 14 groups: non-major: update-types: ["minor", "patch"] 

Cooldown. This is the supply-chain setting. Dependabot now applies a default cooldown of three days to version updates even if you configure nothing, and cooldown lets you raise it. For GitHub Actions only default-days is supported; the per-semver keys (semver-major-days and friends) work for ecosystems like npm. The cooldown never delays security updates, which is exactly what you want: patches for known vulnerabilities arrive immediately, brand-new releases wait.

Groups. By default Dependabot opens one pull request per dependency. A group collapses them: one PR for all actions, one for all minor and patch npm updates. Fewer PRs means each one actually gets read.

Dependabot also works with SHA-pinned actions. When a workflow says @<sha> # v4.2.2, it updates the SHA and the version comment, as long as the comment sits on the same line.

Renovate: the configurable alternative

Renovate runs as a GitHub App. You install it from github.com/apps/renovate, pick the repositories, and it opens a "Configure Renovate" pull request containing a renovate.json. Nothing else happens until you merge that PR, so onboarding is risk-free.

A sensible starting config is a single line:

{ "$schema": "https://docs.renovatebot.com/renovate-schema.json", "extends": ["config:best-practices"] } 

Renovate is built around presets, named bundles of configuration you extend. config:recommended gives you the basics, including the Dependency Dashboard. config:best-practices adds the security layer on top:

  • helpers:pinGitHubActionDigests pins GitHub Actions to digests.
  • docker:pinDigests does the same for container images.
  • security:minimumReleaseAgeNpm waits until an npm package is three days old before raising the update.
  • :maintainLockFilesWeekly schedules weekly lockfile maintenance.

The cooldown setting is called minimumReleaseAge. Renovate waits that long for each separate version. Like Dependabot, it lets security updates skip the wait.

A real-world preset: unjs/renovate-config

Presets can live in any repository, which is how an organization shares one policy across all its projects. UnJS, the organization behind packages such as ofetch, consola and unstorage, keeps theirs in unjs/renovate-config. A project adopts it with one line:

{ "extends": ["github>unjs/renovate-config"] } 

The preset itself is a 50-line default.json, and it's a good template because every line reflects a decision.

{ "extends": [ "config:recommended", "docker:pinDigests", "helpers:pinGitHubActionDigests", ":configMigration", "abandonments:recommended", "security:minimumReleaseAgeNpm", ":maintainLockFilesWeekly", "group:allNonMajor", ":semanticCommitTypeAll(chore)" ], "minimumReleaseAge": "1 day", "rangeStrategy": "bump", "ignoreDeps": ["node"], "packageRules": [ { "matchManagers": ["github-actions"], "groupName": "github-actions", "schedule": ["after 2am and before 3am"] } ] } 

(Abridged: the full file also disables the Meteor manager and schedules minor and patch updates overnight with automerge turned off.)

What it tells you:

  • It's config:best-practices, spelled out. The first seven presets are the best-practices list minus :pinDevDependencies.
  • Actions are pinned by digest. The repository's own CI shows the result: actions/checkout@df4cb1c0… # v6.0.3.
  • A cooldown everywhere. minimumReleaseAge: "1 day" covers every ecosystem, and the npm preset raises it to three days for npm packages. The commit history shows it was added on 22 May 2026, the same day as a commit titled "add security best practices".
  • One PR for everything non-major. group:allNonMajor bundles minor and patch updates, and the package rule groups all GitHub Actions updates into a single nightly PR.
  • Automerge is off. The preset sets automerge: false for minor, patch, pin and digest updates.

The repository also validates itself: its CI runs renovate-config-validator on every push to main and every pull request, so a broken preset can't reach the repositories that extend it. Today that's 68 of the organization's 86 public repos.

Which one should you use?

Start with Dependabot if you want zero setup. It's already in GitHub, it has a cooldown by default, and one YAML file covers actions and packages. For a single repository or a small team it's enough.

Look at Renovate when you want a preset that pins actions and images to digests for you, one shared policy across many repositories, or the Dependency Dashboard. UnJS shows how far a single shared preset can go.

Whichever you pick, three rules carry over:

  1. Pin by SHA or digest, and let the bot keep the pin fresh.
  2. Set a cooldown of at least three days, longer for major versions.
  3. Group updates so the pull requests stay few enough to review properly.

Conclusion

Pinning protects you today; an update bot keeps you protected next month. Dependabot gets you there with one file, Renovate with one preset, and the UnJS config shows what a mature policy looks like: pinned digests, a cooldown, grouped pull requests and automerge turned off.

You can follow me on GitHub, where I'm creating cool projects.

I hope you enjoyed this article, until next time 👋

原文:https://www.a8q9.cn/en/article/keep-your-pins-fresh-dependabot-renovate-and-the-unjs-preset-19ae64.html

相关文章