Conversation
Re-resolve the lockfile within the ranges already declared, and add the constraints needed to reach patched versions those ranges cannot select on their own. Re-resolution alone (no manifest change required) moves 33 transitive packages onto patched releases and drops got, http-cache-semantics and ip from the tree entirely, the last of which has no patched release. Manifest changes: - resolutions axios ^1.18.0, lodash ^4.18.0, qs ^6.15.3: @eyeseetea/d2-api declares these as exact versions and no published release of it relaxes them, so upgrading the parent cannot move them. - resolution vite ^6.4.3: vitest declares a vite range reaching vite 7, which requires Node 20.19 or later and cannot be installed here. - nodemailer ^9.0.5 with @types/nodemailer ^8.0.1: only the 9.x line is outside the open advisory ranges. - vitest ^3.2.7 with vite ^6.4.3 and vite-tsconfig-paths ^4.3.2, which is the newest line still loadable from a CommonJS config file. - nodemon 3.1.11: the newest release installable on Node 18, since 3.1.12 requires brace-expansion 5. The 2.x line resolves semver to a vulnerable release through its update-notifier chain. - Remove eight devDependencies that have no reference outside package.json. vitest 3 dropped the default "**/__tests__/**" include pattern, which would have silently stopped collecting the *.specs.ts suites. It is restored explicitly in vitest.config.ts so the same 14 suites run. Type the exportTranslations mock so the first-call assertions narrow without a non-null assertion, and await a rejects assertion that vitest 3 no longer auto-awaits. Add RESOLUTIONS.md recording each constraint, its drop-when condition, and the two findings that have no fix installable on this Node version.
anagperal
marked this pull request as ready for review
August 18, 2026 13:57
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
📌 References
Issue: Closes #869e9w0v1 analyze dependency issues
Findings on this branch: open code-scanning alerts — filtered to tool
OWASP Dependency-Track (yarn4), which is what this description quotes throughout.Documentation:
RESOLUTIONS.md, added by this PR, following the same structure as the reference repositories.Reference implementations: dhis2-app-skeleton#120 — open and not approved — for the
RESOLUTIONS.mdstructure, plus metadata-synchronization#1264 and Bulk-Load#413 for the floor conventions, and user-extended#532 for the vite 6 line. Used as references and re-verified against this tree, not copied: all are Yarn 4 browser applications and this is a Yarn 1 Node CLI, so one of their shared conventions does not apply — see the note on vite below.Process notes are in the internal wiki (draft, for team discussion).
📝 Implementation
A dedicated remediation pass over the open Dependency-Track findings on this branch, so the bar
applied was fix everything that has a published fix, not introduce nothing new. Everything with a
fix installable on the Node version this project targets is fixed; everything without one is recorded
in
RESOLUTIONS.md, which this repository did not have.Scope note: this PR deliberately contains no toolchain migration — the Node and Yarn versions
are untouched. Two of the six remaining alerts are open only because of this choice.
Check the current alerts
rather than a figure quoted here
Note this repository is on Yarn 1, so the commands are
yarn upgraderather thanyarn up -R,and there is no
.yarnrc.yml: no install-policy age gate applies, and no fix in this PR was deferredby one.
Most of it is re-resolution, not new constraints
The largest part of this change is a lockfile refresh. For 33 packages the declared ranges already
admitted the patched release and the lockfile had simply gone stale, so
yarn upgradereached thefix with a byte-identical
package.json. That includes three of the four criticals:webpack^5.70.0GHSA-hc6q-2mpp-qw7j)form-data^4.0.0GHSA-fjxv-7rqg-78g4)minimist^1.2.0GHSA-xvch-5gv4-984h)brace-expansion^1.1.7fast-uri^3.0.1js-yaml^4.1.0minimatch^3.0.4postcss^8.4.27ws^8.13.0nanoid^3.3.7The rest moved the same way, each inside a range its parents already declared:
eslint,terser,rollup,ajv,braces,micromatch,picomatch,cross-spawn,es5-ext,flatted,follow-redirects,json5,moment,semver,word-wrapand@tootallnate/once.Three packages left the tree entirely rather than being upgraded, which is worth recording
because none of them could have been fixed by a version bump:
ip@2.0.0—socks-proxy-agentdeclaressocks: ^2.7.1, and socks 2.8.x replacedipwithip-address.GHSA-2p57-rm9w-gvfp(high) affectsip <= 2.0.1with no patched version —ipis unmaintained, so upgrading it could never have closed this. Eviction was the only route.got@9.6.0andhttp-cache-semantics@4.1.0— reached only through nodemon'supdate-notifierchain, which the nodemon 3 line replaced.
Three exact pins in
@eyeseetea/d2-apineeded floor resolutionsaxios@1.6.4alone was the single largest item on the branch: 29 live advisories.The ladder's upgrade the parent rung is genuinely closed here, and this was checked rather than
assumed: every published d2-api release — 1.18.0, 1.19.0, 1.19.1, 1.20.0, 1.21.0 and
42.22.0-beta.2— carries the same three exact pins, so no d2-api version moves them.axios: ^1.18.0lodash: ^4.18.0qs: ^6.15.3Each was verified by removing it, reinstalling and comparing resolved versions — not lockfile
bytes. All three are load-bearing: without them the tree resolves back to 1.6.4, 4.17.21 and 6.9.7
respectively. That evidence is recorded per entry in
RESOLUTIONS.md.them as ranges. Removing them resolves all three downwards into the affected ranges.
One toolchain upgrade closed the last critical and the vite group together
vitest@0.32.4carriedGHSA-5xrq-8626-4rwp(critical). Its ranges are< 3.2.6 → 3.2.6and
>= 4.0.0, < 4.1.0 → 4.1.0; 0.32.4 falls in the first, so 3.2.7 is sufficient. Theadvisory summary alone would have invited a needless move to vitest 4.
vite@4.5.3carried 7 further advisories, andesbuild@0.18.20came only from vite 4.The cost was near zero, because this project does not use vite to build. There is no
vite.config.ts— the build is webpack — and vite is present only as vitest's engine.vite-plugin-checkeris not used, so the coupling that forced an ESLint flat-config port in otherrepositories does not exist here. ESLint is untouched.
The same Node 18 ceiling shapes two more decisions below, so it is worth stating once: Node 18 caps
viteat 6,nodemonat 3.1.11,serialize-javascriptat 6.0.2 andcopy-webpack-pluginat 13.nodemailerneeded a majorDirect runtime dependency. Re-resolution within
^6.7.5reaches 6.10.1 and still leaves 8 findingsopen; only the 9.x line clears them.
engines.nodeis>=6.0.0on nodemailer 9, so Node 18 is not ablocker.
@types/nodemailermoved to^8.0.1to match, since nodemailer ships no types of its own.nodemonwas required to avoid introducing a new highRe-resolution on the 2.x line pulls
simple-update-notifier@^1.0.7, which declaressemver@~7.0.0and resolves to
semver@7.0.0, carryingGHSA-c2qf-rxjj-qqgw(high) that was not previously inthe tree. The 3.x line uses
simple-update-notifier@^2, which declaressemver@^7.5.3.Pinned to
3.1.11rather than^3: nodemon 3.1.12+ depends onminimatch@10→brace-expansion@5, which declaresengines.nodeof20 || >=22. Recorded inRESOLUTIONS.mdas afixture, with the condition for converting it back to a floor.
Eight devDependencies removed
No reference outside
package.json— leftovers from the jest → vitest migration (3742cca,a5b85b5):vite-plugin-checker,vite-plugin-eslint,vite-plugin-node-stdlib-browser,vite-bundle-visualizer,fake-indexeddb,react-html-parser-ultimate,flow-remove-types,core-js@2.6.9.Two non-dependency changes, both required by the vitest upgrade
Neither is unrelated cleanup.
vitest.config.ts— restores test collection. vitest <1 had two default includepatterns:
["**/__tests__/**/*.?(c|m)[jt]s?(x)", "**/?(*.){test,spec}.?(c|m)[jt]s?(x)"].vitest 3 dropped the first. Six suites here are named
*.specs.ts(plural) and matched onlyvia that
__tests__pattern, so the upgrade silently cut the run from 14 files / 86 tests to8 / 40 — while passing green. The pattern is restored explicitly. This is also why the config
already excluded
**/*.data.ts: the same catch-all matched fixture files.mock.callsproperly, which surfacedthree
TS2532errors under this repository'snoUncheckedIndexedAccess. Fixed by typing themock rather than with a non-null assertion. Separately, vitest 3 warns that an un-awaited
expect().rejectsassertion will stop being auto-awaited; one such assertion is now awaited.🔥 Notes for the reviewer
Run against the consumer of every package whose version changed, not just
yarn install, underNode 18.20.8 (
nvm use) from a cleannode_modules:yarn install --frozen-lockfilenode_modulesyarn typecheckeslint src/{data,domain,scripts,types,utils}yarn lintbelowyarn testyarn buildbuild:dev; webpack 5.109.2 compiled successfullyNeeds a manual look — not covered by the checks above:
src/data/NotificationsEmailRepository.ts— the API shape wasexercised, but not against a live SMTP server.
yarn service— nodemon crossed a major.xlsxitself is unchanged, but they are the heaviest runtimeconsumers in the tool.
Remaining findings
Six alerts are open, in three groups. Grouped by what would close them, because the cheapest action here is
not a code change at all.
Two need a dismissal, not a code change. Neither describes a real vulnerability, and "fixing"
either would be an upgrade that corrects nothing:
GHSA-gv7w-rqvm-qjhragainstesbuild@0.25.12,withdrawn upstream on 2026-06-17, and
GHSA-p5wg-g6qr-c7cgagainsteslint@8.57.1, withdrawn on2026-02-03.
Two are a published fix that cannot be installed here.
serialize-javascript@6.0.2carriesGHSA-5c6j-r48x-rmvq(high) andGHSA-qj8w-gfj5-8c6v(medium). The fix is 7.0.5, which declaresengines.node >=20.0.0; thecopy-webpack-pluginrelease that requests the 7.x line declares>=20.9.0. That is a different conclusion from "no fix exists", and it is recorded as such. Buildtooling only — it is not part of the built artifact.
Two are a genuine dead end on npm.
xlsx@0.18.5carriesGHSA-4r6h-8v6p-xvw6andGHSA-5pgg-2g8v-p4x9, both high, both with no patched version recorded. Checking the publishedversion list rather than only the advisory confirms it:
npm view xlsx dist-tagsreturnslatest: 0.18.5, because SheetJS stopped publishing to npm at that version and moved to their ownCDN. No registry-selectable version escapes the ranges. Runtime-reachable when parsing a workbook
supplied from outside this repository. The two routes out — installing from the SheetJS CDN tarball,
which puts a non-registry URL in the lockfile, or migrating the two call sites to
xlsx-js-style,which this repository already depends on — are both decisions in their own right and are
deliberately not taken here.
Follow-up work
Three changes are out of scope here and each is worth doing on its own. Listed with what it closes,
because two of them are the reason anything remains open at all.
serialize-javascriptfindings, and retires a resolution@eyeseetea/d2-apid2-api📹 Screenshots/Screen capture
None
📑 Others
Any change in the D2 Api? No change is required for this
PR to merge, but one is worth making.
@eyeseetea/d2-apideclaresaxios,lodashandqsas exact versions in every published release up to and including 1.21.0 and
42.22.0-beta.2.axios: 1.6.4alone had accumulated 29 live advisories and structurally cannotreceive a patch. Because the pins are exact, every consuming application inherits all three and
has to write the same three resolutions — which is exactly what
metadata-synchronization#1264,
Bulk-Load#413,
home-page-app-dev#71 and this PR have
each done independently. Relaxing them to floors upstream would retire those entries across every
consuming repository at once. Not raised yet.
Two pre-existing issues found while verifying this branch. Neither is caused by this PR and
neither is fixed here.
The Bundlemon check has never passed — it fails on every run since 2026-06-22, including on
feature/add_githubactionsitself, so the red mark on this PR is not new. The cause is a pathmismatch: the shared
.bundlemonrcinEyeSeeTea/github-workflowsdeclares"baseDir": "./build", while this project is a Node CLI whose webpack config outputs todist/,so BundleMon finds nothing to measure. The workflow already supports the fix — it looks for a
.bundlemonrcin the caller repository first and only falls back to the shared one — so addingone here with
"baseDir": "./dist"resolves it.yarn serviceno longer does anything useful, andnodemoncould go with it.nodemon.jsonruns./src/indexwith no subcommand, so the CLI prints its usage and exits andthe watcher reports
app crashedon every reload. That dates from 2022, whensrc/index.tswasa single dataset-comparison script, and stopped making sense once the entry point became a
multi-command dispatcher; it is undocumented in the README.
nodemonis the only consumer ofthat script, so removing both would drop 11 packages and retire the manifest's only
exact-version pin —
nodemonis held at3.1.11because 3.1.12+ pullsminimatch@10→brace-expansion@5, which requires Node 20. That pin exists solely to keep a broken scriptinstallable;
yarn start:dev <command>covers the same need.