diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ae5da1..f55ee38 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/README-cs.md b/README-cs.md index 2397ffb..cdd524b 100644 --- a/README-cs.md +++ b/README-cs.md @@ -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 @@ -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 diff --git a/README.md b/README.md index c15897a..87f7588 100644 --- a/README.md +++ b/README.md @@ -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 @@ -69,16 +69,26 @@ and remediation.
-| 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.
@@ -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 @@ -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 @@ -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 @@ -157,7 +168,7 @@ once per copy: ```json { - "extends": ["local>ownctrl/supply-chain"], + "extends": ["github>ownctrl/supply-chain"], "labels": ["dependencies", "yourbrand"] } ``` @@ -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. @@ -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"] } @@ -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 ---
-

🛠 Maintained by @miccy with 💙

-

© 2025 Miccy

+

Maintained by ownctrl

+

© 2025–2026 Miccy · MIT

diff --git a/default.json b/default.json index 37661ba..735a572 100644 --- a/default.json +++ b/default.json @@ -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" ] } ]