From 9a6456e81e127e348b68dcc23011bf4a7c176960 Mon Sep 17 00:00:00 2001 From: Moritz Mazetti Date: Thu, 30 Jul 2026 15:26:40 +0200 Subject: [PATCH] feat: add Dependabot config with grouping and a five-day cooldown Groups updates per ecosystem so one upstream release does not arrive as three pull requests, with GitHub Actions kept separate because a workflow bump changes what runs in the release path and deserves its own review. Five-day cooldown on every ecosystem. This is a supply-chain control, not a convenience: most malicious npm and PyPI releases in recent memory were detected and yanked within hours, so waiting before adoption neutralises that class of attack without anyone needing to be watching at the right moment. Security updates are advisory-driven and ignore it. Follows webapp's existing convention -- multi-ecosystem-groups, per-update cooldown, `dependencies` label -- rather than inventing a second style. Corrects a mistake in my earlier work. I documented the cooldown as coming from the Renovate presets and warned against enabling Dependabot version updates alongside them. But Renovate is not installed on the organisation: there are zero Renovate pull requests across it, while Dependabot is actively opening them and webapp already ships a dependabot.yml. So the Renovate presets were describing a control that was not running, and the warning had it backwards. The presets stay, since they are valid and express the same policy for any consumer that does adopt Renovate, but README and SECURITY.md now state plainly that Dependabot is what runs here and that the presets require installing the Renovate app. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01CEdTd43qLEEE5qCsL1A7gW --- .github/dependabot.yml | 70 ++++++++++++++++++++++++++++++++++++++++++ CHANGELOG.md | 8 +++-- README.md | 22 +++++++++---- SECURITY.md | 19 ++++++++---- 4 files changed, 104 insertions(+), 15 deletions(-) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..b763555 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,70 @@ +# Dependabot version updates, grouped per ecosystem so one upstream release does not arrive as three +# pull requests. +# +# The five-day cooldown is a supply-chain control, not a convenience. Most malicious npm and PyPI +# releases in recent memory were detected and yanked within hours, so waiting before adopting a new +# version neutralises that class of attack without anyone needing to be watching at the right moment. +# Security updates are unaffected: Dependabot security PRs are driven by advisories and ignore this. +# +# Layout note: this repository publishes three packages, and each ecosystem's manifest sits where its +# packaging rules force it. composer.json and pyproject.toml are at the root; the npm package is in +# `js/`. See the README. + +version: 2 + +multi-ecosystem-groups: + # Everything that ends up in a published artefact or its lockfile. + packages: + schedule: + interval: weekly + # Kept separate because a workflow bump changes what runs in the release path, which deserves its own + # review rather than being batched with library updates. + github-actions: + schedule: + interval: weekly + +updates: + - package-ecosystem: npm + multi-ecosystem-group: packages + directory: /js + patterns: + - '*' + cooldown: + default-days: 5 + labels: + - dependencies + + - package-ecosystem: composer + multi-ecosystem-group: packages + directory: / + patterns: + - '*' + allow: + - dependency-type: all + cooldown: + default-days: 5 + labels: + - dependencies + + - package-ecosystem: pip + multi-ecosystem-group: packages + directory: / + patterns: + - '*' + cooldown: + default-days: 5 + labels: + - dependencies + + # Every action here is pinned to a full commit SHA, and a CI job fails the build if any is not. + # Dependabot understands SHA pins and bumps them with the version comment intact, which is the only + # sustainable way to keep pinned actions current. + - package-ecosystem: github-actions + multi-ecosystem-group: github-actions + directory: / + patterns: + - '*' + cooldown: + default-days: 5 + labels: + - dependencies diff --git a/CHANGELOG.md b/CHANGELOG.md index 202fb7d..753a717 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -83,9 +83,11 @@ ecosystems, so a malicious version would run in our CI and on developer machines builds install with `--ignore-scripts`. - CodeQL (JavaScript, Python, Actions), dependency review with a copyleft denylist, and a weekly OpenSSF Scorecard run. -- The Renovate base sets a five-day `minimumReleaseAge` cooldown. Most malicious releases are detected - and yanked within hours, so a cooldown neutralises that class of attack without anyone needing to be - watching at the right moment. +- A five-day dependency cooldown, applied by `.github/dependabot.yml` across npm, Composer, pip and + GitHub Actions, with updates grouped per ecosystem. Most malicious releases are detected and yanked + within hours, so a cooldown neutralises that class of attack without anyone needing to be watching at + the right moment. Security updates are advisory-driven and unaffected. The Renovate presets express + the same policy for consumers on Renovate. `SECURITY.md` documents the controls, the verification commands, and the known gaps — including that Composer has no artefact provenance mechanism, so the PHP package's integrity rests on repository diff --git a/README.md b/README.md index a29d79c..87b33c3 100644 --- a/README.md +++ b/README.md @@ -375,10 +375,20 @@ repos: --- -## Renovate +## Dependency updates -This repository is also the org-wide Renovate config, extended by name the same way the style presets -are. In a consuming repository's `renovate.json`: +This repository's own updates are handled by **Dependabot** (`.github/dependabot.yml`): grouped per +ecosystem, with a five-day cooldown on every one. The cooldown is a supply-chain control rather than a +convenience — see `SECURITY.md`. + +Note that Renovate is **not installed** on the organisation. Dependabot is what actually runs. The +presets below are for consumers that adopt Renovate, and express the same policy. + +## Renovate presets (optional) + +This repository also ships an org-wide Renovate config, extended by name the same way the style presets +are. Using it requires installing the Renovate GitHub App. In a consuming repository's +`renovate.json`: ```json { @@ -403,9 +413,9 @@ polyglot repository would otherwise get three pull requests for one upstream com Requires Renovate 38 or newer, which is when `matchPackageNames` gained glob support. -**Do not also enable Dependabot version updates.** Dependabot *security* updates are fine alongside -this and complement it: they only fire on advisories. A `dependabot.yml` with a `schedule` block, -though, means every bump arrives twice. +**Pick one tool per repository.** Dependabot *security* updates compose fine with Renovate, because +they only fire on advisories. Dependabot *version* updates do not: every bump would arrive twice. Our +repositories use Dependabot, so these presets are only relevant if that changes. --- diff --git a/SECURITY.md b/SECURITY.md index 7bf03b5..b82b938 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -92,12 +92,19 @@ Enforced through GitHub settings rather than files: ### Consuming a compromised upstream -The Renovate presets set a repository-wide `minimumReleaseAge` cooldown, so a dependency version stays -unadopted for several days after publication. Most malicious npm and PyPI releases in recent memory -were detected and yanked within hours; a cooldown converts that class of attack into a non-event -without needing anyone to be paying attention at the right moment. - -Linters and formatters additionally never automerge, at any update type. +`.github/dependabot.yml` sets a **five-day cooldown** on every ecosystem, so a dependency version stays +unadopted for five days after publication. Most malicious npm and PyPI releases in recent memory were +detected and yanked within hours; a cooldown converts that class of attack into a non-event without +needing anyone to be paying attention at the right moment. Security updates are unaffected — those are +advisory-driven and ignore the cooldown. + +Updates are grouped per ecosystem so one upstream release does not arrive as three pull requests, and +GitHub Actions are grouped separately: a workflow bump changes what runs in the release path and +deserves its own review. + +The Renovate presets this repository also ships (`default.json`, `renovate/*.json`) express the same +policy for consumers who use Renovate. They are **not active here** — Renovate is not installed on the +organisation, Dependabot is. ## Known gaps