From 312e3b3d1f23aa6ea8638a3fc3be04b702cd7217 Mon Sep 17 00:00:00 2001 From: Ray Walker Date: Tue, 28 Jul 2026 22:36:38 +1000 Subject: [PATCH 1/3] chore(deps): pin pnpm release-age window, floor-pin advisory fixes (LAB-1020) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Renovate becomes the sole dependency-PR bot (Dependabot security-update PRs are disabled at the repo level; the alert feed stays on). pnpm's release-age quarantine is pinned to 1440 min — the pnpm 11 built-in default CI already runs — so the policy no longer moves silently with package-manager bumps. Floor-pins remediate the open high advisories that would red the security job on any PR: postcss (GHSA-r28c-9q8g-f849), brace-expansion 2.x/5.x (GHSA-3jxr-9vmj-r5cp, GHSA-mh99-v99m-4gvg), js-yaml (GHSA-52cp-r559-cp3m), sharp (GHSA-f88m-g3jw-g9cj), protobufjs (GHSA-j3f2-48v5-ccww). New floors are bounded to their current major so a lockfile refresh cannot jump majors. brace-expansion 2.1.3 (same-day security backport) enters via a version-scoped minimumReleaseAgeExclude; GHSA-mh99 is audit-ignored only for advisory-metadata lag — the fix is installed on every resolved line. --- CONTRIBUTING.md | 6 + pnpm-lock.yaml | 357 ++++++++++++++++++++++++-------------------- pnpm-workspace.yaml | 35 ++++- 3 files changed, 234 insertions(+), 164 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8e91865..551724f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -79,6 +79,12 @@ GitHub disables self-hosted runners for fork PRs by security policy. Our CI work 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. + +**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 picks mature versions automatically; you only hit the gate if the lockfile was generated by a tool that doesn't respect it. For a security backport that can't wait out the window, add a _version-scoped_ entry to `minimumReleaseAgeExclude` with a comment saying when it can be removed. + ## Reporting bugs vs security issues - **Bugs**: [open a GitHub issue](https://github.com/cachekit-io/cachekit-ts/issues/new) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 633f63a..464e27b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,13 +5,17 @@ settings: excludeLinksFromLockfile: false overrides: - protobufjs: '>=7.5.8' + protobufjs: '>=7.6.5 <8' vite: '>=8.0.5' lodash: '>=4.18.0' flatted: '>=3.4.2' picomatch: '>=4.0.4' yaml: '>=2.8.3' - postcss: '>=8.5.14' + postcss: '>=8.5.18' + brace-expansion@2: '>=2.1.3 <3' + brace-expansion@5: '>=5.0.8' + js-yaml: '>=4.3.0 <5' + sharp: '>=0.35.0' importers: @@ -59,7 +63,7 @@ importers: devDependencies: '@cloudflare/vitest-pool-workers': specifier: 0.18.7 - version: 0.18.7(@vitest/runner@4.1.9)(@vitest/snapshot@4.1.9)(vitest@4.1.9) + version: 0.18.7(@types/node@25.9.4)(@vitest/runner@4.1.9)(@vitest/snapshot@4.1.9)(vitest@4.1.9) '@testcontainers/redis': specifier: ^11.13.0 version: 11.14.0 @@ -430,152 +434,161 @@ packages: resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} engines: {node: '>=18'} - '@img/sharp-darwin-arm64@0.34.5': - resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-darwin-arm64@0.35.3': + resolution: {integrity: sha512-RMnFX7YQsMoh7lWfcM4NEHHymBX/rLuKNPVM84XE9ONPcaSCDgE7CHIHpSgPcO2xcRthgBy1HfNO319mwhIAkg==} + engines: {node: '>=20.9.0'} cpu: [arm64] os: [darwin] - '@img/sharp-darwin-x64@0.34.5': - resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-darwin-x64@0.35.3': + resolution: {integrity: sha512-Xo+5uFBtLN0BKqieTxiFzFPQAUlBbbH5iBKyRX/z1JrbnYsHTfKJnUfL8+p2TPXr1pXqao4eeL4Rl144uDpK9w==} + engines: {node: '>=20.9.0'} cpu: [x64] os: [darwin] - '@img/sharp-libvips-darwin-arm64@1.2.4': - resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} + '@img/sharp-freebsd-wasm32@0.35.3': + resolution: {integrity: sha512-lUxcqWIj2wMQ9BrwNjngcr1gWUr5xgaGThBRqPPalIC2n67Cqj1uPh8NnA/ZhAg8hUbKl+kVHKwgUIwe6ZYPrg==} + engines: {node: '>=20.9.0'} + os: [freebsd] + + '@img/sharp-libvips-darwin-arm64@1.3.2': + resolution: {integrity: sha512-9J6ypZFpQBj4YnePGoq/S38w6nz+vqg5WZLrLGY4YuSemdMq47GMLBPO42MzwdGwpg/agZ7xzZcFHa48xlywfg==} cpu: [arm64] os: [darwin] - '@img/sharp-libvips-darwin-x64@1.2.4': - resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} + '@img/sharp-libvips-darwin-x64@1.3.2': + resolution: {integrity: sha512-m2pW1n6cns9VaubNwsZ+c3CRYjxNQWgJ5gPlnL1nbBcpkBvFm6SCFN5o0psFHI8w9n11NKhFkeEDns98tiqbEw==} cpu: [x64] os: [darwin] - '@img/sharp-libvips-linux-arm64@1.2.4': - resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} + '@img/sharp-libvips-linux-arm64@1.3.2': + resolution: {integrity: sha512-dqVSFynCox4C/J8kT16V7SIFAns0IjgLwkvYT7p8LQVmJ5OS5b6tI9IGflxTeuBS//zXeFIUbwt5dwxyZ17cnA==} cpu: [arm64] os: [linux] libc: [glibc] - '@img/sharp-libvips-linux-arm@1.2.4': - resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} + '@img/sharp-libvips-linux-arm@1.3.2': + resolution: {integrity: sha512-1eMLzy92I4J6rmi4mAT8yC3HxOtniyGELlzGbNMLLeqe052ahFQ0h6LFq+lh5DsDIdYViIDst08abvSbcEdLXQ==} cpu: [arm] os: [linux] libc: [glibc] - '@img/sharp-libvips-linux-ppc64@1.2.4': - resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} + '@img/sharp-libvips-linux-ppc64@1.3.2': + resolution: {integrity: sha512-3z0NHDxD6n5I9gc05U1eW1AyRm+Gznzq3naMrthPNqE6oYykcogW0l/jfpJdjYnuNl8R7yI9pNbE1XiUeyq0Aw==} cpu: [ppc64] os: [linux] libc: [glibc] - '@img/sharp-libvips-linux-riscv64@1.2.4': - resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} + '@img/sharp-libvips-linux-riscv64@1.3.2': + resolution: {integrity: sha512-bsb4rI+NldGOsXuej2r8OdSS8+zXDVaCWxyWrcv6kneTOlgAHtZABRzBBCwdsPiD90J4myNJuHpg6kA20ImW/w==} cpu: [riscv64] os: [linux] libc: [glibc] - '@img/sharp-libvips-linux-s390x@1.2.4': - resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} + '@img/sharp-libvips-linux-s390x@1.3.2': + resolution: {integrity: sha512-/ABshyj8gCpyIrNXnHn4LorDJ0HHm1VhXPBlxZ8zAtfVPAaSafXPGn+sUSIRiwaSBy0mmFjSjiXI5mkcwdChKQ==} cpu: [s390x] os: [linux] libc: [glibc] - '@img/sharp-libvips-linux-x64@1.2.4': - resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} + '@img/sharp-libvips-linux-x64@1.3.2': + resolution: {integrity: sha512-ITPEtgffGJ0S6G9dRyw/366tJQqFRcHWPHhC+Stpg3Z8AEMrDrTr2lhdz4f/Y/HMbRh//7Z5mBzEpVdi62Oc3w==} cpu: [x64] os: [linux] libc: [glibc] - '@img/sharp-libvips-linuxmusl-arm64@1.2.4': - resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} + '@img/sharp-libvips-linuxmusl-arm64@1.3.2': + resolution: {integrity: sha512-zE9EdiUzUmg5mDT5a1rk5fYJ6GWPloTwWBYDS14naqHsL+EaMpDj1AWnpLgh3u0YCORv2Tt50wrcrpYqkP97Kw==} cpu: [arm64] os: [linux] libc: [musl] - '@img/sharp-libvips-linuxmusl-x64@1.2.4': - resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} + '@img/sharp-libvips-linuxmusl-x64@1.3.2': + resolution: {integrity: sha512-m0lrLiUt+lBYnCFr8qV/65yMR4E/c7/wf78I5eKTdkEakFAlZ9QlzEM3QIhhAwVeUhLAHLcCq7a7Vszq/oFNZQ==} cpu: [x64] os: [linux] libc: [musl] - '@img/sharp-linux-arm64@0.34.5': - resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linux-arm64@0.35.3': + resolution: {integrity: sha512-QgKDspHPnrU+GQ55XPhGwyhC8acLVOOSyAvo1oVfFmrIXLkDNmGWzAfDZ4xK8oSA1qBQrALcHX0G5UZni/SuFQ==} + engines: {node: '>=20.9.0'} cpu: [arm64] os: [linux] libc: [glibc] - '@img/sharp-linux-arm@0.34.5': - resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linux-arm@0.35.3': + resolution: {integrity: sha512-affVWCTLooy8TSxbDx2qkzuDeaWLNVBA+P//FNBirHsXpP2fuBhk5AuboYUnrDnzoXes8GFjpTx0SBFOCRg+FA==} + engines: {node: '>=20.9.0'} cpu: [arm] os: [linux] libc: [glibc] - '@img/sharp-linux-ppc64@0.34.5': - resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linux-ppc64@0.35.3': + resolution: {integrity: sha512-sMd8rDxmpLOwv/7N44klFjOD5DUO7FLdjiXDI0hoxYaf7Ar262dQIEkosE98bps+5HPLtp/EvNqeqQtOycP/IA==} + engines: {node: '>=20.9.0'} cpu: [ppc64] os: [linux] libc: [glibc] - '@img/sharp-linux-riscv64@0.34.5': - resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linux-riscv64@0.35.3': + resolution: {integrity: sha512-0Eob78yjlYPfL5vMNWAW55l3R9Y6BQS/gOfe0ZcP9mEz9ohhKSt4im1hayiknXgf8AWrFqMvJcKIdmLmEe7yeQ==} + engines: {node: '>=20.9.0'} cpu: [riscv64] os: [linux] libc: [glibc] - '@img/sharp-linux-s390x@0.34.5': - resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linux-s390x@0.35.3': + resolution: {integrity: sha512-KgAxQ0DxpNOq1rG2t5cgTgShJFGSuU7XO45cqC+1NVOuZnP6tlgZRuSYOfNupGkHID0o3cJOsw4DVeJpMovcGw==} + engines: {node: '>=20.9.0'} cpu: [s390x] os: [linux] libc: [glibc] - '@img/sharp-linux-x64@0.34.5': - resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linux-x64@0.35.3': + resolution: {integrity: sha512-8pqvxubL2PGdhlPy6GLqzDYMUjyRmKAwKHYKixpdJYBUK7PJ0C029XdsnpFIdgRZG68fZiGdHVWcKPvtiPB4cA==} + engines: {node: '>=20.9.0'} cpu: [x64] os: [linux] libc: [glibc] - '@img/sharp-linuxmusl-arm64@0.34.5': - resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linuxmusl-arm64@0.35.3': + resolution: {integrity: sha512-Vz0iQjzzcSX3HCbfwFfCSG/9SCIqyO0mH2sXyiHaAYfBk0cRsCWXRyQYX0ovCK/PAQBbTzQ0dsPQHh5MAFL59w==} + engines: {node: '>=20.9.0'} cpu: [arm64] os: [linux] libc: [musl] - '@img/sharp-linuxmusl-x64@0.34.5': - resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linuxmusl-x64@0.35.3': + resolution: {integrity: sha512-6O1NPKcDVj9QEdg7Hx549EX8U0rp6yXQERqru6yRN7fGBn32UvIRJUlWnk+8xDCiG76hXVBbX82NZ/ZKr0euIg==} + engines: {node: '>=20.9.0'} cpu: [x64] os: [linux] libc: [musl] - '@img/sharp-wasm32@0.34.5': - resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-wasm32@0.35.3': + resolution: {integrity: sha512-cZ0XkcYGpHZkqW6iCkqTcmUC0CD9DhD5d/qeZlZkfRBn6GnHniZXLUo5+9xw8Iv76YE6LQFN9YNBlKREcCG76w==} + engines: {node: '>=20.9.0'} + + '@img/sharp-webcontainers-wasm32@0.35.3': + resolution: {integrity: sha512-2rnq7bX3NzeR2T4YWgz8qiG4h3TSdMe+vN1iQXpJleSJ3SM5zQ8Fy2SyyXAWlbxpEZ2Y+Z4u1BePgJEYbSy80Q==} + engines: {node: '>=20.9.0'} cpu: [wasm32] - '@img/sharp-win32-arm64@0.34.5': - resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-win32-arm64@0.35.3': + resolution: {integrity: sha512-4bPwFdMbeC4JQ8L8LOyWp6nsHcboP5fxkp6iPOXz2Vg49R42TuMs2whkJ5OAP4/Ul035qOzy0AecOF9VOscn4w==} + engines: {node: '>=20.9.0'} cpu: [arm64] os: [win32] - '@img/sharp-win32-ia32@0.34.5': - resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-win32-ia32@0.35.3': + resolution: {integrity: sha512-r53mXsBN6lFUDiST764SvgwUdHAqM4rPAiDzAmf4fLoB6X/rkfyTrLCg6+g17wJJiCmB3JYgHuUldCWUIRFSXw==} + engines: {node: ^20.9.0} cpu: [ia32] os: [win32] - '@img/sharp-win32-x64@0.34.5': - resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-win32-x64@0.35.3': + resolution: {integrity: sha512-D4y1vNeZrIIJCN+uHaWVtH86B+aCrdMYYjicy9pXHvbGZeGYLLSd3wdVuC37FxVXlU1ARsk84eKWfWMXGYEqvA==} + engines: {node: '>=20.9.0'} cpu: [x64] os: [win32] @@ -1617,12 +1630,12 @@ packages: blake3-wasm@2.1.5: resolution: {integrity: sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==} - brace-expansion@2.1.1: - resolution: {integrity: sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==} + brace-expansion@2.1.3: + resolution: {integrity: sha512-DRdx5neNsG/QXbniLFWi2YmC/68oeOOmKz6zOjVk6ZS1ZLXgLIKqVEc6hWsmkjBbgii0SwaBTcJ5XKj5gzY/4A==} - brace-expansion@5.0.6: - resolution: {integrity: sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==} - engines: {node: 18 || 20 || >=22} + brace-expansion@5.0.8: + resolution: {integrity: sha512-JZyDyq3D4AUifKTPOB7DELf6XsB3WdPuNxCtob1vFXPsSXhdAiHBWJ/tJ8HAc9aH84BK+5JFZLNkJKx3G9kzQg==} + engines: {node: 20 || >=22} buffer-crc32@1.0.0: resolution: {integrity: sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==} @@ -2007,8 +2020,8 @@ packages: js-tokens@10.0.0: resolution: {integrity: sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==} - js-yaml@4.2.0: - resolution: {integrity: sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==} + js-yaml@4.3.0: + resolution: {integrity: sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==} hasBin: true json-buffer@3.0.1: @@ -2181,8 +2194,8 @@ packages: nan@2.28.0: resolution: {integrity: sha512-fTsDz99OTq2sVePhGdp4qQhggZFtKr64ZNVyVajRKtMOkJxYekplBh577PiJB12v/D3s2E5cGtOI45LWp6rnLQ==} - nanoid@3.3.15: - resolution: {integrity: sha512-y7Wygv/7mEOvxTuEQDB8StXdMRBWf1kR/tlhAzBRUFkB2jfcLOAxO/SHmOO2zgz1pVgK29/kyupn059/bCHdjA==} + nanoid@3.3.16: + resolution: {integrity: sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true @@ -2240,8 +2253,8 @@ packages: resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} engines: {node: '>=12'} - postcss@8.5.15: - resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==} + postcss@8.5.23: + resolution: {integrity: sha512-g50586zr4bZmwFiTlflMu8E0bDTb5I5gertgwAKmsdUlTQIhZtunzUlD1WSzwcVWPoAVpsrA6vlfCD7oXvRwgg==} engines: {node: ^10 || ^12 || >=14} prelude-ls@1.2.1: @@ -2271,8 +2284,8 @@ packages: resolution: {integrity: sha512-WPn+h9RGEExOKdu4bsF4HksG/uzd3cFq3MFtq8PsFeExPse5Ha/VOjQNyHhjboBFwGXGev6muJYTSPAOkROq2g==} engines: {node: '>=18'} - protobufjs@7.6.4: - resolution: {integrity: sha512-RJJPTTpvFfHcWLkIa2JFWK4XvtSzS0yEWDmunqHXli1h3JlkbcQZXDZdcWxv+JK3Xsl5/UFDPZ0iGm7DAengYw==} + protobufjs@7.6.5: + resolution: {integrity: sha512-/FPD0nUc9jH6rfFjji9IBqOz4pcSE3CsT1m7Ep6Mdb0LxSUMj8hgl6GomOvZzpNpAqqGaXA0P3VSrZLFzIhQrw==} engines: {node: '>=12.0.0'} pump@3.0.4: @@ -2331,9 +2344,14 @@ packages: engines: {node: '>=10'} hasBin: true - sharp@0.34.5: - resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + sharp@0.35.3: + resolution: {integrity: sha512-ej0zVHuZGHCiABXcNxeYhpRnPNPAcvbG8RMdBAhDAxLKkCRVSpK3Iyu7qbqw3JMzoj0REeM6f3tJLtVwl0023Q==} + engines: {node: '>=20.9.0'} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} @@ -2712,18 +2730,19 @@ snapshots: optionalDependencies: workerd: 1.20260721.1 - '@cloudflare/vitest-pool-workers@0.18.7(@vitest/runner@4.1.9)(@vitest/snapshot@4.1.9)(vitest@4.1.9)': + '@cloudflare/vitest-pool-workers@0.18.7(@types/node@25.9.4)(@vitest/runner@4.1.9)(@vitest/snapshot@4.1.9)(vitest@4.1.9)': dependencies: '@vitest/runner': 4.1.9 '@vitest/snapshot': 4.1.9 cjs-module-lexer: 1.2.3 esbuild: 0.28.1 - miniflare: 4.20260721.0 + miniflare: 4.20260721.0(@types/node@25.9.4) vitest: 4.1.9(@opentelemetry/api@1.9.1)(@types/node@25.9.4)(@vitest/coverage-v8@4.1.9)(vite@8.1.0(@types/node@25.9.4)(esbuild@0.28.1)(yaml@2.9.0)) - wrangler: 4.113.0 + wrangler: 4.113.0(@types/node@25.9.4) zod: 3.25.76 transitivePeerDependencies: - '@cloudflare/workers-types' + - '@types/node' - bufferutil - utf-8-validate @@ -2883,14 +2902,14 @@ snapshots: dependencies: lodash.camelcase: 4.3.0 long: 5.3.2 - protobufjs: 7.6.4 + protobufjs: 7.6.5 yargs: 17.7.3 '@grpc/proto-loader@0.8.1': dependencies: lodash.camelcase: 4.3.0 long: 5.3.2 - protobufjs: 7.6.4 + protobufjs: 7.6.5 yargs: 17.7.3 '@humanfs/core@0.19.2': @@ -2911,98 +2930,108 @@ snapshots: '@img/colour@1.1.0': {} - '@img/sharp-darwin-arm64@0.34.5': + '@img/sharp-darwin-arm64@0.35.3': optionalDependencies: - '@img/sharp-libvips-darwin-arm64': 1.2.4 + '@img/sharp-libvips-darwin-arm64': 1.3.2 optional: true - '@img/sharp-darwin-x64@0.34.5': + '@img/sharp-darwin-x64@0.35.3': optionalDependencies: - '@img/sharp-libvips-darwin-x64': 1.2.4 + '@img/sharp-libvips-darwin-x64': 1.3.2 + optional: true + + '@img/sharp-freebsd-wasm32@0.35.3': + dependencies: + '@img/sharp-wasm32': 0.35.3 optional: true - '@img/sharp-libvips-darwin-arm64@1.2.4': + '@img/sharp-libvips-darwin-arm64@1.3.2': optional: true - '@img/sharp-libvips-darwin-x64@1.2.4': + '@img/sharp-libvips-darwin-x64@1.3.2': optional: true - '@img/sharp-libvips-linux-arm64@1.2.4': + '@img/sharp-libvips-linux-arm64@1.3.2': optional: true - '@img/sharp-libvips-linux-arm@1.2.4': + '@img/sharp-libvips-linux-arm@1.3.2': optional: true - '@img/sharp-libvips-linux-ppc64@1.2.4': + '@img/sharp-libvips-linux-ppc64@1.3.2': optional: true - '@img/sharp-libvips-linux-riscv64@1.2.4': + '@img/sharp-libvips-linux-riscv64@1.3.2': optional: true - '@img/sharp-libvips-linux-s390x@1.2.4': + '@img/sharp-libvips-linux-s390x@1.3.2': optional: true - '@img/sharp-libvips-linux-x64@1.2.4': + '@img/sharp-libvips-linux-x64@1.3.2': optional: true - '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + '@img/sharp-libvips-linuxmusl-arm64@1.3.2': optional: true - '@img/sharp-libvips-linuxmusl-x64@1.2.4': + '@img/sharp-libvips-linuxmusl-x64@1.3.2': optional: true - '@img/sharp-linux-arm64@0.34.5': + '@img/sharp-linux-arm64@0.35.3': optionalDependencies: - '@img/sharp-libvips-linux-arm64': 1.2.4 + '@img/sharp-libvips-linux-arm64': 1.3.2 optional: true - '@img/sharp-linux-arm@0.34.5': + '@img/sharp-linux-arm@0.35.3': optionalDependencies: - '@img/sharp-libvips-linux-arm': 1.2.4 + '@img/sharp-libvips-linux-arm': 1.3.2 optional: true - '@img/sharp-linux-ppc64@0.34.5': + '@img/sharp-linux-ppc64@0.35.3': optionalDependencies: - '@img/sharp-libvips-linux-ppc64': 1.2.4 + '@img/sharp-libvips-linux-ppc64': 1.3.2 optional: true - '@img/sharp-linux-riscv64@0.34.5': + '@img/sharp-linux-riscv64@0.35.3': optionalDependencies: - '@img/sharp-libvips-linux-riscv64': 1.2.4 + '@img/sharp-libvips-linux-riscv64': 1.3.2 optional: true - '@img/sharp-linux-s390x@0.34.5': + '@img/sharp-linux-s390x@0.35.3': optionalDependencies: - '@img/sharp-libvips-linux-s390x': 1.2.4 + '@img/sharp-libvips-linux-s390x': 1.3.2 optional: true - '@img/sharp-linux-x64@0.34.5': + '@img/sharp-linux-x64@0.35.3': optionalDependencies: - '@img/sharp-libvips-linux-x64': 1.2.4 + '@img/sharp-libvips-linux-x64': 1.3.2 optional: true - '@img/sharp-linuxmusl-arm64@0.34.5': + '@img/sharp-linuxmusl-arm64@0.35.3': optionalDependencies: - '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.3.2 optional: true - '@img/sharp-linuxmusl-x64@0.34.5': + '@img/sharp-linuxmusl-x64@0.35.3': optionalDependencies: - '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + '@img/sharp-libvips-linuxmusl-x64': 1.3.2 optional: true - '@img/sharp-wasm32@0.34.5': + '@img/sharp-wasm32@0.35.3': dependencies: '@emnapi/runtime': 1.11.1 optional: true - '@img/sharp-win32-arm64@0.34.5': + '@img/sharp-webcontainers-wasm32@0.35.3': + dependencies: + '@img/sharp-wasm32': 0.35.3 + optional: true + + '@img/sharp-win32-arm64@0.35.3': optional: true - '@img/sharp-win32-ia32@0.34.5': + '@img/sharp-win32-ia32@0.35.3': optional: true - '@img/sharp-win32-x64@0.34.5': + '@img/sharp-win32-x64@0.35.3': optional: true '@inquirer/ansi@2.0.7': {} @@ -3169,7 +3198,7 @@ snapshots: colorette: 2.0.20 emnapi: 1.11.1 es-toolkit: 1.49.0 - js-yaml: 4.2.0 + js-yaml: 4.3.0 obug: 2.1.3 semver: 7.8.5 typanion: 3.14.0 @@ -3945,11 +3974,11 @@ snapshots: blake3-wasm@2.1.5: {} - brace-expansion@2.1.1: + brace-expansion@2.1.3: dependencies: balanced-match: 1.0.2 - brace-expansion@5.0.6: + brace-expansion@5.0.8: dependencies: balanced-match: 4.0.4 @@ -4064,7 +4093,7 @@ snapshots: '@grpc/grpc-js': 1.14.4 '@grpc/proto-loader': 0.7.15 docker-modem: 5.0.7 - protobufjs: 7.6.4 + protobufjs: 7.6.5 tar-fs: 2.1.4 uuid: 10.0.0 transitivePeerDependencies: @@ -4337,7 +4366,7 @@ snapshots: js-tokens@10.0.0: {} - js-yaml@4.2.0: + js-yaml@4.3.0: dependencies: argparse: 2.0.1 @@ -4441,29 +4470,30 @@ snapshots: memjs@1.3.2: {} - miniflare@4.20260721.0: + miniflare@4.20260721.0(@types/node@25.9.4): dependencies: '@cspotcode/source-map-support': 0.8.1 - sharp: 0.34.5 + sharp: 0.35.3(@types/node@25.9.4) undici: 7.28.0 workerd: 1.20260721.1 ws: 8.21.0 youch: 4.1.0-beta.10 transitivePeerDependencies: + - '@types/node' - bufferutil - utf-8-validate minimatch@10.2.5: dependencies: - brace-expansion: 5.0.6 + brace-expansion: 5.0.8 minimatch@5.1.9: dependencies: - brace-expansion: 2.1.1 + brace-expansion: 2.1.3 minimatch@9.0.9: dependencies: - brace-expansion: 2.1.1 + brace-expansion: 2.1.3 minipass@7.1.3: {} @@ -4478,7 +4508,7 @@ snapshots: nan@2.28.0: optional: true - nanoid@3.3.15: {} + nanoid@3.3.16: {} natural-compare@1.4.0: {} @@ -4526,9 +4556,9 @@ snapshots: picomatch@4.0.4: {} - postcss@8.5.15: + postcss@8.5.23: dependencies: - nanoid: 3.3.15 + nanoid: 3.3.16 picocolors: 1.1.1 source-map-js: 1.2.1 @@ -4558,7 +4588,7 @@ snapshots: transitivePeerDependencies: - supports-color - protobufjs@7.6.4: + protobufjs@7.6.5: dependencies: '@protobufjs/aspromise': 1.1.2 '@protobufjs/base64': 1.1.2 @@ -4646,36 +4676,38 @@ snapshots: semver@7.8.5: {} - sharp@0.34.5: + sharp@0.35.3(@types/node@25.9.4): dependencies: '@img/colour': 1.1.0 detect-libc: 2.1.2 semver: 7.8.5 optionalDependencies: - '@img/sharp-darwin-arm64': 0.34.5 - '@img/sharp-darwin-x64': 0.34.5 - '@img/sharp-libvips-darwin-arm64': 1.2.4 - '@img/sharp-libvips-darwin-x64': 1.2.4 - '@img/sharp-libvips-linux-arm': 1.2.4 - '@img/sharp-libvips-linux-arm64': 1.2.4 - '@img/sharp-libvips-linux-ppc64': 1.2.4 - '@img/sharp-libvips-linux-riscv64': 1.2.4 - '@img/sharp-libvips-linux-s390x': 1.2.4 - '@img/sharp-libvips-linux-x64': 1.2.4 - '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 - '@img/sharp-libvips-linuxmusl-x64': 1.2.4 - '@img/sharp-linux-arm': 0.34.5 - '@img/sharp-linux-arm64': 0.34.5 - '@img/sharp-linux-ppc64': 0.34.5 - '@img/sharp-linux-riscv64': 0.34.5 - '@img/sharp-linux-s390x': 0.34.5 - '@img/sharp-linux-x64': 0.34.5 - '@img/sharp-linuxmusl-arm64': 0.34.5 - '@img/sharp-linuxmusl-x64': 0.34.5 - '@img/sharp-wasm32': 0.34.5 - '@img/sharp-win32-arm64': 0.34.5 - '@img/sharp-win32-ia32': 0.34.5 - '@img/sharp-win32-x64': 0.34.5 + '@img/sharp-darwin-arm64': 0.35.3 + '@img/sharp-darwin-x64': 0.35.3 + '@img/sharp-freebsd-wasm32': 0.35.3 + '@img/sharp-libvips-darwin-arm64': 1.3.2 + '@img/sharp-libvips-darwin-x64': 1.3.2 + '@img/sharp-libvips-linux-arm': 1.3.2 + '@img/sharp-libvips-linux-arm64': 1.3.2 + '@img/sharp-libvips-linux-ppc64': 1.3.2 + '@img/sharp-libvips-linux-riscv64': 1.3.2 + '@img/sharp-libvips-linux-s390x': 1.3.2 + '@img/sharp-libvips-linux-x64': 1.3.2 + '@img/sharp-libvips-linuxmusl-arm64': 1.3.2 + '@img/sharp-libvips-linuxmusl-x64': 1.3.2 + '@img/sharp-linux-arm': 0.35.3 + '@img/sharp-linux-arm64': 0.35.3 + '@img/sharp-linux-ppc64': 0.35.3 + '@img/sharp-linux-riscv64': 0.35.3 + '@img/sharp-linux-s390x': 0.35.3 + '@img/sharp-linux-x64': 0.35.3 + '@img/sharp-linuxmusl-arm64': 0.35.3 + '@img/sharp-linuxmusl-x64': 0.35.3 + '@img/sharp-webcontainers-wasm32': 0.35.3 + '@img/sharp-win32-arm64': 0.35.3 + '@img/sharp-win32-ia32': 0.35.3 + '@img/sharp-win32-x64': 0.35.3 + '@types/node': 25.9.4 shebang-command@2.0.0: dependencies: @@ -4907,7 +4939,7 @@ snapshots: dependencies: lightningcss: 1.32.0 picomatch: 4.0.4 - postcss: 8.5.15 + postcss: 8.5.23 rolldown: 1.1.3 tinyglobby: 0.2.17 optionalDependencies: @@ -4964,19 +4996,20 @@ snapshots: '@cloudflare/workerd-linux-arm64': 1.20260721.1 '@cloudflare/workerd-windows-64': 1.20260721.1 - wrangler@4.113.0: + wrangler@4.113.0(@types/node@25.9.4): dependencies: '@cloudflare/kv-asset-handler': 0.5.0 '@cloudflare/unenv-preset': 2.16.1(unenv@2.0.0-rc.24)(workerd@1.20260721.1) blake3-wasm: 2.1.5 esbuild: 0.28.1 - miniflare: 4.20260721.0 + miniflare: 4.20260721.0(@types/node@25.9.4) path-to-regexp: 6.3.0 unenv: 2.0.0-rc.24 workerd: 1.20260721.1 optionalDependencies: fsevents: 2.3.3 transitivePeerDependencies: + - '@types/node' - bufferutil - utf-8-validate diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 7b99527..8ee7a79 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,6 +1,31 @@ packages: - 'packages/*' +# Release-age quarantine (minutes). 1440 = 24h, pnpm 11's built-in default — +# pinned so CI policy doesn't silently move when the package manager bumps. +# Applies at resolution (lockfile refresh skips younger versions) AND at +# `--frozen-lockfile` verification, regardless of which bot wrote the lockfile. +# Renovate's routine window is 5 days, so its PRs always clear this; a 0-day +# security PR may red for up to 24h — accepted, rebase after the window. +minimumReleaseAge: 1440 + +# Surgical quarantine bypass for a same-day security backport: brace-expansion +# 2.1.3 (published 2026-07-28) is the 2.x backport of the GHSA-mh99-v99m-4gvg +# fix. Version-scoped so future releases of the package still age-gate. +# Safe to delete after 2026-07-29, when 2.1.3 clears the 24h window on its own. +minimumReleaseAgeExclude: + - 'brace-expansion@2.1.3' + +# GHSA-mh99-v99m-4gvg's advisory data claims vulnerable <=5.0.7 / patched +# 5.0.8 only — a range that swallows the whole 2.x line and does not yet +# reflect the 2.x backport (2.1.3, published 2026-07-28) we install above. +# Every resolved brace-expansion carries the fix (2.1.3 / 5.0.8); this ignore +# covers pure advisory-metadata lag, not an unpatched vulnerability. +# Remove once the advisory lists a patched 2.x version (audit then passes bare). +auditConfig: + ignoreGhsas: + - GHSA-mh99-v99m-4gvg + # pnpm v11 no longer reads the "pnpm" field in package.json; these settings # moved here. allowBuilds replaces onlyBuiltDependencies — same allowlist, # unlisted packages stay default-denied (ERR_PNPM_IGNORED_BUILDS). @@ -17,11 +42,17 @@ 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. overrides: - protobufjs: '>=7.5.8' + protobufjs: '>=7.6.5 <8' # GHSA-j3f2-48v5-ccww vite: '>=8.0.5' lodash: '>=4.18.0' flatted: '>=3.4.2' picomatch: '>=4.0.4' yaml: '>=2.8.3' - postcss: '>=8.5.14' + postcss: '>=8.5.18' # GHSA-r28c-9q8g-f849 + 'brace-expansion@2': '>=2.1.3 <3' # GHSA-3jxr-9vmj-r5cp + GHSA-mh99 2.x backport + 'brace-expansion@5': '>=5.0.8' # GHSA-3jxr + 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) From 5d6c19aa567d574cf0db5296a119aa5bfccb076c Mon Sep 17 00:00:00 2001 From: Ray Walker Date: Tue, 28 Jul 2026 22:48:06 +1000 Subject: [PATCH 2/3] chore(deps): tighten policy comments per expert-panel review (LAB-1020) - ignoreGhsas: document the graph-wide safety invariant (only valid while the brace-expansion floor-pins exist and only 2.x/5.x lines resolve) and add a hard re-evaluation date. - Correct the exclude removal date (window clears 2026-07-29 ~10:17 UTC, so deletable from 2026-07-30). - Full GHSA ids in override comments (grep-ability); point the 5-day Renovate window claim at its owning repo. --- pnpm-workspace.yaml | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 8ee7a79..5a016c1 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -5,23 +5,28 @@ packages: # pinned so CI policy doesn't silently move when the package manager bumps. # Applies at resolution (lockfile refresh skips younger versions) AND at # `--frozen-lockfile` verification, regardless of which bot wrote the lockfile. -# Renovate's routine window is 5 days, so its PRs always clear this; a 0-day -# security PR may red for up to 24h — accepted, rebase after the window. +# Renovate's routine window is 5 days (set in cachekit-io/renovate-config), so +# its PRs always clear this; a 0-day security PR may red for up to 24h — +# accepted, rebase after the window. minimumReleaseAge: 1440 # Surgical quarantine bypass for a same-day security backport: brace-expansion # 2.1.3 (published 2026-07-28) is the 2.x backport of the GHSA-mh99-v99m-4gvg # fix. Version-scoped so future releases of the package still age-gate. -# Safe to delete after 2026-07-29, when 2.1.3 clears the 24h window on its own. +# Safe to delete from 2026-07-30 (2.1.3 clears the window 2026-07-29 ~10:17 UTC). minimumReleaseAgeExclude: - 'brace-expansion@2.1.3' # GHSA-mh99-v99m-4gvg's advisory data claims vulnerable <=5.0.7 / patched # 5.0.8 only — a range that swallows the whole 2.x line and does not yet # reflect the 2.x backport (2.1.3, published 2026-07-28) we install above. -# Every resolved brace-expansion carries the fix (2.1.3 / 5.0.8); this ignore -# covers pure advisory-metadata lag, not an unpatched vulnerability. -# Remove once the advisory lists a patched 2.x version (audit then passes bare). +# This ignore covers pure advisory-metadata lag, not an unpatched vulnerability: +# the brace-expansion overrides below floor every resolved line at the fix. +# SAFETY INVARIANT: this ignore is graph-wide — it is safe ONLY while those +# overrides exist and only the 2.x/5.x lines resolve in the lockfile. If any +# other brace-expansion major ever appears (e.g. minimatch@3 pulling ^1.1.7), +# remove this ignore and re-justify. Remove once the advisory lists a patched +# 2.x version (audit then passes bare); re-evaluate by 2026-09-01 regardless. auditConfig: ignoreGhsas: - GHSA-mh99-v99m-4gvg @@ -52,7 +57,7 @@ overrides: picomatch: '>=4.0.4' yaml: '>=2.8.3' postcss: '>=8.5.18' # GHSA-r28c-9q8g-f849 - 'brace-expansion@2': '>=2.1.3 <3' # GHSA-3jxr-9vmj-r5cp + GHSA-mh99 2.x backport - 'brace-expansion@5': '>=5.0.8' # GHSA-3jxr + GHSA-mh99-v99m-4gvg + 'brace-expansion@2': '>=2.1.3 <3' # GHSA-3jxr-9vmj-r5cp + GHSA-mh99-v99m-4gvg 2.x backport + '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) From f80f7c7e762038f0e3f04f8769484c1c8cddb231 Mon Sep 17 00:00:00 2001 From: Ray Walker Date: Wed, 29 Jul 2026 00:19:05 +1000 Subject: [PATCH 3/3] ci(security): enforce the brace-expansion advisory-ignore invariant (LAB-1020) The graph-wide GHSA-mh99-v99m-4gvg ignore is sound only while every resolved brace-expansion sits on a floor-pinned 2.x/5.x line. That was documented as a SAFETY INVARIANT comment and enforced by nothing, so a transitive pulling a third major would have been silently un-audited by 'pnpm audit'. Add a security- job step that reads the resolved majors out of the lockfile and fails on any line outside 2/5, or on brace-expansion leaving the graph (dead ignore). The guard swallows grep's no-match exit deliberately: under pipefail it would otherwise abort the step with no output, reproducing the silent-failure shape this PR exists to remove. Verified against three lockfiles - real (pass), rogue 1.x injected (fail, names the major), absent (fail, names the dead config). Also correct CONTRIBUTING.md: the quarantine does not only bite tool-written lockfiles. A range whose every candidate is younger than the window has nothing legal to resolve to and errors locally too - which is the case that actually motivates minimumReleaseAgeExclude. --- .github/workflows/ci.yml | 25 +++++++++++++++++++++++++ CONTRIBUTING.md | 2 +- pnpm-workspace.yaml | 4 ++++ 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4b6cc6c..3d9371e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -145,6 +145,31 @@ jobs: - name: Install dependencies run: pnpm install --frozen-lockfile + # pnpm-workspace.yaml ignores GHSA-mh99-v99m-4gvg graph-wide (advisory + # metadata lags the 2.x backport). That is only sound while every resolved + # brace-expansion sits on a floor-pinned line — 2.x or 5.x. A third major + # would be silently un-audited by the step below, so fail here instead of + # letting the ignore suppress a real advisory. Enforces the SAFETY + # INVARIANT documented beside the ignore; delete both together. + - name: Verify brace-expansion advisory-ignore invariant + run: | + set -euo pipefail + # `|| true`: no match makes grep exit 1, which under pipefail would + # abort the step with no message. Let the empty case reach the + # explicit branch below so the failure explains itself. + majors=$(grep -oE '^ brace-expansion@[0-9]+\.' pnpm-lock.yaml \ + | sed -E 's#.*@([0-9]+)\.#\1#' | sort -u || true) + if [ -z "${majors}" ]; then + echo "::error::brace-expansion no longer resolves in pnpm-lock.yaml. The GHSA-mh99-v99m-4gvg ignore and its overrides in pnpm-workspace.yaml are now dead config — remove them." + exit 1 + fi + unexpected=$(printf '%s\n' "${majors}" | grep -vxE '2|5' || true) + if [ -n "${unexpected}" ]; then + echo "::error::brace-expansion major(s) outside the floor-pinned 2.x/5.x lines resolved: $(printf '%s' "${unexpected}" | tr '\n' ' '). The graph-wide GHSA-mh99-v99m-4gvg ignore in pnpm-workspace.yaml no longer holds — floor-pin the new line via overrides, or drop the ignore and re-justify." + exit 1 + fi + echo "brace-expansion majors resolved: $(printf '%s' "${majors}" | tr '\n' ' ')— invariant holds" + - name: Audit production dependencies (blocking) run: pnpm audit --prod --audit-level=high diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 551724f..4b3eb61 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -83,7 +83,7 @@ If you need stable, depend on a published version on npm. **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. -**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 picks mature versions automatically; you only hit the gate if the lockfile was generated by a tool that doesn't respect it. For a security backport that can't wait out the window, add a _version-scoped_ entry to `minimumReleaseAgeExclude` with a comment saying when it can be removed. +**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. ## Reporting bugs vs security issues diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 5a016c1..218f215 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -27,6 +27,10 @@ minimumReleaseAgeExclude: # other brace-expansion major ever appears (e.g. minimatch@3 pulling ^1.1.7), # remove this ignore and re-justify. Remove once the advisory lists a patched # 2.x version (audit then passes bare); re-evaluate by 2026-09-01 regardless. +# ENFORCED, not just documented: ci.yml's "Verify brace-expansion +# advisory-ignore invariant" step fails the security job if any other major +# resolves, or if brace-expansion leaves the graph entirely. Delete that step +# in the same commit that deletes this ignore. auditConfig: ignoreGhsas: - GHSA-mh99-v99m-4gvg