Skip to content

Fix: clear the tar, shell-quote, @tootallnate/once and tmp advisories via npm overrides - #798

Open
AmaadMartin wants to merge 1 commit into
mainfrom
fix/dependabot-tar-once-tmp-overrides
Open

Fix: clear the tar, shell-quote, @tootallnate/once and tmp advisories via npm overrides#798
AmaadMartin wants to merge 1 commit into
mainfrom
fix/dependabot-tar-once-tmp-overrides

Conversation

@AmaadMartin

@AmaadMartin AmaadMartin commented Aug 8, 2026

Copy link
Copy Markdown
Owner

Please ensure you have read the contribution guide before creating a pull request.

Link to Issue or Description of Change

  1. Link to an existing issue (if applicable):

Related: google#448

  1. Or, if no issue exists, describe the change:

Problem: 17 of the 46 open Dependabot alerts sit on four transitive
packages that no in-range bump can reach. tar@6.2.1 is the last 6.x release
and every one of its 12 advisories is first patched on a 7.5.x version.
concurrently pins shell-quote to an exact version, @mikro-orm/sqlite pins
sqlite3 to exactly 5.1.7, and gts@7, the latest release, still resolves
inquirer -> external-editor -> tmp ^0.0.33. sqlite3@5.1.7 is the root cause
of most of the cluster, because it drags in
node-gyp@8 -> make-fetch-happen@9 -> http-proxy-agent@4 -> @tootallnate/once@1.1.2.

Solution: A root overrides block forces each package to the highest
first-patched version in its cluster. I override sqlite3 rather than
@tootallnate/once or http-proxy-agent, because that chain is optional: npm
drops the node instead of replacing it and leaves a dangling edge. sqlite3@6
depends on tar ^7.5.10 and peers node-gyp 12, so it deletes the legacy chain
and takes the last tar 6-era consumers with it, which means the forced tar 7
no longer sits under a package written against the tar 6 API. No source file
changes: tar and sqlite3 are install-time only, shell-quote and tmp are
dev-only.

"overrides": {
  "tar": "^7.5.21",
  "shell-quote": "^1.9.0",
  "sqlite3": "^6.0.1",
  "tmp": "^0.2.6"
}

The 17 alerts, enumerated from gh api repos/google/adk-js/dependabot/alerts

Package Alerts Severities Highest first-patched
tar 12 1 critical, 6 high, 5 medium 7.5.21
shell-quote 2 1 critical, 1 high 1.9.0
tmp 2 1 high, 1 low 0.2.6
@tootallnate/once 1 1 low 2.0.1

@tootallnate/once has no override entry because the package leaves the tree.
The only copy left is
node_modules/teeny-request/node_modules/@tootallnate/once@2.0.1, already at
the patched floor.

Why each entry is load-bearing

Override Consumer that pins it Declared spec
shell-quote concurrently 1.8.3 exact
sqlite3 @mikro-orm/sqlite 5.1.7 exact
tmp external-editor ^0.0.33
tar sqlite3@6.0.1 / node-gyp@12.4.0 ^7.5.10 / ^7.5.4

The tar entry is the one that does no work today: after the sqlite3 bump its
two consumers float to 7.5.22 unaided. It stays as a security floor and becomes
load-bearing again the moment the sqlite3 override goes away.

Collision check

I listed all 300 open pull requests on the working fork and diffed every
adjacent one. Fork PR #684 wrote the tar and shell-quote entries; it has
been open and untouched since 2026-08-05, so this change carries them forward
and supersedes it. Close #684 if this lands. #797 upgrades the @mikro-orm
family to v7, which removes sqlite3 from the tree entirely; when it lands,
delete the sqlite3 override, because npm ignores an override for a package
that is not in the tree. No other open pull request touches these four
packages.

Limits of this change

Consumers who install @google/adk-devtools still get sqlite3@5.1.7. npm
overrides are a workspace-local resolution directive and are not honoured for
consumers of a published package. This clears the alerts, because Dependabot
reads the committed package-lock.json, and it fixes this repository's own
installs and CI. It does not fix downstream installs; the durable fix is the
MikroORM v6 to v7 migration.

Testing Plan

Please describe the tests that you ran to verify your changes. This is required for all PRs that are not small documentation or typo fixes.

Unit Tests:

  • I have added or updated unit tests for my change.
  • All unit tests pass locally.

This change adds no executable line, so there is no new code to cover and no
unit test for a lockfile would be meaningful. I ran the suites that reach the
overridden packages instead, plus the whole CI gate sequence, on Node v22.22.2,
linux-x64:

Command Result
npm ci --registry=https://registry.npmjs.org exit 0
npm run build exit 0
npx vitest run --project unit:core core/test/sessions/database_session_service_test.ts core/test/sessions/db/operations_test.ts 41 passed
npx vitest run --project integration tests/integration/lazy_load_db_drivers/... tests/integration/sessions 8 passed
npm run lint exit 0
npm run format:check exit 0
npm run docs:check exit 0
npx secretlint package.json package-lock.json exit 0

database_session_service_test.ts drives the real sqlite3 driver against
:memory:, so those 26 tests are the sqlite3 5 to 6 canary, not a mock.

Control run (proving the overrides are what move the tree)

I ran the identical regeneration command against main's manifest with the
overrides block absent:

npm update tar shell-quote sqlite3 tmp --package-lock-only --ignore-scripts --registry=https://registry.npmjs.org

Without the block the tree does not move: tar@6.2.1, shell-quote@1.8.3,
sqlite3@5.1.7, tmp@0.0.33, @tootallnate/once@1.1.2,
http-proxy-agent@4.0.1, 1174 nodes. With it: tar@7.5.22,
shell-quote@1.10.0, sqlite3@6.0.1, tmp@0.2.7, both vulnerable nodes gone,
1131 nodes. npm update alone is not what produces the effect.

Dangling-edge gate

A forced override can make npm silently drop an unsatisfiable optional node,
which is exactly how the @tootallnate/once and http-proxy-agent overrides
fail. I walked every dependencies / optionalDependencies /
peerDependencies / devDependencies edge in the lockfile through the
node_modules walk-up, before and after.

Measure main This branch
unresolved required edges 0 0
unresolved optional-peer edges 28 29
lockfile nodes 1174 1131

The one new optional-peer edge is node-fetch -> encoding@^0.1.0.
node-fetch@2.7.0 declares peerDependenciesMeta.encoding.optional = true, and
encoding@0.1.13 was in the tree only as a minipass-fetch@1 dependency, which
this change removes. An optional peer is allowed to be absent, so I did not add
encoding back.

npm audit

46 to 32, no new advisory. Cleared: tar, shell-quote, concurrently,
@mikro-orm/sqlite, sqlite3, node-gyp, cacache, make-fetch-happen,
http-proxy-agent, @tootallnate/once, gts, inquirer, external-editor,
tmp.

Severity main This branch
critical 3 0
high 14 8
moderate 22 22
low 7 2

Compatibility of the two majors

sqlite3 5 to 6 is the real risk, because it is a native addon and it overrules
an exact pin. sqlite3@6.0.1 loads and reports SQLite 3.52.0, and the 26
real-driver session tests pass. tmp 0.0.33 to 0.2.7 crosses
external-editor@3.1.0, whose only call is tmp.tmpNameSync(); I constructed
an ExternalEditor, confirmed it wrote its temp file and confirmed cleanup()
removed it. That path is dev-only and this repository never executes it:
external-editor is reached only by inquirer's editor prompt, which is
reached only by gts init, and this repository uses gts solely for
tsconfig.json's extends.

sqlite3@6.0.1 publishes napi prebuilds for linux-x64, linux-arm64,
linuxmusl-x64, linuxmusl-arm64, darwin-x64, darwin-arm64 and
win32-x64. I downloaded the win32-x64 and darwin-arm64 assets and
confirmed each contains build/Release/node_sqlite3.node, so
prebuild-install does not fall back to a source build on any runner. The
runners report Node v22.23.1 (ubuntu), v22.23.2 (windows) and v24.18.0 (macos),
all above sqlite3@6.0.1's declared engines: >=20.17.0 and node-gyp@12's
^20.17.0 || >=22.9.0. The full run-tests matrix passed on all three of
ubuntu-latest, windows-latest and macos-latest, so the native install is
confirmed rather than inferred.

Manual End-to-End (E2E) Tests

npm ci --registry=https://registry.npmjs.org
npm run build
node -e "console.log(require('tar/package.json').version)"              # 7.5.22
node -e "console.log(require('shell-quote/package.json').version)"      # 1.10.0
node -e "console.log(require('sqlite3/package.json').version)"          # 6.0.1
node -e "console.log(require('tmp/package.json').version)"              # 0.2.7
node -e "console.log(require('prettier/package.json').version)"         # 3.8.4, must not move
test ! -e node_modules/@tootallnate/once && echo removed                # removed
test ! -e node_modules/http-proxy-agent && echo removed                 # removed
grep -c 'us-npm.pkg.dev' package-lock.json                              # 0

The lockfile holds exactly one tar, one shell-quote, one sqlite3 and one
tmp node, with no nested duplicates. It was regenerated with npm 11, because
npm 9 does not write the license field and strips it from every entry it
rewrites.

Checklist

  • I have read the CONTRIBUTING.md document.
  • I have performed a self-review of my own code.
  • I have commented my code, particularly in hard-to-understand areas.
  • I have added tests that prove my fix is effective or that my feature works.
  • New and existing unit tests pass locally with my changes.

…sories

Four transitive packages carry 17 open advisories that no in-range bump can
reach, so a root overrides block is the only mechanism that moves them.

tar@6.2.1 is the last 6.x release and every one of its advisories is first
patched on a 7.5.x version. concurrently pins shell-quote to an exact version.

@mikro-orm/sqlite pins sqlite3 to exactly 5.1.7, and sqlite3@5.1.7 drags in
node-gyp@8 -> make-fetch-happen@9 -> http-proxy-agent@4 ->
@tootallnate/once@1.1.2. Overriding @tootallnate/once or http-proxy-agent
directly does not work: that chain is optional, so npm drops the node instead
of replacing it and leaves a dangling edge. Overriding sqlite3 to ^6.0.1
deletes the chain, because sqlite3@6 depends on tar ^7.5.10 and peers
node-gyp 12, neither of which uses make-fetch-happen@9. It also removes the
last tar 6-era consumers, so the forced tar 7 no longer sits under a package
written against the tar 6 API.

tmp@0.0.33 arrives through gts -> inquirer -> external-editor. gts@7, the
latest release, still resolves the same chain.

The tar and shell-quote entries were first written for fork PR #684, which
this change supersedes.

npm audit: 46 -> 32 (critical 3 -> 0, high 14 -> 8, low 7 -> 2).
Lockfile: 1174 -> 1131 nodes, 0 unresolved required edges before and after.
@AmaadMartin AmaadMartin changed the title Fix: drop @tootallnate/once and tmp from the tree via npm overrides Fix: clear the tar, shell-quote, @tootallnate/once and tmp advisories via npm overrides Aug 8, 2026
@AmaadMartin
AmaadMartin force-pushed the fix/dependabot-tar-once-tmp-overrides branch from 387f06a to bbfc38a Compare August 8, 2026 07:31
@AmaadMartin
AmaadMartin changed the base branch from fix/dependabot-tar-shell-quote-overrides to main August 8, 2026 07:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant