Skip to content

Security dependency refresh + EBADENGINE cleanup: npm audit 106 -> 53 - #191

Merged
olsonanl merged 2 commits into
alphafrom
deps/security-refresh
Aug 17, 2026
Merged

Security dependency refresh + EBADENGINE cleanup: npm audit 106 -> 53#191
olsonanl merged 2 commits into
alphafrom
deps/security-refresh

Conversation

@olsonanl

@olsonanl olsonanl commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Refreshes vulnerable dependencies. npm audit: 106 → 57 (critical 15→11, high 59→24).
No first-party code changes — offline test results are identical to pristine alpha.

Also closes out the nine stale dependabot PRs (see bottom).

What changed

Most of the win (49 advisories) came from npm audit fix --package-lock-only, which needed
no package.json edits at all — it just re-resolved in-range transitives. Only three
manifest entries moved:

dep from to why it's safe
ejs ^2.7.4 ^3.1.10 Major, but the 2→3 break is removal of old-style <% include x %>. views/ contains zero includes and all 5 templates compile clean under 3.1.10 (verified).
nodemailer ^6.10.1 ^9.0.5 Major, but lib/mailer.js uses only createTransport (sendmail / SMTP / auth / tls) and callback-style sendMail — all exercised against 9.0.5. Clears a critical command-injection advisory in a dep added days ago in #190.
nconf ^0.10.0 ^0.13.0 Major, but config.js:234 is the sole consumer — one chained argv().env().file().defaults(). Verified identical resolution on 0.13.0.

Deliberately not bumped

npm audit fix --force offers these. Each is a real breaking change, not a version bump:

  • redis 2.x → 4+ — v4 removed the callback API. rpc/proteinFamily.js and
    routes/dataRouter.js both use client.get(key, cb) and client.set(k, v, 'EX', ttl).
    Needs a rewrite plus an apicache compatibility check.
  • forever / pm2 — process supervisors; grep require('forever') → 0 hits. Their CVEs
    are ops surface, not request path.
  • request-promise / request — deprecated upstream, no fix exists. Still used by
    routes/genomePermissionRouter.js and several tests. Retiring means porting to axios
    (already a direct dep at 1.19.0) — worth doing as its own change.
  • mocha 7 → 11 — dev-only, needs a test-suite pass.

Where the remaining 57 live

Almost none are reachable from first-party request-path code:

  • p3-user tree — 6 of the 11 criticals (bson, plus nested ejs 2.5.9, nconf 0.6.9,
    nodemailer 1.11.0, forever). These are copies inside the p3-user git dependency,
    which pins its own versions, so our upgrades can't reach them. Being fixed upstream in
    p3_user right now
    — once that lands, re-pin the git SHA here and re-audit.
  • pm2 / forever trees — 11. See above.
  • npm bundled — 3. Vendored inside the npm dependency's own node_modules.
  • axios — the direct dep is already latest (1.19.0) and clean; the alert is
    @pm2/js-api's pinned 0.21.4.

Verification

  • app.js loads; config, lib/mailer, lib/indexRetry, lib/solrjs all require clean.
  • Offline suites (test-util, test-join, test-distributed): 247 passing / 2 failing
    numerically identical to a pristine alpha worktree, so no regressions.
  • Those 2 failures are pre-existing on alpha and documented in CLAUDE.md:
    test.fastaHeaderFormatter.spec.js ("missing values gracefully") and
    test.config.spec.js ("return current configuration", config-key drift).
  • npx eslint on the touched files: 56 errors, unchanged from baseline.
  • nodemailer 9.0.5 exercised directly: sendmail transport, SMTP transport, SMTP+auth, and
    callback sendMail all behave as lib/mailer.js expects.

CLAUDE.md

Adds a Dependency Security Maintenance section recording the analysis, the do-not-bump
list with reasons, the re-run procedure (the isDirect / fixAvailable.isSemVerMajor
grouping one-liner), and the two pre-existing test failures so they aren't misread as
regressions later.

Stale dependabot PRs

#117, #118, #123, #124, #125, #126, #128, #129, #133 are obsolete — 2022–2023 vintage,
all targeting master, all CONFLICTING, and every package they name is either already
patched or superseded here. Recommend closing rather than merging. A companion PR applies
this same refresh to master.

🤖 Generated with Claude Code


Update: second commit — EBADENGINE cleanup (ports #193 to alpha)

A production npm install on Node 22.4.1 printed 80+ EBADENGINE warnings. Root cause was
two dependencies that should never have been declared:

  • npm and install removed. Neither is imported (require('npm') / require('install')
    → 0 hits) and nothing invokes node_modules/.bin/npm. Prod runs from a persistent checkout
    on the system npm, so the vendored npm@11.19.0 was never doing the installing. Both
    arrived incidentally in 84e20f6f, a commit about solrjs that never mentions them.

    Declaring npm vendors the entire npm CLI: 143 of 1339 lockfile entries lived under
    node_modules/npm/, and its subpackages require node: ^20.17.0 || >=22.9.0 — unsatisfied
    by prod's 22.4.1. npm was warning that a vendored copy of itself, which nothing would ever
    execute, didn't match the running Node.

  • apicache ^1.6.2^1.6.3. The one remaining warning; 1.6.2 declares
    node: >=8 <=15, 1.6.3 relaxes to >=8. routes/dataRouter.js:15 usage verified unchanged.

Revised totals for this PR

before after
npm audit 106 53 (crit 15→11, high 59→22)
EBADENGINE warnings 80+ 0
lockfile entries 1336 1191 (−145)

Offline suites still 247 passing / 2 failing, matching pristine alpha exactly.

Confirmed on the live prod checkout after #193 merged: removed 145 packages … 53 vulnerabilities, no EBADENGINE output.

CLAUDE.md gains a "Never declare npm as a dependency" note with the mechanism, and flags
that the repo pins no Node version (no engines, no .nvmrc) so nothing catches this drift.


Update: third commit — deprecation warnings

Separate axis from vulnerabilities (npm audit never reports these). Traced each warning to
its source; only one was fixable from this repo:

  • uuid ^2.0.1^11.1.1. Root dep, used solely as Uuid.v4() at
    routes/indexer.js:204. That named export is unchanged. uuid 11 is "type": "module", but
    its exports map carries a node.require condition, so plain CJS require('uuid') still
    resolves — verified rather than assumed.

Everything else is transitive and belongs upstream:

warning source
nodemailer@1.11.0, mailcomposer@2.1.0, buildmail@2.0.0 p3-user's pinned nodemailer 1.x (mailcomposer/buildmail are its deps)
bson@0.2.22 p3-user^0.2.17
rimraf@3.0.2 @mapbox/node-pre-gyp, flat-cache, temp, utile
@humanwhocodes/* eslint@7's own deps

eslint 7 → 8 was attempted and reverted. eslint-config-standard@12 and
eslint-plugin-import@2.22 both pin peer eslint <= 7, so npm fails ERESOLVE. It needs the
whole standard/plugin stack moved together plus a lint re-run — its own change.

request-promise@4.2.2 is a root dep and genuinely deprecated, but retiring it means porting
routes/genomePermissionRouter.js and several tests to axios. Already in the do-not-bump list.

No audit delta (53 → 53; uuid 2 carried a deprecation, not an advisory). Offline suites still
247 passing / 2 pre-existing failures. CLAUDE.md gains a deprecation table with provenance.

Lockfile-only in-range updates (npm audit fix --package-lock-only) plus three
manifest bumps. No first-party code changes; offline test results are identical
to pristine alpha (247 passing / 2 pre-existing failures).

Manifest bumps, all majors, each verified against actual usage:

- ejs ^2.7.4 -> ^3.1.10   The 2->3 break is removal of old-style
                          "<% include x %>". views/ has zero includes; all 5
                          templates compile clean on 3.1.10.
- nodemailer ^6.10.1 -> ^9.0.5
                          lib/mailer.js uses only createTransport (sendmail,
                          SMTP, auth, tls) and callback-style sendMail. All
                          verified on 9.0.5. Clears a critical (command
                          injection < 6.4.16) in a dep added days ago.
- nconf ^0.10.0 -> ^0.13.0
                          config.js:234 is the sole consumer; verified the
                          chained argv().env().file().defaults() resolves
                          identically.

Deliberately NOT bumped (breaking, need their own change): redis 2->4 removes
the callback API used in rpc/proteinFamily.js and routes/dataRouter.js;
forever/pm2 are ops tooling imported by no app code; request-promise has no
fix and needs porting to axios; mocha 7->11 is dev-only.

Most of the remaining 57 are unreachable from here: 6 criticals are nested
copies inside the p3-user git dep (being fixed upstream), 11 are pm2/forever
trees, 3 are vendored inside npm itself. Direct axios is already latest and
clean; its alert is @pm2/js-api's pinned 0.21.4.

CLAUDE.md documents the analysis, the do-not-bump list with reasons, the
re-run procedure, and the two pre-existing test failures.

The 9 open dependabot PRs (#117 #118 #123 #124 #125 #126 #128 #129 #133) are
obsolete: 2022-2023 vintage, all target master, all conflicting, every package
already patched or superseded here.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… noise

Ports the master-side fix (#193) to alpha so the two lines stay aligned.

A production `npm install` on Node 22.4.1 printed 80+ EBADENGINE warnings. All
but one came from two dependencies that should never have been declared.

- Drop `npm` (^11.11.0) and `install` (^0.13.0). Neither is imported by any
  first-party code (`require('npm')` / `require('install')` -> 0 hits), and
  nothing invokes `node_modules/.bin/npm`. Prod runs from a persistent checkout
  using the system npm, so the vendored npm@11.19.0 was never doing the
  installing -- pure dead weight. Added incidentally in 84e20f6, a commit about
  solrjs that never mentions them.

  Vendoring the npm CLI pulled its whole tree into the lockfile: 143 of 1339
  entries under node_modules/npm/, whose subpackages require
  `node: ^20.17.0 || >=22.9.0` -- unsatisfied by prod's 22.4.1. Hence the wall.

- apicache ^1.6.2 -> ^1.6.3. 1.6.2 declares `node: >=8 <=15`; 1.6.3 relaxes to
  `>=8`. routes/dataRouter.js:15 uses apicache.options({redisClient}).middleware,
  verified unchanged.

Result on alpha: EBADENGINE warnings 80+ -> 0, lockfile 1336 -> 1191 entries,
npm audit 57 -> 53. Offline suites still 247 passing / 2 pre-existing failures,
matching pristine alpha exactly.

CLAUDE.md gains a "Never declare npm as a dependency" note explaining the
mechanism, plus a pointer that the repo pins no Node version so nothing catches
this drift automatically.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@olsonanl olsonanl changed the title Security dependency refresh: npm audit 106 -> 57 Security dependency refresh + EBADENGINE cleanup: npm audit 106 -> 53 Aug 17, 2026
@olsonanl
olsonanl merged commit 6f13397 into alpha Aug 17, 2026
olsonanl added a commit to olsonanl/p3_api that referenced this pull request Aug 17, 2026
Re-lands the commit that PR BV-BRC#191 missed. BV-BRC#191 was merged while GitHub's PR view
was stale (it showed head a3ab21e and never picked up the third commit), so
this change was left behind on both alpha and master while the rest of the
refresh landed.

`npm install` still prints deprecation warnings after the security refresh.
These are a separate axis from vulnerabilities -- npm audit never reports them
-- so they needed their own pass. Traced each to its source; only one was
fixable from this repo:

- uuid ^2.0.1 -> ^11.1.1. Root dep, used solely as `Uuid.v4()` at
  routes/indexer.js:204. The v4 named export is unchanged. uuid 11 is
  "type": "module", but its exports map carries a node.require condition, so
  plain CJS `require('uuid')` still resolves -- verified, not assumed.

Not fixable here (transitive):

- nodemailer@1.11.0, mailcomposer@2.1.0, buildmail@2.0.0 -- all from p3-user's
  pinned nodemailer 1.x (mailcomposer/buildmail are its deps, not ours).
- bson@0.2.22 -- p3-user wants ^0.2.17.
- rimraf@3.0.2 -- @mapbox/node-pre-gyp, flat-cache, temp, utile.
- @humanwhocodes/* -- eslint 7's own deps.

Deliberately not done:

- eslint 7 -> 8 fails ERESOLVE: eslint-config-standard@12 and
  eslint-plugin-import@2.22 both pin peer eslint <=7. Needs the whole
  standard/plugin stack upgraded together plus a lint re-run. Its own change.
  (The earlier version of this commit carried a stray eslint ^7.8.1 -> ^7.32.0
  range narrowing, left over from that attempt; dropped here.)
- request-promise@4.2.2 is a root dep and genuinely deprecated, but retiring it
  means porting routes/genomePermissionRouter.js and several tests to axios.
  Already tracked in the do-not-bump list.

No audit change (53 before and after -- uuid 2 carried a deprecation, not an
advisory). Verified: 0 EBADENGINE warnings, app.js and routes/indexer.js load,
offline suites 247 passing / 2 pre-existing failures, matching alpha exactly.

CLAUDE.md gains a deprecation-warning table with provenance for each entry.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
olsonanl added a commit to olsonanl/p3_api that referenced this pull request Aug 17, 2026
Brings in the dependency refresh that landed on alpha while this branch was
open (PRs BV-BRC#191, BV-BRC#194, BV-BRC#197, BV-BRC#199):

  npm audit  106 -> 35     criticals 15 -> 2
  packages  1339 -> 900    EBADENGINE warnings 80+ -> 0

- ejs 2->3, nconf 0.10->0.13, nodemailer 6->9, uuid 2->11, apicache 1.6.3
- npm and install dropped (they vendored the whole npm CLI, 143 lockfile
  entries, and caused every EBADENGINE warning)
- forever dropped; the services run under pm2
- p3-user repinned to BV-BRC/BV-BRC-UserManagement#105a60b7, which carries a
  SigningSubject auth-bypass fix and makes the local validateToken.js patch
  obsolete -- that patch never survived npm install, so this removes a standing
  operational hazard for this branch too

Conflict: CLAUDE.md only, and not a real one -- this branch added "Trace Replay
& Shakedown Testing" and alpha added "Dependency Security Maintenance" at the
same location. Both kept, in that order. package.json and package-lock.json
merged cleanly.

Verified after the merge: the branch's own additions survive (test-distributed
and test-util scripts, dojo-declare, the inlined lib/solrjs with no solrjs
dependency); lockfile re-resolves to no change; 0 EBADENGINE; app.js,
middleware/auth.js, lib/mailer, lib/indexRetry and lib/solrjs all load.

Offline suites 327 passing / 1 failing -- identical to this branch's pre-merge
baseline at 2de2677, measured directly. The single failure is the known
pre-existing fastaHeaderFormatter case. (Alpha shows 247/2; this branch has
more suites and does not hit alpha's test.config.spec.js failure, since the
config keys that test expects are the ones this branch adds.)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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