Skip to content

fix(deps): take the fix for the four OSV advisories blocking every manifest PR - #14736

Merged
baozhoutao merged 2 commits into
mainfrom
claude/issue-14639-osv-xmldom-qs-fix
Sep 3, 2026
Merged

fix(deps): take the fix for the four OSV advisories blocking every manifest PR#14736
baozhoutao merged 2 commits into
mainfrom
claude/issue-14639-osv-xmldom-qs-fix

Conversation

@claude

@claude claude Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Fixes #14639

OSV-Scanner blocks every PR touching a package.json on four fixable advisories in pnpm-lock.yaml. All four name a fixed version, so this is the take-the-fix path osv-scanner.toml's own header describes.

No osv-scanner.toml exemption and no .github/workflows/validate-deps.yml change — the ledger still holds zero entries (that file is untouched by this PR), and the scan-cadence question stays where triage put it, on #14645.

Where the pin lives — a correction to the card's assumed file surface

The card and the claim both name root package.json pnpm.overrides. That is not this repo's mechanism and under pnpm 10 it would have been a silent no-op: every override in this workspace lives in pnpm-workspace.yaml, which already carries 30 of them, and scripts/check-override-consistency.mjs reads them from there (its pass line says so: "9 published-manifest declaration(s) covered by pnpm-workspace.yaml overrides"). Root package.json's pnpm block holds only ignoredBuiltDependencies and is untouched here.

The route is otherwise exactly what triage ruled. A transitive resolution does not move on its own: the only pnpm-native alternative was pnpm update --recursive --depth Infinity, which re-resolves the whole graph — measured on this branch, it moved nine unrelated packages (@inquirer/*, ip-address, isbot, node-abi, seroval, type-fest) and dropped a peer-resolution suffix from a drizzle-orm entry. That was reverted. An override selector is what makes the move surgical, and it is the shape every prior member of this class used (#5032, #6407, #6506).

Dependents — every declared range already admits its own fixed version

flagged fixed pulled by that dependent's declared range admits the fix
@xmldom/xmldom 0.8.13 0.8.15 @authenio/xml-encryption@2.0.2 ^0.8.6 yes
samlify@2.13.1 ^0.8.11 yes
xml-crypto@6.1.2 ^0.8.10 yes
@xmldom/xmldom 0.9.11 0.9.12 @better-auth/sso@1.7.2 ^0.9.10 yes
qs 6.15.3 6.16.0 body-parser@2.3.0 ^6.15.2 yes
express@5.2.1 ^6.14.0 yes

So no dependent needed forcing past what it supports — each entry is a dedupe onto the patched line, the dompurify / nanoid shape already documented in that block. Ranges read from the installed package.json of each dependent, not inferred.

@xmldom/xmldom needs two selectors, not one: both of its resolved lines are flagged and they have different fixed versions (0.8.15 and 0.9.12). One selector reaching the 0.9 fix would have dragged the three 0.8 consumers across a 0.x minor — the compatibility boundary for a 0.x package — past every range they declare.

Bounds sit at the compatibility boundary (0.9.0 and 0.10.0 for the two 0.x lines, 7.0.0 for qs), never at the fixed version itself, per that block's header rule and the undici 7.28.0 / brace-expansion 5.0.8 specimens. check:override-consistency confirms the shape: all three new entries are absent from both of its reports — they have consumers, and their bounds sit above their target's version line.

Nothing in the workspace declares either package directly (grep over every non-node_modules package.json = 0 hits), so both are transitive-only and no publishable manifest has to move in lockstep.

Commands — the lockfile was regenerated by pnpm, never hand-edited

# 3 override entries appended to pnpm-workspace.yaml, then:
pnpm install --lockfile-only     # exit 0
pnpm install --frozen-lockfile   # exit 0 — CI's "Verify lockfile is up to date" step

The three flagged lines are gone, the fixed ones are present

$ grep -cE "@xmldom/xmldom@0\.8\.13|@xmldom/xmldom@0\.9\.11|qs@6\.15\.3|'@xmldom/xmldom': 0\.8\.13|'@xmldom/xmldom': 0\.9\.11|qs: 6\.15\.3" pnpm-lock.yaml
0

$ grep -nE "@xmldom/xmldom@0\.8\.15|@xmldom/xmldom@0\.9\.12|qs@6\.16\.0" pnpm-lock.yaml
5362:  '@xmldom/xmldom@0.8.15':
5366:  '@xmldom/xmldom@0.9.12':
8253:  qs@6.16.0:
11683:  '@xmldom/xmldom@0.8.15': {}
11685:  '@xmldom/xmldom@0.9.12': {}
14785:  qs@6.16.0:

Diff hygiene — every changed lockfile line accounted for

 pnpm-lock.yaml      | 35 ++++++++++++++++++-----------------
 pnpm-workspace.yaml | 33 +++++++++++++++++++++++++++++++++
 2 files changed, 51 insertions(+), 17 deletions(-)

Filtering the lockfile diff down to lines that name neither package leaves exactly seven, all of them the moved packages' own metadata: three resolution: integrity hashes (one per moved version) and, on the - side, two deprecated: this version has critical issues, please update to the latest version notes that upstream dropped when it published the patched releases. No other resolution moved and no peer-resolution suffix changed.

OSV result — the workflow's own scanner, run locally

api.osv.dev is blocked from this container, so the scan ran against OSV-Scanner's offline npm database (downloaded 2026-09-02 22:27 UTC). Scanner version 2.3.8, matching the google/osv-scanner-action pin in validate-deps.yml.

Positive control — origin/main 4d0d9445a lockfile:

Total 4 packages affected by 8 known vulnerabilities (0 Critical, 4 High, 4 Medium, 0 Low, 0 Unknown)
| https://osv.dev/GHSA-6gmq-8vp8-gcm6 | 6.3 | @xmldom/xmldom | 0.8.13 | 0.8.15 |
| https://osv.dev/GHSA-6gmq-8vp8-gcm6 | 6.3 | @xmldom/xmldom | 0.9.11 | 0.9.12 |
| https://osv.dev/GHSA-4mjr-xmp4-gh2g | 6.3 | qs             | 6.15.3 | 6.16.0 |
| https://osv.dev/GHSA-x5fp-wj9c-mxmx | 6.3 | qs             | 6.15.3 | 6.16.0 |
  ... plus 4 on fast-uri 3.1.5, see below

This branch, same scanner, same database — all four the card names are gone:

Total 1 package affected by 4 known vulnerabilities (0 Critical, 4 High, 0 Medium, 0 Low, 0 Unknown)
| https://osv.dev/GHSA-5jgf-p345-68v8 | 7.5 | fast-uri | 3.1.5 | 3.1.6 |
| https://osv.dev/GHSA-f65p-4m7j-42xc | 7.5 | fast-uri | 3.1.5 | 3.1.6 |
| https://osv.dev/GHSA-fph4-wmhf-6fwf | 7.5 | fast-uri | 3.1.5 | 3.1.6 |
| https://osv.dev/GHSA-jqff-g426-hqxp | 7.5 | fast-uri | 3.1.5 | 3.1.6 |

⚠️ The job will still be red after this merges — on four DIFFERENT advisories

Four new fast-uri advisories (7.5 high each, fixed in 3.1.6) landed after #14639 was filed and triaged — that card quotes its CI run as 0 Critical, 0 High, 4 Medium, so they were not present then. They are out of this card's ruled scope (⛔ no other dependency moves), and they are a one-line target lift on the fast-uri pin pnpm-workspace.yaml already carries from the #5032 batch. Filed as #14732, with the measurement, the dependents and the fix shape. This PR does not touch them.

Tests

Affected workspace packages, from pnpm why -r on both packages: @objectstack/plugin-auth (xmldom, via @better-auth/sso and samlify), and @objectstack/connector-mcp / @objectstack/mcp / @objectstack/example-showcase (qs, via @modelcontextprotocol/sdk and express).

run result
pnpm --filter @objectstack/plugin-auth test 91 files, 1862 passed
pnpm --filter @objectstack/plugin-auth typecheck pass
pnpm --filter @objectstack/connector-mcp test 3 files, 23 passed
pnpm --filter @objectstack/connector-mcp typecheck pass
pnpm --filter @objectstack/mcp test 25 files, 271 passed
pnpm --filter @objectstack/mcp typecheck pass

Dependency closures were built first (pnpm --filter '...^...' build, exit 0), so none of the above is a stale-dist reading.

Gates

node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands derived a 10-command family for this change set (pnpm-lock.yaml, pnpm-workspace.yaml; merge base dbf115284). The union was re-run on the final commit ac8c23345, after merging origin/main dbf115284 — that merge brought in one commit (#14651) which touches neither the lockfile nor the override ledger, so nothing had to be regenerated on top. Eight ran green:

check-changeset-fixed             0
check-cross-package-test-inputs   0
check-osv-exemptions              0   (--self-test also 0; "zero OSV exemptions, the intended steady state")
check-prerelease-pin-watch        0
check-shard-attestation           0
spec check:llms-txt               0
check:override-consistency        0
check:workspace-manifest-cycles   0

Two are NOT MEASURED locally, neither of them a red — each printed its own prerequisite verdict and exited 3, the code both scripts reserve for "nothing was measured":

  • check-test-completeness — needs a saved turbo run test log, which only CI produces; the script names this branch unreachable in CI and says to record it as NOT MEASURED locally.
  • check:dual-build-cjs-loadsPREREQUISITE NOT MET, run pnpm build first; it reads every package's dist/. Declared narrowing: this diff changes no workspace source, no workspace manifest and no workspace-package version, only third-party transitive resolutions inside dependencies' own trees, so it cannot alter any package's emitted bytes or exports map, which is all this gate reads. CI builds and runs it regardless.

Changeset

None — skip-changeset. This moves only the lockfile and the workspace override ledger; overrides pin what this workspace resolves and do not ship with published packages, and no publishable manifest declares either package, so no published package changes for a consumer.

🤖 Generated with Claude Code

https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV


Generated by Claude Code

…nifest PR

`Validate Package Dependencies` (OSV-Scanner against pnpm-lock.yaml) exits 1 on
four fixable advisories, so every PR touching any package.json is red:

  GHSA-6gmq-8vp8-gcm6  @xmldom/xmldom  0.8.13 -> 0.8.15
  GHSA-6gmq-8vp8-gcm6  @xmldom/xmldom  0.9.11 -> 0.9.12
  GHSA-4mjr-xmp4-gh2g  qs              6.15.3 -> 6.16.0
  GHSA-x5fp-wj9c-mxmx  qs              6.15.3 -> 6.16.0

All four name a fixed version, so this is the take-the-fix path osv-scanner.toml's
header describes, not the exemption path. That ledger keeps its zero entries and
is untouched here, as is .github/workflows/validate-deps.yml.

Both packages are transitive-only; nothing in the workspace declares either. Every
dependent's declared range already admits its own fixed version (xml-encryption
^0.8.6, samlify ^0.8.11, xml-crypto ^0.8.10, better-auth/sso ^0.9.10, body-parser
^6.15.2, express ^6.14.0), so each entry is a dedupe onto the patched line rather
than a forced upgrade past what a dependent supports - the dompurify / nanoid
shape the overrides block already documents.

@xmldom/xmldom needs two selectors, not one: both resolved lines are flagged and
their fixed versions differ, and a single selector reaching the 0.9 fix would drag
the three 0.8 consumers across a 0.x minor. Bounds sit at the compatibility
boundary rather than at the fixed version, so a future lift moves only the target.

The lockfile was regenerated by `pnpm install --lockfile-only` and never edited by
hand; `pnpm install --frozen-lockfile` is green.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV
@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

⛔ merge queue 构建失败 — 先分诊,再决定要不要重排

队列构建 33696603273 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集),
所以失败的测试可能在本 PR 没碰过的包里 —— 那不是重排能修的。每次盲目重排都会让排在后面的所有 PR 重建一轮。

失败的 job(日志抽取,best effort):

  • Test Core (1/6) — 失败步骤: Run this shard's tests

    @objectstack/cli:test:  FAIL   integration  test/run-dev-unbuilt-workspace.e2e.test.ts > the mirror direction: a reader that is never coming back > gives up and exits instead of waiting forever
      ↳ 失败原因: @objectstack/cli:test: AssertionError: the harness SIGKILLed the child — it was still alive at the ceiling. cap 180000 ms (RUN_TIMEOUT_MS, constant and load-independent by design); this child ran 1801
    

↳ 失败原因 是判读的关键:超时Test timed out in … / Hook timed out in …)多半是负载/时序,不是本 PR 的回归;
断言AssertionError: …)才指向真实的行为改变。两者的 FAIL 行长得一模一样,只有这一行能区分。

⚠️ 断言这一侧有一类例外,判据是断言在测什么,不是它是不是 AssertionError 断言的对象是产品行为(一个值、一个形状、一次拒收)⇒ 照上面读:真实的行为改变,去查,⛔ 不要重排掉;
断言的对象是这次实验自身的有效性前提(跑完的耗时、负载下的先后、任何只在时间预算内才成立的条件)⇒ 它跟超时是同一类,同样对负载敏感,重排一次是合法的判别手段。
识别是机械的:断言的消息或它比较的值本身点名了一段时长、一个时间戳、一个耗时计数。实测过的一对 —— AssertionError: SecurityPlugin.init() ran: expected false to be true 测的是产品行为(真回归);
AssertionError: this run took over a second, so second-precision stamps could have differed too: expected 1006 to be less than 1000 测的是实验前提:它守护的那条不变式当时是绿的,同一个 head 原样重排一次即成功。
穿着 AssertionError 外衣的时间测量,仍然是时间测量。(⛔ 这只改「怎么读一次红」,不改「哪些测试可以重排」——后者由别处管。)

跨 PR 相同签名(24h,按失败测试文件聚合):

历史信号:

  • 本 PR 过去 24h 无队列失败记录(首次)。
  • 过去 24h 队列共有 31 个失败构建(不含本次)。

分诊清单:

  1. 失败测试在本 PR 改动的包里 → 真回归,修 PR。
  2. 失败测试与本 PR 无关 → 看上面的「跨 PR 相同签名」;已有汇总 issue ⇒ flaky/环境问题实锤,去那张 issue 上谈,修好前重排只会再烧一轮全队列。
  3. 两者都不是 → 可能与同组 PR 语义冲突;等前面的 PR 落地或失败出队后再重排一次即可,不要连续重排。

Generated by Claude Code · merge-queue-triage workflow (#4859)

@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

⛔ merge queue 构建失败 — 先分诊,再决定要不要重排

队列构建 33697811481 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集),
所以失败的测试可能在本 PR 没碰过的包里 —— 那不是重排能修的。每次盲目重排都会让排在后面的所有 PR 重建一轮。

失败的 job(日志抽取,best effort):

  • Test Core (1/6) — 失败步骤: Run this shard's tests

    @objectstack/cli:test:  FAIL   integration  test/run-dev-unbuilt-workspace.e2e.test.ts > the mirror direction: a reader that is never coming back > gives up and exits instead of waiting forever
      ↳ 失败原因: @objectstack/cli:test: AssertionError: expected 'SIGKILL' to be null
    

↳ 失败原因 是判读的关键:超时Test timed out in … / Hook timed out in …)多半是负载/时序,不是本 PR 的回归;
断言AssertionError: …)才指向真实的行为改变。两者的 FAIL 行长得一模一样,只有这一行能区分。

⚠️ 断言这一侧有一类例外,判据是断言在测什么,不是它是不是 AssertionError 断言的对象是产品行为(一个值、一个形状、一次拒收)⇒ 照上面读:真实的行为改变,去查,⛔ 不要重排掉;
断言的对象是这次实验自身的有效性前提(跑完的耗时、负载下的先后、任何只在时间预算内才成立的条件)⇒ 它跟超时是同一类,同样对负载敏感,重排一次是合法的判别手段。
识别是机械的:断言的消息或它比较的值本身点名了一段时长、一个时间戳、一个耗时计数。实测过的一对 —— AssertionError: SecurityPlugin.init() ran: expected false to be true 测的是产品行为(真回归);
AssertionError: this run took over a second, so second-precision stamps could have differed too: expected 1006 to be less than 1000 测的是实验前提:它守护的那条不变式当时是绿的,同一个 head 原样重排一次即成功。
穿着 AssertionError 外衣的时间测量,仍然是时间测量。(⛔ 这只改「怎么读一次红」,不改「哪些测试可以重排」——后者由别处管。)

跨 PR 相同签名(24h,按失败测试文件聚合):

历史信号:

  • ⚠️ 本 PR 过去 24h 已在队列失败 1 次(不含本次)。 内容未变而反复失败 ⇒ 高度怀疑 flaky 测试或与同组 PR 的语义冲突,重排不解决。
  • 过去 24h 队列共有 33 个失败构建(不含本次)。

分诊清单:

  1. 失败测试在本 PR 改动的包里 → 真回归,修 PR。
  2. 失败测试与本 PR 无关 → 看上面的「跨 PR 相同签名」;已有汇总 issue ⇒ flaky/环境问题实锤,去那张 issue 上谈,修好前重排只会再烧一轮全队列。
  3. 两者都不是 → 可能与同组 PR 语义冲突;等前面的 PR 落地或失败出队后再重排一次即可,不要连续重排。

Generated by Claude Code · merge-queue-triage workflow (#4859)

Merged via the queue into main with commit d4ac61f Sep 3, 2026
39 of 40 checks passed
@baozhoutao
baozhoutao deleted the claude/issue-14639-osv-xmldom-qs-fix branch September 3, 2026 00:49
baozhoutao pushed a commit that referenced this pull request Sep 3, 2026
Four NEW fast-uri advisories (GHSA-5jgf-p345-68v8, GHSA-f65p-4m7j-42xc,
GHSA-fph4-wmhf-6fwf, GHSA-jqff-g426-hqxp; 7.5 high each, fixed in 3.1.6)
keep `Validate Package Dependencies` red after #14639/#14736 clear the
xmldom/qs batch. Lift the existing #5032 override's target from ^3.1.5
to ^3.1.6 (selector stays at the 4.0.0 boundary) and extend its comment
with the four new GHSAs. ajv@8.20.0 declares ^3.0.1, which already
admits 3.1.6, so this is a dedupe onto the patched line.

pnpm-lock.yaml regenerated with `pnpm install --lockfile-only` only.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file size/s skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Validate Package Dependencies is red for every PR touching a package.json — 4 FIXABLE OSV advisories in the lockfile (@xmldom/xmldom, qs)

2 participants