Conversation
GHSA-2883-xcg3-v3hh (high) affects js-yaml >= 3.0.0 < 3.15.2 and >= 4.0.0 < 4.3.2. depcheck requests ^3.14.1 and @eslint/eslintrc requests ^4.3.0, so both ranges already admit the patched releases and re-resolving the lockfile is the whole fix, with no manifest change.
GHSA-x5fp-wj9c-mxmx affects qs >= 6.14.2 <= 6.15.3 and GHSA-4mjr-xmp4-gh2g affects qs >= 2.2.5 < 6.16.0 (both medium). The existing qs: ^6.15.3 resolution already admits 6.16.0, so re-resolving the lockfile is enough and the resolution is left unchanged. qs is runtime: @eyeseetea/d2-api only calls qs.stringify(params, { arrayFormat: "repeat" }), and its output is identical between 6.15.3 and 6.16.0 for representative DHIS2 query parameters.
GHSA-82fw-gwwq-j7x9 (medium) affects vitest and @vitest/mocker >= 2.1.0 < 4.1.11, and the 3.x line has no fix, so the upgrade is a major. In vitest 4 the test key is only added to vite's UserConfig by vitest/config, so vite.config.ts now references that entry point; with the old reference the tests still ran but the config no longer type-checked. RESOLUTIONS.md gains a note for applications copying this baseline, including the vite 8 lockfile entry vitest 4 brings without installing it.
The config function's { mode } argument and the proxy rewrite's path
parameter were untyped. tsconfig.node.json is not strict, so neither
was reported. Type them as ConfigEnv and string, and rename the
rewrite parameter so it no longer shadows the path import.
BundleMonNo change in files bundle size Groups updated (1)
Final result: ✅ View report in BundleMon website ➡️ |
@dhis2/d2-i18n-extract and @dhis2/d2-i18n-generate are archived and will not receive fixes. @dhis2/cli-app-scripts does the same job and is maintained, so it replaces them in devDependencies, and extract-pot and localize now call d2-app-scripts. It is pinned at exactly 12.11.1: 12.11.3 and 12.11.4 add __MANIFEST_APP_TITLE and __MANIFEST_APP_DESCRIPTION to en.pot and to the generated translations when there is no d2.config.js, and this project builds its manifest with d2-manifest. en.pot keeps the same 39 msgids; its msgstr is now filled with the source string, which does not change what i18n.t() returns for any key in en or es. The new tool brings an outdated transitive chain (31 findings in yarn npm audit). The next commit pins it.
Nine scoped resolutions bring yarn npm audit from 31 findings back to
elliptic, request and uuid, none of which has a published fix. No parent in
the chain has a release that selects a patched version, including
@dhis2/cli-app-scripts 12.11.5. Each resolution was verified by calling the
code that uses the package, not only by installing it:
- @dhis2/cli-app-scripts/vite ^6.4.3: build/start modules load, vite 6.4.3
- @dhis2/cli-helpers-engine/tar ^7.5.21: fetchAndExtract downloads and
extracts a tarball from a local server
- execa@npm:0.7.0/cross-spawn ^6.0.6: execa 0.7 sync, shell, ENOENT and
async paths, and term-size
- external-editor/tmp ^0.2.7: editor temp file created and cleaned up
- http-proxy-agent/@tootallnate/once ^2.0.1: request through a local proxy
- latest-version/package-json ^7.0.0: latestVersion() on a local registry
- request/form-data ^2.5.6 and request/tough-cookie ^4.1.3: multipart
upload and cookie jar through request
- styled-jsx/loader-utils ^1.4.2: styled-jsx webpack loader options
package-json/got ^11.8.5 was tried first and breaks package-json 6 ("The GET
method cannot be used with a body"); lifting package-json to 7 brings got 11
through a release written for it. tmp is floored at 0.2.7 because
GHSA-7c78-jf6q-g5cm affects exactly 0.2.6.
RESOLUTIONS.md documents the new entries, request and uuid as known
findings, and the rejected got pin. It also rewrites two conventions that
measurement contradicted on Yarn 4.15.0 and 4.12.0: a versioned-parent key
uses the resolved version, not a descriptor, and it can select a version
outside the parent's declared range. It lists the advisories the qs floor
really covers, and drops the history of retired pins, dates in headings, the
archived-i18n rationale and the future-improvements list, which moved to
tickets.
# Conflicts: # yarn.lock
xurxodev
left a comment
There was a problem hiding this comment.
thanks @anagperal
1. Should fix
-
The gate fails on two new high alerts, not only on
uuid/request. The run on 134b29d reportsNew alert instances vs base: high=2 medium=1:- #735
uuid@3.4.0, GHSA-w5hq-g745-h8pq. Dependency-Track scores it high and GitHub medium. It is already documented as not reachable and unfixable. - #649 GHSA-gv7w-rqvm-qjhr against esbuild. The alert still shows
esbuild@0.18.20because it reuses an older alert frommaster. The current tree has no esbuild 0.18.x: the SBOM generated the same way as CI only containsesbuild@0.25.12(pulled in by@dhis2/cli-app-scripts/vite: ^6.4.3) and0.28.1. GitHub withdrew this advisory, but Dependency-Track still reports it. - #734
request@2.88.2(medium) does not block.
The description only mentions
uuid/requestas the reason the gate fails. Please add the esbuild alert as well. Whatever decision unblocks the gate (dismissing the alerts in code scanning, or suppressing them in Dependency-Track so the VEX picks them up) has to cover both alerts, unless esbuild is removed as in recommendation 1 below. - #735
-
Re-run the gate and re-audit before merging. The last run is from 22-09. Today
yarn npm audit --recursiveon 134b29d reports 31 findings, none of them in the PR description:axios×12,brace-expansion×9,undici×3,fast-uri,markdown-it,moment,serialize-javascript,elliptic,requestanduuid. Several are high. Some of them may show up in Dependency-Track as new compared withmaster, which would keep the gate red even after the two alerts above are dealt with. The audit cadence inRESOLUTIONS.mdasks for a re-audit right before requesting review on a change that claims a clean gate.
2. Recommendations non blocking
- Option: remove the esbuild alert instead of dismissing it. Changing the resolution in
package.jsonfrom"@dhis2/cli-app-scripts/vite": "^6.4.3"to"^7.3.6"takesesbuild@0.25.12out of the tree. Everything then resolves toesbuild@0.28.1, which is outside the advisory range (>= 0.17.0, < 0.28.1). vite also collapses to a single 7.3.6 shared with the application, andyarn.lockloses about 390 net lines (+65 / −454). Checked locally on 134b29d
Re-resolve brace-expansion, undici, markdown-it, fast-uri, serialize-javascript and moment within their declared ranges. Raise the axios floor to 1.20.0 and pin d2-ui-components' exact moment 2.29.4 request to ^2.31.0, documented in RESOLUTIONS.md.
vite 6 pulls esbuild 0.25.12, which Dependency-Track still reports against the withdrawn GHSA-gv7w-rqvm-qjhr. Sharing the application's vite 7.3.6 leaves only esbuild 0.28.1 in the tree.
Thanks @xurxodev, all three points are addressed!
|
ℹ️ Why the gate fails:
masterstill uses the archived i18n tools (d2-i18n-extract/d2-i18n-generate) and has never had@dhis2/cli-app-scriptsin its tree. This PR introduces it (a decision already made: maintained-with-vulnerabilities over archived-and-unmaintained), anduuid/requestarrive with it, so the gate counts them as introduced by the PR because they genuinely did not exist inmasterbefore. Not a stale-baseline artifact:masterwas rescanned on 2026-10-02 before the last run. It's a real clash between the dependency decision and how the gate compares. The only high left is #735uuid@3.4.0(requestis medium and does not block), and it needs an approved dismissal before this can merge.📌 References
📝 Implementation
Four things, in this order:
masterafter [Security] resolve dependency vulnerabilities #120 that have a published fix.@dhis2/d2-i18n-extractand@dhis2/d2-i18n-generateto the maintained@dhis2/cli-app-scripts, with the resolutions its dependency chain needs.RESOLUTIONS.mdis corrected, including two conventions that turned out to be wrong when measured.master.1. Alerts open on
masterAfter #120,
masterhad 7 open alerts, and Dependabot and Dependency-Track agreed on all 7. The 6 with a published fix are closed here:js-yamldepcheck(^3.14.1),@eslint/eslintrc(^4.3.0)qs@eyeseetea/d2-apiandurl, through theqs: ^6.15.3resolutionvitest,@vitest/mocker^3.2.7→^4.1.11qsis runtime.@eyeseetea/d2-apionly callsqs.stringify(params, { arrayFormat: "repeat" }), and its output is identical between 6.15.3 and 6.16.0 over representative DHIS2 query parameters. The resolution stays at^6.15.3, since it already admits the fix./// <reference types="vitest/config" />invite.config.ts: in vitest 4 onlyvitest/configadds thetestkey to vite's config types. Same 13 test files and 137 tests, no snapshot rewritten.yarn.locknow contains avite@8.2.2entry that is not installed: vitest 4 declaresviteas both a dependency and a peer, and the peer wins, soyarn why vite -Rlists only the application's vite.refactor(config)commit removes two implicitanytypes fromvite.config.ts.elliptic@6.6.1(low) stays: every published version is affected.2. i18n tooling:
@dhis2/cli-app-scriptsThe archived packages receive no fixes when a new advisory lands, and a maintained tool is preferred even when its dependency chain carries findings.
@dhis2/cli-app-scriptsgoes indevDependencies.extract-potbecomesd2-app-scripts i18n extract -p src/ -o i18n/, andlocalizebecomesyarn update-po && d2-app-scripts i18n generate -n dhis2-skeleton-app -p ./i18n/ -o ./src/locales/.12.11.1. 12.11.3 and 12.11.4 add__MANIFEST_APP_TITLEand__MANIFEST_APP_DESCRIPTIONtoen.potand to the generated translations whenever there is nod2.config.js. They are meant for DHIS2 app platform manifests, and this project builds its manifest withd2-manifest. With 12.11.1,en.potkeeps the same 39msgids asmasterand the generated translations the same 42 keys. The other way to avoid them, ad2.config.jswith no entry points, would present this project as an app platform app, which it is not. Same version as metadata-synchronization.i18n.t()was compared for every key inenandes, with the translations generated before and after: 0 differences. The only difference in the generated files is thaten.potgets itsmsgstrfilled with the source string instead of left empty.The chain's cost, and how it is paid back. Adding the package took
yarn npm audit -Rfrom 1 finding to 31 (3 critical, 14 high, 11 moderate, 3 low). Every parent was checked for a release that selects a patched version, and none has one, so the remaining step of the remediation ladder is a scoped resolution per path. Nine were added, and each was verified by calling the code that uses the package, not only by installing or loading it:@dhis2/cli-app-scripts/vite: ^7.3.6yarn localizestill extracts and generates the translations;build/startcommand modules load andimport('vite')resolves to 7.3.6; the i18n commands do not load vite@dhis2/cli-helpers-engine/tar: ^7.5.21fetchAndExtractdownloads a.tar.gzfrom a local server withrequestand extracts it with tar 7execa@npm:0.7.0/cross-spawn: ^6.0.6execa@0.7.0sync,shellSync,ENOENThook and async API, andterm-sizeitselfexternal-editor/tmp: ^0.2.7ExternalEditorcreates and cleans up its temp filehttp-proxy-agent/@tootallnate/once: ^2.0.1latest-version/package-json: ^7.0.0latestVersion()against a local registryrequest/form-data: ^2.5.6requestrequest/tough-cookie: ^4.1.3requestcallsstyled-jsx/loader-utils: ^1.4.2Four details worth reading:
package-json/got: ^11.8.5was tried first and breaks its consumer.package-json@6loads fine and every lookup then fails withThe GET method cannot be used with a body: it passesjson: true, which got 9 reads as "parse the response" and got 11 as "send a JSON body". Lifting the parent instead, topackage-json@7, brings got 11 through a release written for it. Recorded under "Rejected pins".tmpis floored at 0.2.7, not 0.2.6. GHSA-7c78-jf6q-g5cm affects exactly>= 0.2.6, < 0.2.7, so^0.2.6would admit a vulnerable release.cross-spawn@5.1.0is fixable, contrary to what the conventions said. See below.esbuild@0.25.12, which Dependency-Track reports against GHSA-gv7w-rqvm-qjhr (>= 0.17.0, < 0.28.1). GitHub withdrew that advisory on 2026-06-17, but the alert (#649) still blocked the gate. With the floor at 7.3.6,@dhis2/cli-app-scriptsshares the application's vite, the tree only hasesbuild@0.28.1, andyarn.lockloses 326 net lines. Neither vite 7.3.6 nor esbuild 0.28.1 has an open advisory.elliptic@6.6.1(above),request@2.88.2(GHSA-p8p7-x288-28g6, no patched version, deprecated since 2020) anduuid@3.4.0(GHSA-w5hq-g745-h8pq).uuidcannot be forced to the patched 11.1.1 becauserequestimports theuuid/v4subpath removed in v7, and it is not reachable:requestonly callsv4()with no arguments. All three are build tooling and documented inRESOLUTIONS.md.3.
RESOLUTIONS.mdTwo conventions were wrong, and were measured before being rewritten. The file said a versioned-parent path must use the descriptor, and cannot select outside the parent's declared range. On Yarn 4.15.0, and the same on 4.12.0:
glob@npm:7.2.3/minimatch: 3.1.2binds, whileglob@npm:^7.1.3/minimatch: 3.1.2does nothing, although^7.1.3is a real descriptor.execa@npm:0.7.0/cross-spawn: ^6.0.6selects 6.0.6 althoughexeca@0.7.0declares^5.0.1.Both rules are rewritten from these measurements, and a new one says a floor must name the highest patched version of the advisories it covers.
The file now holds only what a maintainer needs today: active resolutions, rejected pins and known findings without a fix. Removed: "Why the archived i18n packages are still here" (superseded by the switch above), "Future improvements" (moved to tickets), the history of retired pins ("Removed", "Considered and dropped"), and dates in headings. That history stays in git and in [Security] resolve dependency vulnerabilities #120.
"Notes for applications copying this baseline" keeps only the couplings an application may not need: vite 7 without ESLint 9, vitest 4, and the i18n switch with its exact
12.11.1.Smaller fixes: the fixtures get their own section, the
node-gettextentry names the parent that actually requests it, and theqsentry lists the advisories its floor really covers (GHSA-6rw7, GHSA-q8mj, GHSA-w7fw) and warns that GHSA-4mjr and GHSA-x5fp are only closed because the lockfile resolves 6.16.0.4. Advisories published after the first audit
Re-audited after merging
masterand rescanning it: 29 new Dependency-Track alerts, all from advisories published between 2026-09-28 and 2026-09-30, all on packages also present onmaster, and all with a published fix that clears the 7-daynpmMinimalAgeGate.axios@eyeseetea/d2-api,@eyeseetea/feedback-component,@dhis2/cli-app-scripts, through theaxiosresolution^1.18.0→^1.20.0brace-expansionminimatch3, 5 / 7 / 9, and 10undicinode-gypmarkdown-ittypedocmoment@dhis2-ui/header-bar,@dhis2/app-shell,@dhis2/d2-i18n;@eyeseetea/d2-ui-components(exactly2.29.4)@eyeseetea/d2-ui-components/moment: ^2.31.0fast-uriajv8serialize-javascript@rollup/plugin-terseraxiosis runtime. Verified with a GET, a POST and a redirect against a local server, and with an authenticatedD2Apirequest. The lockfile alone would have reached 1.20.0, but the floor goes up too, since a floor has to name the version that fixes every advisory it covers.momentneeds a resolution for one path.@eyeseetea/d2-ui-componentsrequests exactly2.29.4, and 2.13.0, its latest release, still does. It is runtime:DatePickerwas rendered, its calendar opened and a day picked, andformatRowValueandformatDateLonggive the same output for ISO strings andDatevalues. moment 2.31.0 adds adevEnginesNode range, which applies only to moment's own development;engines.nodeis still*.minimatchmajor with itsbrace-expansion,ajv8 compiling a schema withfast-uri,markdown-itrendering,undicifetchagainst a local server, andserialize-javascript.Verification
Run on Node 24.13.1 / Yarn 4.15.0:
yarn install --immutableyarn check(typecheck, prettier, lint, tests)master, which adds the ESLint rule spec)yarn buildlocalize, the manifest and the zip stepyarn localizeen.pothas the same 39msgids asmaster, no__MANIFEST_*keys;t()output identical for every key inenandesyarn npm audit -Relliptic,request,uuid📹 Screenshots/Screen capture
None
🔥 Notes to the tester
Node 24 is required (
.nvmrc): runnvm usefirst.yarn install, thenyarn start: the app loads, a screen that fetches data from DHIS2 works, a date picker opens and accepts a date, and switching the user language to Spanish shows the Spanish strings.yarn localize: completes;git diff i18n/shows only generation timestamps.yarn check(14 files, 144 tests) andyarn build.yarn npm audit -R: onlyelliptic,requestanduuid.yarn why cross-spawn -R: 6.0.6 underexeca@0.7.0and 7.0.6 elsewhere, no 5.x.yarn why vite -R: 7.3.6 for both@dhis2/cli-app-scriptsand the app. Thevite@8.2.2entry inyarn.lockis expected and is not installed.yarn why esbuild -R: only 0.28.1.yarn why moment -R: only 2.31.0.elliptic,request,uuid;uuidis the only high, pending an approved dismissal.