From ee25df714b9cac6ffd4547cee670648b37afb0ef Mon Sep 17 00:00:00 2001 From: Miccy Date: Sun, 23 Aug 2026 02:49:17 +0200 Subject: [PATCH 1/3] =?UTF-8?q?=F0=9F=94=92=20fix:=20stop=20pointing=20rea?= =?UTF-8?q?ders=20at=20a=20repository=20they=20cannot=20open?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit dont-be-shy-hulud is not publicly reachable under either owner -- 404 from miccy and from ownctrl. This preset linked to it five times. The worst one was in default.json. Every Renovate PR for a watch-listed package told the reader to "Run ./scripts/detect.sh from dont-be-shy-hulud" and handed them a dead link -- a security instruction that could not be followed, in the one place someone was about to act on it. Replaced that step with checks a reader can actually perform: confirm the affected range against Datadog's IOC list, check the lockfile including transitively, and rotate whatever the package could have reached. The README references now point at the Datadog IOC database, which is public and already cited elsewhere in the file. Footer credits the org that now owns the repo, and the copyright range covers this year's work. --- README-cs.md | 5 ++--- README.md | 13 ++++++------- default.json | 5 +++-- 3 files changed, 11 insertions(+), 12 deletions(-) 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..8463163 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 @@ -294,19 +294,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" ] } ] From 3badc5335481631411c1af765bacd5b2a42a4c6c Mon Sep 17 00:00:00 2001 From: Miccy Date: Sun, 23 Aug 2026 02:53:30 +0200 Subject: [PATCH 2/3] =?UTF-8?q?=F0=9F=93=9D=20docs:=20fix=20what=20the=20R?= =?UTF-8?q?EADME=20and=20CHANGELOG=20got=20wrong?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three things found reviewing the public face of this repo after the transfer. The English README recommended local> throughout while the Czech one used github>. Two files in one repo contradicting each other, and the English one was recommending the form that pays off only once the preset is mirrored -- which it is not. Both now say github>, and the section on local> says when it becomes the right choice instead of implying it already is. The ecosystem table predated nine of the ecosystems this preset now groups, and listed Biome, Oxlint and Vitest as if they were ecosystems rather than packages the trust list names. It now lists the managers actually configured, and says what happens to anything not named. The CHANGELOG had everything under [Unreleased] with v1.0.0 already tagged, and carried a sentence left ungrammatical by an earlier edit. Rewritten with the 1.0.0 entry it should have had, including the known limitations a reader would otherwise discover the hard way. --- CHANGELOG.md | 84 ++++++++++++++++++++++++++++++++++++++++++++++++---- README.md | 63 +++++++++++++++++++++++---------------- 2 files changed, 115 insertions(+), 32 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ae5da1..1489c1d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,13 +7,85 @@ 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). +### 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.0...HEAD +[1.0.0]: https://github.com/ownctrl/supply-chain/releases/tag/v1.0.0 diff --git a/README.md b/README.md index 8463163..87f7588 100644 --- a/README.md +++ b/README.md @@ -69,16 +69,26 @@ version ranges are published in the
-| 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 @@ version ranges are published in the 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"] } From 76ed2c430482f301a98c3d44458238cc710ca304 Mon Sep 17 00:00:00 2001 From: Miccy Date: Sun, 23 Aug 2026 02:53:54 +0200 Subject: [PATCH 3/3] =?UTF-8?q?=F0=9F=93=9D=20docs:=20cut=20the=201.0.1=20?= =?UTF-8?q?entry?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1489c1d..f55ee38 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [1.0.1] - 2026-08-23 + ### Fixed - Stopped linking readers to a repository they cannot open. `dont-be-shy-hulud` @@ -87,5 +89,6 @@ injection in the `setup-owner` workflow. - 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.0...HEAD +[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