Skip to content
Merged
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
87 changes: 81 additions & 6 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,88 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added
- **Security:** Expanded the Shai-Hulud 2.0 watch list to the complete set of 428 compromised packages, gated behind dashboard approval with automerge disabled (updates stay enabled so fixed versions can still land) sourced directly from the official [Datadog IOC database](https://github.com/DataDog/indicators-of-compromise).
## [1.0.1] - 2026-08-23

### Fixed

- Stopped linking readers to a repository they cannot open. `dont-be-shy-hulud`
is not publicly reachable, and it was referenced five times β€” including in
`prBodyNotes`, so every pull request for a watch-listed package handed the
reader a dead link in place of a remediation step. Replaced with checks that
can be performed without it, including credential rotation.
- Documentation now names `github>` consistently. The English README recommended
`local>`, which resolves against the current forge and only pays off once the
preset is mirrored to each of them.

### Changed
- **Security:** Reordered `packageRules` in `default.json` to ensure the "Never automerge production dependencies" and the "SHAI-HULUD" gate rules are evaluated last, correctly overriding any prior permissive rules (such as dev-tooling whitelists).
- **Code Health:** Upgraded Biome configuration to the latest schema using `biome migrate`.
- **Code Health:** Formatted all JSON files in the repository to ensure consistency.

- Ecosystem table lists the managers actually configured, rather than naming
Biome, Oxlint and Vitest as if they were ecosystems.

### Added

- Czech README (`README-cs.md`), linked from the English one.

## [1.0.0] - 2026-08-23

First tagged release. Renamed from `renovate-config` to `supply-chain`: the old
name described the tool, not the job.

### Fixed
- Fixed a logic bug where generic automerge rules could have potentially applied to production dependencies due to sequential evaluation in Renovate.

Four faults, all live, none findable by reading the documentation:

- **The 7-day npm floor never applied.** `security:minimumReleaseAgeNpm` sets
3 days through a `packageRule`, and a `packageRule` outranks the top-level
value. npm ran on a 3-day floor while the README promised 7.
- **`^jest` matched an unowned namespace.** Unanchored, it matched every
`jest-*` package on npm β€” a prefix anyone can publish into β€” and those
automerged with the trust intended for Jest. Same for `^vitest` and
`^oxlint`.
- **`lockFileMaintenance` bypassed the age gate entirely** and automerged.
Renovate excludes it from `minimumReleaseAge`, along with `pin`,
`lockfileUpdate`, `rollback`, `bump` and `replacement`.
- **`pnpm` and `yarn` are not managers.** The `npm` manager handles all three
lockfiles. `bun` is separate and was missing from the pinning rule, so
bun-only repos got no version pinning at all.

Also fixed: GitHub Actions automerged majors and bare digest moves, the
per-tool rules re-granted automerge after the anchored trust list, and command
injection in the `setup-owner` workflow.

### Added

- Sub-presets: `:lockdown`, `:no-automerge`, `:aggressive`. Previously copy-paste
examples, now referenceable directly.
- Ecosystem coverage: Rust, Go, Python, JVM, .NET, PHP, Ruby, Dart, Swift,
Kubernetes and Deno alongside the JS ecosystems, Nix, Terraform, Ansible and
Docker.
- CI validation with `renovate-config-validator --strict`, and
`tooling/validate.sh` so the same check runs locally. It caught a real error
in one of the fixes above.
- Shai-Hulud 2.0 watch list expanded to 428 packages from the
[Datadog IOC database](https://github.com/DataDog/indicators-of-compromise).
Gated behind dashboard approval with automerge off; updates stay enabled so
fixed versions can still land.

### Changed

- Grouping is universal. The non-major group carried a manager allowlist, so
any ecosystem not named in it got a separate pull request per dependency.
- `packageRules` reordered so "never automerge production dependencies" and the
Shai-Hulud gate evaluate last, overriding the permissive rules above them.
- Migrated deprecated configuration: `npm:unpublishSafe` β†’
`security:minimumReleaseAgeNpm`, dropped `stabilityDays` and
`transitiveRemediation`, `matchPackagePatterns` β†’ `matchPackageNames`.

### Known limitations

- `renovate-config-validator` does not validate manager names.
`matchManagers: ["npm", "pnpm", "yarn"]` passes clean and matches nothing.
The gate covers schema, not semantics.
- Renovate has a hosted app on GitHub.com only. Every other forge needs it
self-hosted.

[Unreleased]: https://github.com/ownctrl/supply-chain/compare/v1.0.1...HEAD
[1.0.1]: https://github.com/ownctrl/supply-chain/compare/v1.0.0...v1.0.1
[1.0.0]: https://github.com/ownctrl/supply-chain/releases/tag/v1.0.0
5 changes: 2 additions & 3 deletions README-cs.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ s tΓ­m, ΕΎe se libovolnΓ‘ zΓ‘vislost mΕ―ΕΎe mezi dvΔ›ma vydΓ‘nΓ­mi obrΓ‘tit prot
a udΔ›lej z toho review mΓ­sto merge.

Seznam kompromitovanΓ½ch balíčkΕ― se poΕ™Γ‘d dodΓ‘vΓ‘, s podmΓ­nkou schvΓ‘lenΓ­
v dashboardu. Detekci a nΓ‘pravu Ε™eΕ‘Γ­
[dont-be-shy-hulud](https://github.com/miccy/dont-be-shy-hulud).
v dashboardu. ZasaΕΎenΓ© rozsahy verzΓ­ jsou v
[databΓ‘zi IOC od Datadogu](https://github.com/DataDog/indicators-of-compromise/tree/main/shai-hulud-2.0).

## Jak to pouΕΎΓ­t

Expand Down Expand Up @@ -173,6 +173,5 @@ Fork znamenÑ opravit každou bezpečnostní vadu tolikrÑt, kolik mÑő kopií.

## Odkazy

- πŸͺ± [dont-be-shy-hulud](https://github.com/miccy/dont-be-shy-hulud) β€” detekce a nΓ‘prava Shai-Hulud 2.0
- πŸ”’ [Socket.dev](https://socket.dev) β€” skenovΓ‘nΓ­ supply chain
- πŸ“Š [Datadog IOC](https://github.com/DataDog/indicators-of-compromise/tree/main/shai-hulud-2.0) β€” oficiΓ‘lnΓ­ IOC seznam
76 changes: 43 additions & 33 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ scope. It prompted the first version and the 428-package watch list, but the
policy here is general: assume any dependency can turn hostile between one
release and the next, and make the blast radius a review instead of a merge.

The watch list still ships, gated behind dashboard approval. See
[dont-be-shy-hulud](https://github.com/miccy/dont-be-shy-hulud) for detection
and remediation.
The watch list still ships, gated behind dashboard approval. Affected
version ranges are published in the
[Datadog IOC database](https://github.com/DataDog/indicators-of-compromise/tree/main/shai-hulud-2.0).

## Shared preset

Expand Down Expand Up @@ -69,16 +69,26 @@ and remediation.

<div align="center">

| Category | Technologies |
| ------------------- | ------------------------------------ |
| **JavaScript/Node** | npm β€’ pnpm β€’ yarn β€’ Bun β€’ Deno |
| **Systems** | Rust (cargo) |
| **System & Infra** | Nix β€’ Terraform β€’ Ansible |
| **Containers** | Docker |
| **CI/CD** | GitHub Actions |
| **Languages** | TypeScript β€’ Python (pip) β€’ Go (mod) |
| **Linting** | Biome β€’ Oxlint |
| **Testing** | Vitest β€’ Jest |
| Category | Grouped as | Managers |
| --- | --- | --- |
| **JavaScript / TypeScript** | *(base)* | npm (covers npm, pnpm, yarn), bun, bun-version |
| **Deno** | Deno | deno |
| **Rust** | Rust | cargo |
| **Go** | Go | gomod |
| **Python** | Python | pip_requirements, pip-compile, poetry, pep621, pipenv, setup-cfg |
| **JVM** | JVM | gradle, gradle-wrapper, maven, maven-wrapper, sbt |
| **.NET** | .NET | nuget |
| **PHP** | PHP | composer |
| **Ruby** | Ruby | bundler |
| **Dart / Flutter** | Dart | pub |
| **Swift** | Swift | swift, cocoapods |
| **Infrastructure** | Nix / Terraform / Ansible | nix, terraform, ansible |
| **Containers** | Docker digests | docker |
| **Kubernetes** | Kubernetes | kubernetes, helmv3, helm-values, helm-requirements, helmfile, flux, argocd |
| **CI/CD** | CI: GitHub Actions | github-actions |

Anything not listed still gets updates β€” everything non-major groups into one
PR by default, and the rules above only split specific ecosystems back out.

</div>

Expand All @@ -87,7 +97,7 @@ and remediation.
Drop this file into a new repo and you are done:

```json
{ "extends": ["local>ownctrl/supply-chain"] }
{ "extends": ["github>ownctrl/supply-chain"] }
```

That is the whole setup. The preset carries the schedule, grouping, automerge
Expand Down Expand Up @@ -117,8 +127,7 @@ run is the part that differs, and only GitHub.com is free of setup:

This is a property of the Renovate ecosystem, not of this preset β€” you would
face it with any preset, or with none. Mirroring this repo to another forge is
about making `local>ownctrl/supply-chain` resolvable there; nothing runs on
the mirror itself.
about making the preset resolvable there; nothing runs on the mirror itself.

### What to expect on a fresh repo

Expand All @@ -135,18 +144,20 @@ That last point is the deliberate trade-off: production dependencies, lockfile
refreshes and bare digest moves are the paths a supply-chain attack travels, so
they are review-gated by design. Expect a handful of clicks a week, not zero.

### `local>` and why it is not `github>`
### `github>` and when to use `local>` instead

`github>` names the forge explicitly and is the right default today, because
GitHub is where this repo actually lives.

`local>` resolves against whichever forge Renovate is currently running on, so
the same line works on GitHub, GitLab, Codeberg and self-hosted Forgejo,
provided the preset repo is mirrored there under the same path. Use
`github>ownctrl/supply-chain` only if you want to pin to GitHub specifically
from another forge.
one line would work on GitHub, GitLab, Codeberg and self-hosted Forgejo alike β€”
but only once the preset is mirrored to each of them under the same path. It is
not, yet. Reach for `local>` when you maintain your own mirrored copy.

Pin a release if you do not want your policy to change under you:

```json
{ "extends": ["local>ownctrl/supply-chain#v1.0.0"] }
{ "extends": ["github>ownctrl/supply-chain#v1.0.0"] }
```

### Using it under your own account
Expand All @@ -157,7 +168,7 @@ once per copy:

```json
{
"extends": ["local>ownctrl/supply-chain"],
"extends": ["github>ownctrl/supply-chain"],
"labels": ["dependencies", "yourbrand"]
}
```
Expand Down Expand Up @@ -256,16 +267,16 @@ Each of these is a ready preset, not a snippet to copy. Reference it directly:

| Preset | Reference | What it changes |
| --- | --- | --- |
| base | `local>ownctrl/supply-chain` | the policy described above |
| lockdown | `local>ownctrl/supply-chain:lockdown` | nothing automerges, 14-day npm floor, every update waits for dashboard approval |
| no-automerge | `local>ownctrl/supply-chain:no-automerge` | automerge off, everything else unchanged |
| aggressive | `local>ownctrl/supply-chain:aggressive` | any time, no release-age floor, higher PR limit |
| base | `github>ownctrl/supply-chain` | the policy described above |
| lockdown | `github>ownctrl/supply-chain:lockdown` | nothing automerges, 14-day npm floor, every update waits for dashboard approval |
| no-automerge | `github>ownctrl/supply-chain:no-automerge` | automerge off, everything else unchanged |
| aggressive | `github>ownctrl/supply-chain:aggressive` | any time, no release-age floor, higher PR limit |

Reach for **lockdown** during an active supply-chain incident and **aggressive**
only when you are certain there is not one.

```json
{ "extends": ["local>ownctrl/supply-chain:lockdown"] }
{ "extends": ["github>ownctrl/supply-chain:lockdown"] }
```

Sub-presets extend the base themselves, so you do not list both.
Expand All @@ -276,7 +287,7 @@ For teams in different timezones:

```json
{
"extends": ["local>ownctrl/supply-chain"],
"extends": ["github>ownctrl/supply-chain"],
"timezone": "America/New_York",
"schedule": ["before 09:00 on monday"]
}
Expand All @@ -294,19 +305,18 @@ This preset includes warnings for packages affected by the Shai-Hulud 2.0 attack

Sourced from the Datadog IOC database. These are gated behind dashboard approval with a warning attached β€” not blocked, so fixed versions can still land.

For the complete list, see [dont-be-shy-hulud IOC database](https://github.com/miccy/dont-be-shy-hulud/blob/main/ioc/malicious-packages.json).
The full list lives in [`default.json`](./default.json). Affected version ranges are in the [Datadog IOC database](https://github.com/DataDog/indicators-of-compromise/tree/main/shai-hulud-2.0).

---

## Related Resources

- πŸͺ± [dont-be-shy-hulud](https://github.com/miccy/dont-be-shy-hulud) β€” Shai-Hulud 2.0 detection and remediation guide
- πŸ”’ [Socket.dev](https://socket.dev) β€” Supply chain security scanning
- πŸ“Š [Datadog IOCs](https://github.com/DataDog/indicators-of-compromise/tree/main/shai-hulud-2.0) β€” Official IOC list

---

<div align="center">
<p>πŸ›  Maintained by <a href="https://github.com/miccy">@miccy</a> with πŸ’™</p>
<p>Β© 2025 <a href="https://github.com/miccy">Miccy</a></p>
<p>Maintained by <a href="https://github.com/ownctrl">ownctrl</a></p>
<p>Β© 2025–2026 <a href="https://github.com/miccy">Miccy</a> Β· MIT</p>
</div>
5 changes: 3 additions & 2 deletions default.json
Original file line number Diff line number Diff line change
Expand Up @@ -667,8 +667,9 @@
"⚠️ **SECURITY WARNING**: This package was affected by the Shai-Hulud 2.0 supply chain attack (November 2025).",
"Before merging, verify:",
"- [ ] The version is from AFTER the malicious versions were removed",
"- [ ] Check [Datadog IOC list](https://github.com/DataDog/indicators-of-compromise/tree/main/shai-hulud-2.0) for affected versions",
"- [ ] Run `./scripts/detect.sh` from [dont-be-shy-hulud](https://github.com/miccy/dont-be-shy-hulud)"
"- [ ] Check the [Datadog IOC list](https://github.com/DataDog/indicators-of-compromise/tree/main/shai-hulud-2.0) for the affected version range",
"- [ ] Check your lockfile for the affected versions, including transitively",
"- [ ] Rotate any credential the package could have reached"
]
}
]
Expand Down
Loading