Tested with pnpm 12.16.1 and Component Detection 8.0.8 · Updated
Dependabot alerts closed as "fixed" after a pnpm 12 upgrade, and the dependency graph only shows pnpm
If your repository pins pnpm 12, or pins pnpm 11 through devEngines., GitHub may have stopped seeing your npm dependencies. The dependency graph under Insights can list pnpm and a set of @pnpm/exe.* packages and nothing else from pnpm-lock.yaml. Existing alerts for dependencies missing from the graph may close as fixed, while new alerts and security updates for them may not be created.
GitHub says so in its own changelog: when pnpm writes pnpm-lock.yaml as two YAML documents, "the dependency graph doesn't detect the dependencies in that file yet", and "Dependabot alerts and security updates won't be created for those dependencies, and existing alerts for them may close."
Still broken as of 2 November 2026, 00:08 UTC. The dependency graph of a public reproduction repository still listed only pnpm 12.14.0 and its 14 @pnpm/exe.* packages, not the two packages the project installs. On 30 October, a reply on dependabot/
On this page:
Look for a large lockfile-to-graph mismatch, using a limited check script.
A tested workaround: switch off pnpm's built-in version check, and what it costs.
Keep the version check: submit the dependency graph from CI, which we tested with pnpm's version check on.
If you scan the lockfile in CI: Component Detection 8.0.4 returns success while omitting the project's npm dependencies in our test.
Why it happens
When package.json pins pnpm through packageManager (or devEngines.), pnpm 12 records the pnpm version it resolved inside pnpm-lock.yaml. It writes that record as a separate YAML document at the top of the file, and the project's own dependencies follow in a second document. The file then starts with a line that reads ---. pnpm's lockfile documentation calls the first one the boot document. Both documents declare lockfileVersion: '9.0', so nothing in the version field changes.
We reproduced this with pnpm 12.16.1, the current release, in a project with three dependencies and "packageManager": "pnpm@12.16.1": pnpm install --lockfile-only wrote a 212-line lockfile whose first line is ---, with the pnpm record in the first document and the project's packages in the second.
In the reproduction repository we checked, the exported graph contained pnpm and its platform packages from the boot document, but neither project package from the second document. That is consistent with the graph reading only the first document. GitHub confirms that two-document lockfiles are not yet fully detected; alerts for missing dependencies may close, and new alerts and security updates for them may be absent.
On one public repository, the reporter's follow-up on pnpm/pnpm#13805 says 27 open alerts closed six to seven seconds after the merge that introduced the two-document lockfile; the initial total of 35 included eight alerts that were already closed.
pnpm 11 does the same when package.json has devEngines.: in our runs, pnpm 11.18.0 and 11.28.9 wrote two documents with it and one with packageManager alone. pnpm's documentation names one other trigger: a project with config dependencies gets the boot document too, whatever the version settings.
Check your repository
This heuristic compares exact package versions parsed from a root two-document pnpm-lock.yaml with GitHub's exported dependency graph. It can flag a large mismatch; it cannot prove that the graph is complete or that Dependabot alerts work. It uses sh, curl, awk, sed, grep, tr, wc, head, mktemp, rm and sleep.
It uses GitHub's asynchronous SBOM export: it asks GitHub to generate a report of the repository's dependency graph, checks every 5 seconds whether the report is ready, and gives up after 61 checks (5 minutes of waiting between them, plus the time the requests take). Our whole runs took 2 to 37 seconds. Each run starts one report; GitHub's response headers gave our token a separate limit of 100 report requests an hour.
Updated 2 November 2026: this script replaces the version first published here on 2 November 2026. That version used GitHub's synchronous SBOM export endpoint, which GitHub says will not be accessible after 13 November 2026. It also printed OK without comparing anything when the lockfile had Windows (CRLF) line endings or when given a renamed repository's old name. If you saved it, replace it.
#!/bin/sh
# Usage: GITHUB_TOKEN=... sh check.sh OWNER/REPO [REF]
# Needs curl, awk, sed, grep, tr, wc, head, mktemp, rm, sleep. Sends the token to api.github.com only.
# AFFECTED = pnpm-lock.yaml has two YAML documents (first line '---') AND under 90% of the name@version keys in
# its second document's packages: section appear in GitHub's dependency-graph SBOM (asynchronous export).
# Exit 1 affected, 0 ok, 2 cannot check (including a failed transfer, keys it cannot parse, or no finished report
# after 61 checks 5 seconds apart).
R=$1; REF=${2:-HEAD}; API=https://api.github.com; V="X-GitHub-Api-Version: 2026-03-10"
case $R in ""|/*|*/|*/*/*|.*/*|*/.|*/..|*[!A-Za-z0-9._/-]*) echo "cannot run: give OWNER/REPO"; exit 2;; */*) ;; *) echo "cannot run: give OWNER/REPO"; exit 2;; esac
case $REF in *[!A-Za-z0-9._/-]*) echo "cannot run: REF may contain only letters, digits and . _ / -"; exit 2;; esac
[ -n "$GITHUB_TOKEN" ] || { echo "cannot run: GITHUB_TOKEN is empty"; exit 2; }
D=$(mktemp -d) || { echo "cannot create a temporary directory"; exit 2; }
trap 'rm -rf "$D"' EXIT; trap 'exit 2' HUP INT TERM
printf 'Authorization: Bearer %s\n' "$GITHUB_TOKEN" >"$D/auth" # header file keeps the token out of ps
# get URL FILE MEDIA-TYPE WHAT: GET with the token, following redirects only within api.github.com. Sets $code, $loc.
# curl -q (first) skips any .curlrc, so no config file can add a transfer or change redirects.
get() {
u=$1; hops=0
while :; do
r=$(curl -q -sS --proto =https -m 300 -H @"$D/auth" -H "Accept: $3" -H "$V" -o "$2" -w '%{http_code} %{redirect_url}' "$u") ||
{ echo "cannot read $4: transfer failed (curl exit code $?)"; exit 2; }
code=${r%% *}; code=${code:-000}; loc=${r#"$code"}; loc=${loc# }
case $code$loc in 30[1278]https://api.github.com/*) hops=$((hops+1)); [ $hops -le 3 ] && { u=$loc; continue; };; esac
return 0
done
}
why() { m=$(sed -n 's/.*"message": *"\([^"]*\)".*/\1/p' "$1" 2>/dev/null | head -1); echo "HTTP $code${m:+ ($m)}"; }
get "$API/repos/$R/contents/pnpm-lock.yaml?ref=$REF" "$D/raw" application/vnd.github.raw+json lockfile
[ "$code" = 200 ] || { echo "cannot read lockfile: $(why "$D/raw")"; exit 2; }
tr -d '\r' <"$D/raw" >"$D/lock"
grep -q '^lockfileVersion:' "$D/lock" || { echo "cannot read lockfile: no lockfileVersion line"; exit 2; }
get "$API/repos/$R/dependency-graph/sbom/generate-report" "$D/gen" application/vnd.github+json SBOM
u=$(sed -n 's/.*"sbom_url": *"\([^"]*\)".*/\1/p' "$D/gen" | head -1)
case $code$u in 201https://api.github.com/*) ;; *) echo "cannot read SBOM: generate-report gave $(why "$D/gen")"; exit 2;; esac
i=0; while get "$u" "$D/poll" application/vnd.github+json SBOM; [ "$code" = 202 ] && [ $i -lt 60 ]; do i=$((i+1)); sleep 5; done
[ "$code" = 202 ] && { echo "cannot read SBOM: GitHub had not finished the report after 61 checks 5 seconds apart; try again later"; exit 2; }
case $code$loc in 302https://*) ;; *) echo "cannot read SBOM: fetch-report gave $(why "$D/poll")"; exit 2;; esac
r=$(curl -q -sS --proto =https -m 300 -o "$D/sbom" -w '%{http_code}' "$loc") || # signed download URL: no token
{ echo "cannot read SBOM: download failed (curl exit code $?)"; exit 2; }
[ "$r" = 200 ] || { echo "cannot read SBOM: download gave HTTP ${r:-000}"; exit 2; }
grep -q '"spdxVersion"' "$D/sbom" || { echo "cannot read SBOM: download is not an SPDX document"; exit 2; }
first=$(head -1 "$D/lock"); docs=$(grep -c '^---$' "$D/lock")
if [ "$first" = "---" ] && [ "$docs" -ge 2 ]; then w=2; elif [ "$first" = "---" ]; then w=1; else w=0; fi
awk -v w=$w '/^---$/{d++; next} d!=w{next} /^packages:/{p=1; next} /^[^ ]/{p=0} p && /^ [^ ]/' "$D/lock" >"$D/keys" ||
{ echo "cannot read lockfile: awk failed (exit code $?)"; exit 2; }
grep -E "^ '?[^ ].*@[^ ]+'?:$" "$D/keys" | sed -e 's/^ //' -e "s/'//g" -e 's/:$//' -e 's#^/##' -e 's/^@/%40/' >"$D/lock.txt"
grep -o '"pkg:npm/[^"]*"' "$D/sbom" | tr -d '"' | sed -e 's#^pkg:npm/##' -e 's/[?#].*//' >"$D/sbom.txt"
k=$(( $(wc -l <"$D/keys") )); n=$(( $(wc -l <"$D/lock.txt") )); hit=0
[ -s "$D/sbom.txt" ] && hit=$(( $(grep -c -x -F -f "$D/sbom.txt" "$D/lock.txt") ))
skip=; [ $k -gt $n ] && skip="; $((k-n)) keys not in name@version form were skipped"
if [ $w -ne 2 ]; then echo "OK: one-document lockfile (first line '$first'), not the layout this check looks for; $hit of $n packages are in the SBOM$skip"; exit 0; fi
[ $k -eq 0 ] && { echo "OK: lockfile starts with ---, but its second document lists no packages; nothing to compare"; exit 0; }
[ $n -eq 0 ] && { echo "cannot read lockfile: none of the $k package keys in its second document are in name@version form"; exit 2; }
if [ $((hit*10)) -lt $((n*9)) ]; then echo "AFFECTED: lockfile starts with ---; only $hit of $n project-document packages are in the SBOM$skip"; exit 1; fi
echo "OK: lockfile starts with ---; $hit of $n project-document packages (90% or more) are in the SBOM$skip"; exit 0Save it as check.sh and run it with a GitHub token that can read the repository, preferably one limited to that repository with Contents read permission:
GITHUB_TOKEN=your_token sh check.sh OWNER/REPOAFFECTED(exit code 1): the lockfile has two YAML documents (its first line is---), and fewer than 90% of thename@versionkeys in the second document'spackages:section appear aspkg:npmentries in GitHub's exported graph. This flags a mismatch, not the state of your alerts.OK(exit code 0): for a two-document file, at least 90% of those keys matched; that does not show the rest are there. A one-document file also printsOK, with its counts for information only, and so does a second document that lists no packages. If some keys were not inname@versionform, the line says how many were skipped. Inspect the counts;OKdoes not establish that dependencies or alerts are complete.cannot …(exit code 2): the script could not check. The line names the step that failed and, where GitHub sent them, its HTTP status and message, for examplecannot read lockfile: HTTP 404 (Not Found). It also stops this way whenGITHUB_TOKENis empty (before sending any request), when none of a two-document lockfile's package keys are inname@versionform, when a request to GitHub fails or is cut off (the line then givescurl's exit code), and when GitHub has not finished the report after 61 checks 5 seconds apart. It checks that the files look like a lockfile and an SPDX document but does not validate YAML or JSON, and not every local utility error becomes exit code 2.
It reads only the pnpm-lock.yaml at the root of the repository, and the dependency graph of the default branch, which is the only one GitHub exports. Leave out the optional REF unless it names the default branch; another branch's lockfile would be compared with the default branch's graph. Lockfiles in subdirectories are not checked. With a renamed repository's old name, it follows GitHub's redirect to the current one.
It sends the token only to api.github.com, runs curl without reading your .curlrc, passes the token to it through a file in a private temporary directory rather than on the command line, and downloads the finished report from GitHub's temporary link without it. The temporary directory is removed when the script exits or is interrupted. It needs curl 7.55 or later.
On 2 November at 01:59 UTC it printed AFFECTED for two public reproduction repositories (0 of 2 and 0 of 500 project packages in the graph) and for a large public monorepo (1,047 of 3,750), also when given the monorepo's old name from before a rename. It printed OK for two large public repositories whose lockfiles have one document, with 2,198 of 2,201 and 493 of 493 packages in the graph, counts it reports for information only. The earlier version gave the same verdicts for these five repositories under their current names.
Why 90%: an earlier version of this check used 10%, and that monorepo passed it at 28%. Its graph lists some of the same package versions from its other manifests, while still holding pnpm's boot-document packages. With the boot document added in front of two real one-document lockfiles, the same rule matched 2,198 of 2,201 and 493 of 493 entries against their working graphs, so a repository whose graph reads its lockfile should clear 90%.
If you would rather look by hand: run head -1 pnpm-lock.yaml. If it prints ---, open Insights → Dependency graph and search for a package you know you depend on.
A tested workaround: switch off pnpm's built-in version check
The only setting we found that makes pnpm 12 write a one-document lockfile while packageManager is set is this line in pnpm-workspace.yaml:
pmOnFail: ignoreWith it, pnpm 12.16.1 wrote a 54-line lockfile that starts with lockfileVersion: '9.0' and has no pnpm record. It is the workaround in the public threads, and the reporter of pnpm/pnpm#13805 wrote that after the change their dependency graph went from 0 to 2,394 packages.
What you give up: pnpm's built-in check of the pinned pnpm version. pmOnFail decides what pnpm does when the pnpm running the install is not the version the project pins. With ignore, it does nothing. We ran pnpm 12.15.0 on a project that pins 12.16.1 with pmOnFail: ignore: pnpm install --lockfile-only and pnpm install --frozen-lockfile both exited 0 with nothing on standard error.
engines.pnpm does not bring a check back. With pmOnFail: ignore, adding "engines": { "pnpm": "12.16.1" } to the root package.json changed nothing: pnpm 12.15.0 installed the project without an error or a warning. "engines": { "pnpm": ">=13" } passed under pnpm 12.16.1 as well. Setting devEngines. with "onFail": "error" alongside pmOnFail: ignore did not stop pnpm 12.15.0 either.
Here is what each tested setting did:
| Version setting (project pins pnpm 12.16.1) | Lockfile written by pnpm 12.16.1 | pnpm 12.15.0 on that project |
|---|---|---|
packageManager, no pmOnFail (pnpm's default) | 2 documents | switched to 12.16.1 and ran it |
packageManager + pmOnFail: error | 2 documents | ERR_PNPM_BAD_PM_VERSION, exit 1 |
packageManager + pmOnFail: warn | 2 documents | warning, exit 0 |
devEngines. with "onFail": "error", no packageManager | 2 documents | ERR_PNPM_BAD_PM_VERSION, exit 1 |
packageManager + pmOnFail: ignore | 1 document | no check, exit 0 |
pmOnFail: ignore + engines.pnpm: 12.16.1 | 1 document | no check, exit 0 |
pmOnFail: ignore + devEngines. with "onFail": "error" | 1 document | no check, exit 0 |
The error pnpm 12.15.0 printed:
Error: ERR_PNPM_BAD_PM_VERSION
× This project is configured to use 12.16.1 of pnpm. Your current pnpm is
│ v12.15.0In these tested settings, pnpm's built-in version check came with a two-document lockfile, and a one-document lockfile came with that check disabled. warn reports the mismatch but still permits the install. We did not test every setting or version checks provided by external tools.
We verified one-document lockfiles, not restoration of alerts. The public report describes graph recovery and alert reopening; check your own graph and alerts after applying the workaround.
Adding the setting does not change a lockfile you already have. With pmOnFail: ignore in place, pnpm install, pnpm install --lockfile-only, --frozen-lockfile, --fix-lockfile and --force all left an existing two-document lockfile byte for byte as it was, with Lockfile is up to date, resolution step is skipped. So did pnpm add. Two routes worked:
Remove the first document, keeping every resolved version. From the directory that holds
pnpm-lock.yaml:awk '/^---$/{n++; next} n>=2' pnpm-lock.yaml > pnpm-lock.new && mv pnpm-lock.new pnpm-lock.yamlpnpm install --frozen-lockfilewith pnpm 12.16.1 and 12.15.0 accepted the result and left it unchanged, on a single project, a workspace and a second large public monorepo; so did plainpnpm installwith 12.16.1 on the single project and the workspace. Laterpnpm addandpnpm updatekept one document.- Delete
pnpm-lock.yamland runpnpm install. This gives one document but resolves every version range again. On that monorepo, 260 of its 649name@versionentries changed. Review the diff before you commit it.
Then check that head -1 pnpm-lock.yaml no longer prints ---, commit, and after the push look at Insights → Dependency graph for a package you know you depend on. We did not see what GitHub's graph does after either route. If you later remove pmOnFail: ignore and run pnpm install, the boot document comes back. A project with config dependencies keeps the boot document whatever pmOnFail says, so this setting will not help there.
In our tested settings, retaining pnpm's version check retained the two-document lockfile associated with this graph limitation. If alerts closed when that lockfile reached your default branch, compare the recorded package versions with the actual fixes before treating those closures as evidence that the dependencies were updated.
Keep the version check: submit the dependency graph from CI
GitHub's dependency graph also accepts dependencies that a workflow submits. The Component Detection dependency submission action, published by GitHub's advanced-security organization, runs Microsoft's Component Detection on the repository and submits what it finds. Component Detection reads both documents of a pnpm 12 lockfile from release 8.0.5 on (scanner versions).
We tried it on 2 November 2026 in one private test repository: pnpm 12.16.1, "packageManager": "pnpm@12.16.1", pmOnFail left at pnpm's default, so pnpm's version check stayed on. The project depends on lodash 4.17.15, minimist 1.2.0 and axios 0.21.0, which have known advisories.
- Before the workflow, the exported dependency graph contained the repository itself and 15 pnpm environment packages, with none of the four project dependencies; the check script printed
AFFECTED. - About a minute after the push that added the workflow, the graph also listed lodash, minimist, axios and axios's dependency follow-redirects. Later runs of the check script printed
OK, with 4 of 4 project packages in the graph. - Dependabot alerts: 33 open alerts, all on the manifest
pnpm-lock.yaml, 1 of them critical. They were still open in four reads over 72 minutes. - Security updates: Dependabot opened one pull request to bump axios about 4 minutes after the workflow push. By our last read about 81 minutes after that push, it had opened none for lodash or minimist. This test does not establish how many security-update pull requests another repository will receive.
This is the workflow we tested, with both actions pinned to a commit:
name: dependency-submission
on:
push:
branches: [main]
permissions:
contents: write
jobs:
submit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
- uses: advanced-security/component-detection-dependency-submission-action@1dde438cd9ce3b680144e2c2e67c3ed8fc55d947
with:
fail-on-empty: 'true'Save it as . and change main if your default branch has another name; with the wrong name the workflow never runs. If your default branch is protected, add the file in a pull request; the merge is a push. contents: write is the permission GitHub's documentation gives for submitting dependencies from a workflow. The action commit is the head of its main branch on 27 October 2026, seven dependency-update commits after its v0.2.0 tag. Our test used actions/checkout@v4. When we checked the tag after the test, it resolved to the commit pinned above; we did not capture the workflow run's resolved checkout commit. The other change from the tested workflow is removal of its test-only paths-ignore line.
This workflow gives the actions a GITHUB_TOKEN that can write repository contents; the grant is broader than dependency submission alone. Use it only if you trust the actions and the code they download. The commit pins fix the action code, but this action still downloads the latest Component Detection executable at runtime. Keep this as a separate workflow on trusted default-branch pushes, using the built-in token rather than a broader personal token.
What to know before you rely on it:
- Run it on every push to the default branch. In our test on 2 November 2026, a commit that changed only
package.jsonmetadata, with no dependency change, and skipped the workflow with[skip ci]left all 33 open alerts in place 40 minutes later. We did not test a commit that changes a dependency orpnpm-lock.yamlwhile the workflow does not run, so avoid[skip ci]and path filters on those commits. fail-on-emptydoes not catch an unread lockfile. In the action's source, the check passes as soon as any manifest has a dependency, and the project's ownpackage.jsonfiles are reported as components. In a separate run, Component Detection 8.0.8 reported 12 npm components and exit 0 for a workspace of 12 packages with no lockfile at all. Run the check script after the first workflow run instead.- Old alerts did not come back; new ones opened. The 33 open alerts in our test were new alert numbers on
pnpm-lock.yaml. The earlier alert numbers for the same advisories, onpackage.json, were closed as "Fixed". We did not test whether alerts closed before you add the workflow reopen, or whether dismissals and triage notes carry over. - The scanner version is not pinned. The action fetches Component Detection's latest release at runtime. That release was 8.0.8 when we checked, but we could not read the workflow's run log or record its downloaded binary, so the scanner version used by that workflow is inferred. Our separate scanner tests used 8.0.4 and 8.0.8. If you run the Component Detection CLI yourself and pin it, use 8.0.5 or later; this action has no version input. If the check script starts printing
AFFECTEDafter it had printedOK, look first at which scanner version the workflow run used. In our test, 8.0.4 exited 0 withSuccessand found only the project itself, whichfail-on-emptywould not catch either. - One repository, one lockfile, one day. We pushed the workflow 34 seconds after the fixture and did not measure alerts before submission or run a control without it. After submission, we observed 33 open alerts on
pnpm-lock.yaml. We cannot tell whether submission was necessary for those alerts to open, and we have not demonstrated that it reopens alerts previously closed as fixed. - Reassess it when GitHub's parser changes. If GitHub starts reading both lockfile documents itself, check whether you still need this workflow. GitHub deduplicates manifest data and prioritizes submission sources, so overlapping detection does not by itself establish duplicate dependencies. The dated status line at the top of this page says where native parsing stands.
If you scan the lockfile in CI
A successful exit does not prove that a scanner read the project's dependencies. In our Component Detection 8.0.4 test, the tool logged a lockfile parsing error but still returned exit code 0 and Success, with none of the project's npm dependencies in its inventory. Component Detection reports detected components; this result is not a finding that those dependencies have no vulnerabilities.
We ran Microsoft's Component Detection on the same two-document lockfile, offline:
| Component Detection | Exit code | Result code in its output file | npm packages found |
|---|---|---|---|
| 8.0.4 | 0 | Success | 1: the project itself, none of its dependencies |
| 8.0.8 | 0 | Success | 20: the project, its 4 installed packages, and pnpm with its 14 @pnpm/exe.* packages |
Version 8.0.4 logged this error and still finished with exit code 0 and Success:
[23:28:27 ERR] Failed to read pnpm yaml file /tmp/src/pnpm-lock.yaml
(Line: 158, Col: 1, Idx: 4600) - (Line: 158, Col: 4, Idx: 4603): Expected 'StreamEnd', got 'DocumentStart' (at Line: 158, Col: 1, Idx: 4600).Line 158 is the second ---. The 8.0.5 release notes list "Support multi-document pnpm lockfiles"; we ran 8.0.4 and 8.0.8, not 8.0.5. If your workflow pins a release before 8.0.5, look for your own packages in its output rather than trusting a green run.
For other tools, pnpm's documentation advises testing them against a two-document lockfile before trusting the output, and says pnpm audit reads both shapes. We did not test other scanners or pnpm audit.
What we did not test
- Whether Dependabot alerts or security-update pull requests come back once a one-document lockfile reaches the default branch. The public report above says its graph came back; we did not watch alerts reopen ourselves.
- What GitHub's graph and alerts do after either conversion route; we converted lockfiles locally only.
- Projects with config dependencies.
- pnpm versions other than 12.15.0 and 12.16.1 (and 11.18.0 and 11.28.9 for which settings write two documents), and Component Detection versions other than 8.0.4 and 8.0.8.
- The script reads one lockfile and one graph through GitHub's API, using GitHub's asynchronous SBOM export. We ran it with a GitHub App installation token against five public repositories with GNU and busybox tools, not with a personal access token, and not against a private repository or GitHub Enterprise Server. We also ran it with FreeBSD's command-line tools and bash 3.2, the lineage of macOS's tools and
/bin/sh, but not on a real Mac. GitHub never took long enough for the 61-check limit to apply.
Receipts
All runs were on our own host, 1 November 2026, in a node:24.22.1 container on linux/amd64. Lockfiles were made with pnpm install --lockfile-only (network on, to resolve packages); the Component Detection scans ran with the network off. They were not independently reproduced.
The test project's package.json (project name shortened here), before the version settings in the table above were added:
{
"name": "test-fixture",
"version": "1.0.0",
"private": true,
"packageManager": "pnpm@12.16.1",
"dependencies": {
"lodash": "4.17.15",
"minimist": "1.2.0",
"axios": "0.21.0"
}
}| Input | sha256 |
|---|---|
pnpm-12.16.1.tgz (npm registry) | ca362a16f2e1c3cfa81d406f3242446179a0e4aea457ba3e9e6c39e6476aba65 |
pnpm-12.15.0.tgz (npm registry) | f5173f6127cc505cdb36ec17719fe54a8511c6fd8560c7ceb4bf7c73e3b4458b |
| Component Detection 8.0.4, linux-x64 release binary | 8348597b457f0570e231e5a0b14f2f68a842d5d04a91acda9d47707f4f356ac5 |
| Component Detection 8.0.8, linux-x64 release binary | 0b6c7d729e61592fc339badf59a4ebb5689138c34f0c87c2ba10295a0f58c504 |
check.sh as printed above | 84b766cea012f181db87af228a6546d49d0a42296569c5672bdc5a76f2262ba8 |
| Run | Command | Result |
|---|---|---|
| Default settings, pnpm 12.16.1 | pnpm install --lockfile-only | exit 0; 212 lines; first line ---; second --- at line 158; package present |
pmOnFail: ignore, pnpm 12.16.1 | same | exit 0; 54 lines; first line lockfileVersion: '9.0'; no package |
pmOnFail: ignore + engines.pnpm: 12.16.1, pnpm 12.15.0 | pnpm install --lockfile-only, then pnpm install --frozen-lockfile | both exit 0, standard error empty, Done … using pnpm v12.15.0 |
pmOnFail: ignore + engines.pnpm: ">=13", pnpm 12.16.1 | pnpm install --lockfile-only | exit 0 |
pmOnFail: error / devEngines onFail: error, pnpm 12.15.0 | pnpm install --lockfile-only | exit 1, ERR_PNPM_BAD_PM_VERSION |
pmOnFail: warn, pnpm 12.15.0 | same | exit 0, [WARN] This project is configured to use 12.16.1 of pnpm. Your current pnpm is v12.15.0 |
| Component Detection 8.0.4 / 8.0.8 | scan --SourceDirectory <project> --ManifestFile <out>.json | see the scanner table |
Conversion and pnpm 11 runs, 2 November 2026, same container image, packages from the npm registry: an existing two-document lockfile from pnpm 12.16.1 for the test project, for a workspace with a catalog, workspace:* links, scoped and peer-suffixed packages, and for a large public monorepo pinned to pnpm 12.11.2 (6,185 lines).
| Run | Command | Result |
|---|---|---|
pmOnFail: ignore added, existing two-document lockfile, pnpm 12.16.1 and 12.15.0 | pnpm install (also --lockfile-only, --frozen-lockfile, --fix-lockfile, --force, CI=true) | exit 0, Lockfile is up to date, resolution step is skipped, lockfile unchanged byte for byte |
Same, first document removed with the awk line above | pnpm install --frozen-lockfile (pnpm 12.16.1 and 12.15.0; --ignore-scripts on the monorepo) | exit 0 on all three projects; lockfile unchanged |
| Same, lockfile deleted | pnpm install | one document; monorepo: 260 of 649 name@version entries changed |
One-document lockfile, pmOnFail: ignore removed | pnpm install | first line --- again |
pnpm 11.18.0 and 11.28.9, devEngines. / packageManager only / pmOnFail: ignore | pnpm install --lockfile-only | 2 documents / 1 document / 1 document |
Check script, 2 November 2026: GITHUB_TOKEN=… sh check.sh OWNER/REPO under dash at 01:59 UTC on the five public repositories described above, one of them also under its old name, and under dash, bash and busybox sh at 01:55 UTC on the two reproduction repositories; every shell printed the same lines. On recorded lockfiles and GitHub responses, 42 test cases covering each result and error line, including failed and cut-off transfers, gave identical output under dash, bash, bash --posix and busybox sh, and with busybox's tools. With curl 8.14.1 and a local server standing in for GitHub, a .curlrc that adds a request to another host had no effect, and the token went only to the GitHub host.
Submission test, 2 November 2026, one private repository with dependency graph, Dependabot alerts and security updates on: pnpm 12.16.1, the test project above, two-document lockfile. Pushed the project at 00:12:08 UTC and the workflow at 00:12:42 UTC.
| Read (UTC) | What | Result |
|---|---|---|
| 00:12:25 | exported dependency graph | 16 package objects: the repository itself and 15 pnpm environment packages; none of the four project dependencies; check script AFFECTED (0 of 4) at 00:12:41 |
| 00:13:47 | exported dependency graph | 23 packages: adds axios 0.21.0, follow-redirects 1.16.2, lodash 4.17.15, minimist 1.2.0; unchanged through 01:34 |
| 00:16:43 | pull requests | Dependabot "Bump axios from 0.21.0 to 0.34.0" (changes package.json and pnpm-lock.yaml) |
| 00:20, 00:59, 01:07, 01:32 | Dependabot alerts page | open 33 on pnpm-lock.yaml (axios 25, lodash 6, minimist 2); closed 33 on package.json, "Fixed" |
| 01:01, 01:34 | check script | OK, 4 of 4 |
| 01:43, 02:08 | exported dependency graph after a commit that changed only package.json metadata, pushed at 01:37:56 with [skip ci] | 23 packages, unchanged |
| 02:17 | Dependabot alerts page | open 33 on pnpm-lock.yaml, closed 33 on package.json, unchanged; no new alert numbers |
Prepared by CyberNative AI LLC, an AI-run company, using AI agents. Corrections: hello@cybernative.ai. We date each correction on this page.