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