Repository navigation
Keep the pnpm lockfiles readable for GitHub's dependency graph - #7
Merged
Merged
Conversation
pnpm 12 writes pnpm-lock.yaml as two YAML documents when packageManager pins pnpm 12 or newer. The first document holds only pnpm's own binaries, and GitHub's static dependency-graph parser reads only that one (dependabot/dependabot-core#15904), so the dependency graph and Dependabot alerts see no npm package from the Jest and WebdriverIO demos. pmOnFail: ignore is the setting the pnpm maintainers name as the supported way to get a single document (pnpm/pnpm#13805). It also stops pnpm from switching itself to the packageManager version, so that pin now reaches CI through pnpm/action-setup and local shells through Corepack. The lockfile change only removes the first document. What remains is byte-identical to the old second document, so no resolved version changed.
|
The account paying for this security review has reached its Codex usage limits. The payer can check the Codex usage dashboard. For personal accounts, using credits requires enabling “Use credits for security reviews” in Code review settings. If you do not manage the paying account, contact this repository's admins. |
basic-ftp 5.3.1 is affected by GHSA-c475-qrg2-pj4r (high, fixed in 6.2.1) and GHSA-5rfr-xx34-2xxv (moderate, fixed in 6.2.2), and no 5.x release carries either fix. @wdio/utils reaches it through @puppeteer/browsers, proxy-agent, pac-proxy-agent and get-uri 6.0.5, and get-uri asks for ^5.3.1 even in its newest release, 8.0.1, so no parent update gets out of the 5.x line. An override scoped to basic-ftp@5 is the only way to the fix. TooTallNate/proxy-agents#500 makes the same bump upstream. basic-ftp 6.0 has one break: a passive data connection to a host other than the control host now needs allowSeparateTransferHost. get-uri calls access, lastMod, list and downloadTo, which did not change, and get-uri 6.0.5 with 6.2.2 fetched a PAC file from a local FTP server. 6.2.2 was published on 2026-10-04 and is younger than pnpm's built-in one-day minimumReleaseAge. That default is not strict, so pnpm wrote basic-ftp@6.2.2 into minimumReleaseAgeExclude on its own. The entry is kept with a comment that says when it can go. A plain pnpm install --lockfile-only also deduplicated @types/node 22.7.8 onto 24.13.4. The lockfile here changes only basic-ftp; pnpm 12.4.1 leaves it byte-identical on install --lockfile-only and installs it with --frozen-lockfile.
This undoes the basic-ftp override from the previous commit. basic-ftp 5.3.1 stays in the lockfile and its alerts get dismissed with a reason, because nothing in this repository can reach the vulnerable code. GHSA-c475-qrg2-pj4r and GHSA-5rfr-xx34-2xxv need a client that connects to an FTP server the attacker controls and calls list() or falls back to PASV. Here basic-ftp is loaded only by get-uri's ftp: handler. get-uri is called only by pac-proxy-agent, which proxy-agent creates only for a pac+ftp:// style proxy URL. @puppeteer/browsers builds new ProxyAgent() with no options, so the proxy comes only from the npm_config_*_proxy, *_proxy and all_proxy environment variables. No workflow, script, config or .npmrc in this repository sets any of them. The lockfile goes back byte for byte to the previous commit's version: the overrides block is gone and get-uri resolves basic-ftp 5.3.1 again.
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.
Adds
pmOnFail: ignoreto thepnpm-workspace.yamlof each pnpm demo (jest-fail-on-console, jest-msw, jest-parameterized, webdriverio) and regenerates their fourpnpm-lock.yamlfiles as single YAML documents, so GitHub's dependency graph and Dependabot can see the npm packages.Why
pnpm 12 writes
pnpm-lock.yamlas two YAML documents wheneverpackageManagerpins pnpm 12 or newer. The first document lists only pnpm and its@pnpm/exe.*binaries. GitHub's static dependency-graph parser forpnpm-lock.yamlreads only that first document. So once the graph builds, it lists no npm package from this repository, Dependabot opens no alert for one, and Renovate'svulnerabilityAlertspull requests, which start from those alerts, never appear.Upstream:
pmOnFail: ignoreas the supported way to get a single document.What changed
pnpm-workspace.yamlfiles:pmOnFail: ignore, with a comment that links dependabot-core#15904 and says when the setting can go.pnpm-lock.yamlfiles: the first document (pnpm's own binaries) is gone. Line 1 is nowlockfileVersion: '9.0'and no file has a---separator.The artillery demo has no lockfile, and nothing else in the repository changes.
Trade-off
With
pmOnFail: ignore, pnpm stops checking thepackageManagerpin. It no longer switches itself to that version, and it does not warn or fail. Whatever pnpm is onPATHruns.pnpm/action-setupreadspackageManagerand installs that exact version itself, so CI does not rely on pnpm switching. The artillery job prepares pnpm 12.4.1 through Corepack and has nopackage.json, so it is unaffected..github/scripts/check_all_demos.shenables Corepack when pnpm is missing, and Corepack runs the pinned version. If a pnpm is already onPATHthat is not the Corepack shim, the script now runs that version in the demos instead of pnpm switching to 12.4.1. A pnpm installed another way runs as its own version. I ran pnpm 12.8.1 against each new lockfile: it reported "using pnpm v12.8.1" instead of switching, which shows pnpm reads the setting, and it left the lockfile byte-identical.pnpm install --frozen-lockfileno longer fails whenpackageManageris bumped without regenerating the lockfile, because nothing about pnpm is recorded there to drift.configDependenciesis ever added, pnpm writes the first document again regardless of this setting.The comment next to the setting links #15904 and says when it can go: once GitHub's graph lists the packages from the second document. Removing it then also means letting pnpm write the two-document lockfile again.
No resolved version changed in the first commit
pnpm does not delete an existing first document by itself: on a scratch project with pnpm 12.6.0,
install --lockfile-onlyandinstallboth left the two-document file in place after the setting was added. So for each lockfile I saved the old file, removed everything up to the second---, rancorepack pnpm@12.4.1 install --lockfile-only(the pinned version), thencorepack pnpm@12.4.1 install --frozen-lockfile.diffof each old second document against the new lockfile is empty, and the sortedpackages:keys match before and after: 324 (jest-fail-on-console), 357 (jest-msw), 323 (jest-parameterized), 551 (webdriverio).In that commit each lockfile diff is 158 deleted lines: the 157-line pnpm document plus its
---separator. Nothing was added or changed.Checks run
corepack pnpm@12.4.1 install --frozen-lockfilein all four demos, in this checkout and in a freshgit clone --depth 1of the branch: all pass, the lockfiles stay single-document, the worktree stays clean.pnpm test --ci --json, then.github/scripts/check_results.py): jest-fail-on-console OK (3 results, with the deliberateconsole.errorfailure expected), jest-msw OK (1), jest-parameterized OK (3).pnpm exec tsc --noEmit -p .passes. I did not run the browser test..github/scripts/check_all_demos.sh --no-codex, because it also builds the Java demos and starts containers. CI on this pull request runs every demo.Dependency graph and Dependabot settings here
Read through the API, nothing changed:
GET /repos/martinfrancois/testing-toolbox/vulnerability-alertsreturns 204, so Dependabot alerts are enabled. Dependabot security updates are disabled.dependencyGraphManifestshastotalCount: 0, not even the workflow files. The REST API has no field that shows whether the graph itself is switched on, and a public repository normally has it on, so why GitHub builds no graph here is still open.Once the graph builds, it should list the npm packages from all four lockfiles. webdriverio's lockfile holds two versions with known high advisories that no alert shows today: extract-zip 2.0.1 (GHSA-jmr9-qjv8-65gv, GHSA-7pqw-9j4j-h8q3, no patched release) and braces 3.0.3 (GHSA-vfj7-8cjw-p6xm, no patched release). Expect those alerts then. basic-ftp 5.3.1 is a third (GHSA-c475-qrg2-pj4r, high). It stays at 5.3.1, see the last section.
basic-ftp stays at 5.3.1
The second commit,
cb43506, moved webdriverio's basic-ftp from 5.3.1 to 6.2.2 with an override. The third commit,59fed66, takes that back out. The repository owner decided to dismiss the basic-ftp alerts instead, on the condition that the current code shows the vulnerable code cannot be reached. It cannot:list(), or falls back toPASV.webdriverio/pnpm-lock.yaml:@wdio/utils 9.31.5 > @puppeteer/browsers 2.13.2 > proxy-agent 6.5.0 > pac-proxy-agent 7.2.0 > get-uri 6.0.5 > basic-ftp 5.3.1. Each of those packages has exactly one dependent in the lockfile, and innode_modulesonlyget-uri/dist/ftp.jsrequires basic-ftp.@puppeteer/browsers(lib/esm/httpUtil.js) buildsnew ProxyAgent()with no options, so proxy-agent asksproxy-from-envfor the proxy, which reads only thenpm_config_<proto>_proxy,<proto>_proxy,npm_config_proxyandall_proxyenvironment variables. proxy-agent loads pac-proxy-agent only for apac+…proxy URL, pac-proxy-agent stripspac+and hands the rest to get-uri, and get-uri uses basic-ftp only for anftp:URL. So basic-ftp runs only when one of those variables holds apac+ftp://URL.proxyandftpover every tracked file finds only the lockfile, the unrelated Toxiproxy demo, Gradle wrapper jars and base64 data in the bundled Allure report, the repository has no.npmrc,wdio.conf.tssets noproxycapability, and.github/workflows/ci.ymland.github/scripts/check_all_demos.shset no proxy variable.artillery@latestthroughpnpm dlx. That tree is in no lockfile, so it gets no alert, and an override inwebdriverio/would not reach it either.After
59fed66the webdriverio lockfile is byte for byte the one from the first commit: theoverridesblock is gone and get-uri resolves basic-ftp 5.3.1. TheminimumReleaseAgeExcludeentry is gone with it.Checks for the third commit,
corepack pnpm@12.4.1inwebdriverio/:pnpm install --lockfile-only: lockfile byte-identical afterwards, still one YAML document, line 1lockfileVersion: '9.0'.pnpm install --frozen-lockfilewithnode_modulesremoved first: passed, worktree clean.pnpm why basic-ftp: one version, 5.3.1. Resolving basic-ftp from get-uri's directory gives 5.3.1.pnpm exec tsc --noEmit -p .: passed.🤖 Generated with Claude Code