Repository navigation
Commit b93c750
fix(deps): re-lock vitest and the @vitest/* family onto 4.1.12 for the two @vitest/mocker OSV advisories (#25164)
Fixes #25163
Clause-②: no
## What this does
`main`'s scheduled `Validate Dependencies` run 39714768704 (job
119614140669, `main` at `6b44efa7b4`) is red at its OSV step on two
Medium advisories in `@vitest/mocker` 4.1.11, and both name 4.1.12 as
the fix. 4.1.12 is the newest 4.1.x on npm (published 2026-10-15). Every
declared range on every path already admits it, so this is a **re-lock
only**. `pnpm-lock.yaml` is the whole diff: no override, no
`osv-scanner.toml` exemption, and no `package.json` range. `vitest` 5.x
is not touched.
| Package | Locked → resolved | Advisories | Path (`pnpm why -r`) | How
|
|:--|:--|:--|:--|:--|
| `@vitest/mocker` | 4.1.11 → **4.1.12** | GHSA-qxg6-89mg-rqv8 (CVSS
4.7), GHSA-xp26-3454-mjgp (CVSS 5.9) | exact dependency `4.1.11` of
`vitest@4.1.11`, 2 peer variations | re-lock |
| `vitest` | 4.1.11 → **4.1.12** | (carries the mocker) | direct
devDependency `^4.1.11` in 79 importers: 78 under one peer variation,
`@objectstack/account` under the other. Also the optional peer `^2.0.0
\|\| ^3.0.0 \|\| ^4.0.0 \|\| ^5.0.0` of `better-auth`,
`@better-auth/oauth-provider`, `@better-auth/scim` and
`@better-auth/sso` 1.7.12 | re-lock |
| `@vitest/coverage-v8` | 4.1.11 → **4.1.12** | none (peers `vitest`
exactly, so it moves with it) | direct devDependency `^4.1.11` in
`@objectstack/spec` | re-lock |
| `@vitest/expect`, `@vitest/pretty-format`, `@vitest/runner`,
`@vitest/snapshot`, `@vitest/spy`, `@vitest/utils` | 4.1.11 → **4.1.12**
| none (lockstep) | exact dependencies `4.1.11` of `vitest@4.1.11` |
re-lock |
No `@vitest/ui` or any other `@vitest/*` package is in the lockfile.
**The two `~4.0.0` declarations** are both in
`packages/create-objectstack/src/templates/blank/package.json`
(`devDependencies.vitest` and `overrides.vitest`). That file is a
scaffold template, not a workspace importer: it matches no
`pnpm-workspace.yaml` glob, the lockfile has no importer for it, and no
4.0.x `vitest` / `@vitest/*` entry is in the lockfile. They are left
alone. What they resolve to in a scaffolded project is in Acceptance
notes.
## The advisories, read from the OSV npm database
`api.osv.dev`, `api.github.com/advisories` and the
`github.com/advisories` pages all answer 403 from this container. The
two records were read instead from the OSV npm database archive
(`osv-vulnerabilities.storage.googleapis.com/npm/all.zip`, fetched
2026-10-22 03:17 UTC):
- **GHSA-qxg6-89mg-rqv8**, "Vitest: Code injection via unauthenticated
manual mock registration". `interceptorPlugin` accepts
`vitest:interceptor:register` events on Vite's dev-server WebSocket
without authentication, and `createManualModuleSource` interpolates the
mock's URL into generated module source without escaping. Affected: from
2.1.0-beta.7 up to the fix in 4.1.12, and from 5.0.0-beta.1 up to the
fix in 5.0.3.
- **GHSA-xp26-3454-mjgp**, "Windows backslash traversal bypasses the
@vitest/mocker redirect allowlist fix". This is a bypass of
GHSA-82fw-gwwq-j7x9's fix. Affected: exactly 4.1.11, and from 5.0.0-rc.2
up to the fix in 5.0.3.
**What 4.1.12 changes.** I diffed the published 4.1.11 and 4.1.12
tarballs of all nine family members:
- The only behavioural code change is the two fixes in
`@vitest/mocker`'s `dist`. `createManualModuleSource` now uses
`JSON.stringify` for the URL and the export names, and the redirect join
now applies a backslash-to-slash `slash()` to the pathname.
- `vitest` changes only its version string and two chunk-hash renames.
- `@vitest/coverage-v8` changes only its version string.
- `runner`, `expect`, `snapshot`, `spy`, `utils` and `pretty-format`
have 0 non-manifest diff lines.
- In the manifests, the only change other than the self-version is one
optional peer of `vitest`: `@vitest/browser-webdriverio` goes from
`4.1.11` to `^4.1.11`. That is the self-contradictory peer `d795719926`
measured against npm 10. It is optional and not installed in this
workspace, and pnpm prints no warning for it.
## How the lockfile was moved, and the route rejected first
- **Rejected: a targeted `pnpm update`.** I measured `pnpm update -r
--no-save vitest @vitest/coverage-v8`. It did reach 4.1.12 for all nine
members and moved no `package.json`. It also touched 29 package names
outside the family in `packages:` (24 replaced, 5 added), at +317/−284
lines:
- `@inquirer/ansi` / `confirm` / `core` / `type`, `seroval` 1.6.8 →
1.7.0, `seroval-plugins` 1.6.8 → 1.6.12, and `chai` 6.2.2 → 6.3.0;
- `rolldown` and its 15 bindings 1.2.14 → 1.2.15, and
`@oxc-project/types` 0.154.0 → 0.155.0;
- new copies of `@babel/runtime`, `ip-address`, `nanoid`, `postcss` and
`set-cookie-parser`;
- in `snapshots:`, rewritten `knex`, `tsup`, `postcss-load-config` and
`fumadocs-mdx` keys, and changed bodies on 7 same-key snapshots
(`@tanstack/router-core`, `@testing-library/dom`, `headers-polyfill`,
`msw`, `socks` and both `vite` 8.3.4 variations).
- This is the same churn #25047 measured for `pnpm update` in this
workspace, plus the `rolldown`, `@oxc-project/types` and `chai` moves.
- **Taken: the re-lock recipe of #21951 / #25047.**
- I added two temporary exact entries (`vitest: '4.1.12'`,
`'@vitest/coverage-v8': '4.1.12'`) to the `overrides` block of
`pnpm-workspace.yaml`, under an EXIT trap that restores the file, and
ran `pnpm install`.
- I then restored the file and ran `pnpm install` again. The second
install keeps the resolutions, because every declared range admits them.
- The restore is proven: `git hash-object pnpm-workspace.yaml` equals
the HEAD blob `d9b99fcddf13011318845269277987410889b7c0`, and `git diff
HEAD -- pnpm-workspace.yaml` is empty.
## Lockfile diff scope
`pnpm-lock.yaml` only, **+159/−159**. I compared the parsed lockfiles,
base `6b44efa7b4` against head `9ada86315f`:
- **`packages:`** 1340 → 1340 keys: 9 removed, 9 added, which are
exactly the nine family members 4.1.11 → 4.1.12. No same-key entry
changed.
- **`snapshots:`** 1347 → 1347 keys: 15 removed, 15 added.
- 11 are the family. `vitest` and `@vitest/mocker` each have two peer
variations, which differ only in `vite`'s `esbuild` 0.28.1 / 0.28.2
peer.
- 4 are `better-auth`, `@better-auth/oauth-provider`,
`@better-auth/scim` and `@better-auth/sso` 1.7.12. They rewrite only
their `vitest` peer suffix: `better-auth` 1.7.12 declares `vitest` as an
optional peer, and pnpm binds it to the workspace's copy.
- No same-key entry changed.
- **`importers:`** 85 → 85, 0 specifier moves.
- 79 `vitest` and 1 `@vitest/coverage-v8` version strings move to
4.1.12.
- The 4 `better-auth` version strings in `@objectstack/plugin-auth`
change only their peer suffix.
- **Unchanged:** `lockfileVersion` (9.0), `settings`, `overrides` and
`patchedDependencies`.
- Nothing outside the family moved, apart from the four peer-suffix
rewrites; `chai` stays at 6.2.2.
## Local proofs, at `9ada86315f`
| Proof | Exit | Reading |
|:--|:--|:--|
| `pnpm install --frozen-lockfile --prefer-offline` (the workflow's
lockfile step) | 0 | |
| `node scripts/check-changeset-fixed.mjs` | 0 | `"fixed" group is in
sync with 73 public workspace packages` |
| `pnpm check:override-consistency` (the published-manifest override
check) | 0 | `9 published-manifest declaration(s) covered by
pnpm-workspace.yaml overrides all resolve to their override targets` |
| `pnpm check:vendor-export-contract-resolve` | 0 | `VERDICT: PASS —
vendor export contract (registry resolution, installed with
npm@11.21.0), 3 edge(s) verified` |
| `node scripts/check-osv-exemptions.mjs --self-test` and the bare run |
0, 0 | `1 OSV exemption(s) … all carry an unexpired ignoreUntil within
90 days and a reason with an advisory link` |
| `node scripts/osv-base-relative.mjs --self-test` | 0 | `23 case(s),
all held (floor 23)` |
| `pnpm --filter @objectstack/spec build` (shared verify lock) | 0 |
`VERDICT command-exit 0` |
| `pnpm --filter @objectstack/formula test` (shared verify lock) | 0 |
`RUN v4.1.12`, 51 files / 1367 tests passed. Includes
`src/cel-env-reuse.test.ts`, which module-mocks `@marcbachmann/cel-js`
with `vi.mock(…, async (importOriginal) =>)`: `@vitest/mocker`'s path.
Resolved from the package: `vitest` 4.1.12, `@vitest/mocker` 4.1.12 |
| `pnpm --filter @objectstack/types test` (shared verify lock) | 0 |
`RUN v4.1.12`, 29 files / 774 tests passed |
| `@objectstack/spec`'s six `vi.mock` test files with `--coverage`
(provider v8, shared verify lock) | 0 | `RUN v4.1.12`, `Coverage enabled
with v8`, 6 files / 101 tests passed. This loads `@vitest/coverage-v8`
4.1.12 against its exact `vitest` 4.1.12 peer |
`pnpm install` prints `ioredis-mock 8.13.1: unmet peer ioredis@^5: found
6.0.0`. That warning is already on `main` and is not caused by this
diff.
## OSV reading
I measured with OSV-Scanner **2.5.0**, the binary the workflow's pinned
action image ships. Its sha256 `edcfc41d…524e0c` matches the release's
`SHA256SUMS`. `api.osv.dev` is refused by this container's egress proxy,
so the scans ran offline (`--offline-vulnerabilities
--download-offline-databases`) against the npm database downloaded
2026-10-22 03:24 UTC. Each side ran under its own `osv-scanner.toml`,
with the identical invocation.
- **Base `6b44efa7b4`: exit 1.** The 2 rows are the scheduled run's:
1340 packages, `@vitest/mocker` 4.1.11, fixed in 4.1.12, CVSS 4.7 and
5.9. The sprintf-js exemption is filtered.
- **This PR `9ada86315f`: exit 0, `No issues found`.** The sprintf-js
exemption is filtered here too. That is the control that shows the
database loaded and matched.
- **The scheduled run's own invocation** (`--lockfile=pnpm-lock.yaml`
from the worktree root, ledger auto-loaded): exit 0, `No issues found`,
with `Loaded npm local db` and the exemption filtered.
- **`scripts/osv-base-relative.mjs`** over both JSON results: exit 0, `0
introduced, 0 inherited, 2 resolved`.
- **One void reading, declared:** my first run of the root invocation,
without `--download-offline-databases`, printed `No issues found` at
exit 0. It printed no `Loaded npm local db` line and no filtered
exemption, so it had loaded no database. It is not counted.
What closes the card's last clause is the next scheduled (or a
`workflow_dispatch`) `Validate Dependencies` run on `main`. This PR's
own run takes the base-relative path.
## Changeset: `skip-changeset`, measured
Nothing publishes.
- The diff is `pnpm-lock.yaml` alone. No `package.json` changed, so
every published package's declared ranges are byte-identical, and a
downstream install resolves exactly as before.
- No manifest in the repository declares `vitest` or any `@vitest/*`
package as a `dependency`, `peerDependency` or `optionalDependency` (0
hits over every tracked `package.json`).
- No `tsup` config names `vitest` in `noExternal` (0 hits).
- The built `@objectstack/spec` `dist` has 0 files naming `@vitest/` or
`createManualModuleSource`. The positive control is 7 files in
`@vitest/mocker` 4.1.12's own `dist`.
- No `.changeset/*.md` file is touched.
## Gates
- **Derivation.** `node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` at `9ada86315f` derived 19 commands from 1
path. I ran all 19, each exit captured before any pipe.
- **`--ran` reconciliation:** `19 derived, 17 run, 2 NOT-MEASURED, 0
UNRUN`.
- **17 exited 0:**
- the `node` gates `check-changeset-fixed`,
`check-closing-keyword-parity` (+ `--self-test`),
`check-comment-mask-corpus`, `check-dts-emitted --self-test`,
`check-osv-exemptions` (+ `--self-test`) and `osv-base-relative
--self-test`;
- the `pnpm` gates `check:driver-memory-census`, `check:dts-closure`,
`check:gitlink-declared`, `check:nul-bytes`,
`check:override-consistency`, `check:refd-timer-probe`,
`check:sourcemap-no-sources-content`,
`check:vendor-export-contract-resolve` and `check:watch-hint-literal`.
- **Partial sweeps:** `check:dts-closure` and
`check:sourcemap-no-sources-content` swept only the one built package,
`@objectstack/spec`.
- **NOT MEASURED:** `pnpm check:dual-build-cjs-loads` and `pnpm
check:lean-entry-closure` each exit 3 (`PREREQUISITE NOT MET`, built
output absent; both need a full `pnpm build`). CI's `Build Core` and
`Lint & Repo Gates` measure them on the built tree.
- **`git merge-tree --write-tree origin/main HEAD`** (`origin/main` =
`06900c9c23`): exit 0, clean. `pnpm-lock.yaml` is not routed to the
`os-regen` driver, so this local reading answers GitHub's question. The
1 commit `main` gained since the base touches none of `pnpm-lock.yaml`,
`pnpm-workspace.yaml`, any `package.json` or `osv-scanner.toml`.
## Acceptance notes
- **A scaffolded project still resolves an affected `@vitest/mocker`.**
- `create-objectstack` copies `src/templates` into `dist/templates`, and
`files` ships `dist`. So the blank template's `vitest: ~4.0.0`, held by
its matching npm `overrides`, ships.
- `~4.0.0` resolves to `vitest` 4.0.18 today, which depends on
`@vitest/mocker` 4.0.18 exactly. That is inside GHSA-qxg6-89mg-rqv8's
affected range, and the advisory names no 4.0.x fix. GHSA-xp26-3454-mjgp
does not reach 4.0.x.
- The pin is deliberate (`d795719926`): `vitest` 4.1.12's
self-contradictory `@vitest/browser-webdriverio ^4.1.11` peer crashes
npm 10's arborist with `edgesOut`. Lifting it is a trade-off and outside
this card's file surface.
- Reported to the seat in the dev report; not filed here.
- Many comments and pins record behaviour "measured on vitest 4.1.11"
(for example `packages/spec/vitest.config.ts`,
`packages/cli/vitest.config.ts`, and the `@vitest/runner@4.1.11`
`withTimeout` notes in `packages/client` tests). After this re-lock they
name the previous patch. The tarball diff above shows `@vitest/runner`
and the `vitest` CLI are byte-identical apart from the version string,
so the recorded behaviour still holds on 4.1.12. CI's `Test Core` runs
the suites that spawn a real vitest child to pin it. Class: none;
carrier: none.
- In this workspace, `pnpm update` re-resolves a fixed set of unrelated
packages even when it is targeted. The temporary-override re-lock is the
route that keeps a lockfile refresh narrow. Class: none (tooling
behaviour, not a defect of this repo); carrier: none.
- `git push` printed GitHub's notice of "3 vulnerabilities on the
default branch (1 critical, 2 moderate)". The two moderate match this
card. The OSV scan of `main` matches nothing else outside the exempted
sprintf-js advisory. Dependabot alerts are not readable from this
session (`Resource not accessible by integration`, 403), so the critical
one is not identified here. Class: none; carrier: none.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01FM29ZqLTrnPNXxijioZwMp)_
Co-authored-by: Claude <noreply@anthropic.com>1 parent e3aa111 commit b93c750
1 file changed
Lines changed: 159 additions & 159 deletions
0 commit comments