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
7 changes: 6 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -176,8 +176,13 @@ jobs:
# Production deps are the blocking gate (step above). Dev-only transitive
# advisories (e.g. tmp <0.2.6 path traversal, build-time tooling) are
# reported for visibility but must not block CI — they ship to no user.
# No --audit-level here on purpose: this step cannot fail the build, so a
# severity floor buys nothing and only hides findings. It used to inherit
# `high`, which is why the medium uuid advisory (GHSA-w5hq-g745-h8pq) was
# invisible to CI until someone read the Dependabot list by hand — and
# transitive advisories have no bot, so this step is the discovery lane.
- name: Audit all dependencies (non-blocking)
run: pnpm audit --audit-level=high
run: pnpm audit
continue-on-error: true

- name: Install cargo-audit
Expand Down
6 changes: 5 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,11 @@ If you need stable, depend on a published version on npm.

## Dependency updates

**Renovate is the only bot that opens dependency PRs here** (config: `renovate.json`, extending `cachekit-io/renovate-config`). It also handles vulnerability remediation for direct dependencies; vulnerable _transitives_ are floor-pinned via `overrides` in `pnpm-workspace.yaml`. Dependabot's security-update PRs are disabled — its _alert feed_ stays on and feeds Renovate.
**Renovate is the only bot that opens dependency PRs here** (config: `renovate.json`, extending `cachekit-io/renovate-config`). It also handles vulnerability remediation, but **only for dependencies that appear in a manifest** — `osvVulnerabilityAlerts` is documented as direct-dependencies-only, and Renovate removed transitive remediation outright in [renovatebot/renovate#27985](https://github.com/renovatebot/renovate/pull/27985).

**Vulnerable transitives have no bot.** Find them with `pnpm audit`, then floor-pin them in `overrides` in `pnpm-workspace.yaml` — bounded to the major of the version you pin, because an unbounded floor re-resolves into new majors. Maintainers additionally watch the repo's Dependabot alerts (that page needs write access, so `pnpm audit` is the check to run from a fork).

Two traps in that loop. Pinning hands the dependency _back_ to Renovate — an `overrides` entry reads as a manifest dep — but Renovate will also propose **widening** an upper bound across majors, as open PR #94 does to `brace-expansion@2`. An upper bound here is a deliberate decision; re-derive it before approving a bot PR that moves one. And Dependabot's _alert feed_, though still enabled, is not a Renovate input: as of 2026-07-30 the acting Renovate App lacks `vulnerability_alerts: read`, which is what the `Cannot access vulnerability alerts` warning on every Dependency Dashboard reports. Granting that scope would silence the warning and let Renovate prioritise advisories on deps it can already see — it would not produce transitive fix PRs, because that capability is gone upstream regardless.

**Release-age quarantine**: `pnpm-workspace.yaml` pins `minimumReleaseAge: 1440` (24 h). `pnpm install --frozen-lockfile` in CI rejects any lockfile entry younger than that — so a lockfile refresh that picks up a just-published version will fail CI until the release ages past the window. pnpm applies the same window when resolving, so a plain `pnpm install` on your machine normally picks mature versions automatically. Two cases still fail locally: a lockfile generated by a tool that ignores the window, and a range with **no** aged-in candidate at all — if every version satisfying a dependency (or an `overrides` floor) is younger than 24 h, resolution has nothing legal to pick and errors out rather than falling back. For a security backport that can't wait out the window — the usual cause of the second case — add a _version-scoped_ entry to `minimumReleaseAgeExclude` with a comment saying when it can be removed.

Expand Down
10 changes: 5 additions & 5 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 17 additions & 2 deletions pnpm-workspace.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,13 @@ allowBuilds:
sharp: false

# Security floor-pins for vulnerable transitives (formerly pnpm.overrides).
# Floors are bounded to their current major where a newer major exists —
# an unbounded floor re-resolves to the newest match, majors included.
# Floors are bounded to the major of the version they pin, where a newer major
# exists — an unbounded floor re-resolves to the newest match, majors included.
# Renovate takes these entries over once they exist (they read as manifest deps)
# but its idea of maintenance includes WIDENING the bound across majors: see the
# open PR #94, which proposes 'brace-expansion@2': '>=2.1.3 <3' -> '<6'. Review
# every bot PR that touches an upper bound here — a bound is a decision, not
# drift.
overrides:
protobufjs: '>=7.6.5 <8' # GHSA-j3f2-48v5-ccww
vite: '>=8.0.5'
Expand All @@ -65,3 +70,13 @@ overrides:
'brace-expansion@5': '>=5.0.8' # GHSA-3jxr-9vmj-r5cp + GHSA-mh99-v99m-4gvg
js-yaml: '>=4.3.0 <5' # GHSA-52cp-r559-cp3m
sharp: '>=0.35.0' # GHSA-f88m-g3jw-g9cj (build denied above; pin is belt+braces)
# GHSA-w5hq-g745-h8pq. Dev-only: testcontainers -> dockerode -> uuid, v4 only
# (alert #47 mislabels it runtime — it can't read pnpm-lock's dev partition).
# 11.1.1 is the advisory's lowest fix, and 10.0.0 is uuid's ONLY 10.x release
# (dockerode's declared range is ^10.0.0, which resolves to it), so there is
# no in-major fix and the forced major is unavoidable.
# <12 IS LOAD-BEARING: uuid >=12 dropped the
# `require` export condition and dockerode does `require("uuid").v4`, so
# widening breaks Node <22.12 — which engines allow (>=22.0.0) and CI, on
# 22-latest, would not catch. Lift only when dockerode moves off ^10.0.0.
Comment thread
coderabbitai[bot] marked this conversation as resolved.
uuid: '>=11.1.1 <12'