perf: cache pnpm's lockfile verification results - #30
Conversation
pnpm v11 and newer verify every lockfile entry against the configured supply-chain policies (`minimumReleaseAge`, `trustPolicy`, ...) and memoize the verdict in `<cacheDir>/lockfile-verified.jsonl`. The action cached only the store, so every job started with that verdict missing and re-checked the whole lockfile against the registry — on typescript-eslint's repository, 16.6s of a 17.6s install on Linux and 40.1s of 42.4s on Windows. The verdict depends on the lockfile content and the policies, never on the runner, so it is cached under its own key alongside the store cache and restored without prefix fallback: an entry recorded for a different lockfile could never be reused. Saving happens before `pnpm store prune`, which drops the log along with the store's other derived state. Anything that goes wrong here only costs the next job the re-verification, so failures are reported as warnings instead of failing the build.
|
Warning Review limit reached
Next review available in: 33 minutes You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (7)
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (1)
📜 Recent review details⏰ Context from checks skipped due to timeout. (2)
🧰 Additional context used🧠 Learnings (4)📓 Common learnings📚 Learning: 2026-05-11T16:24:38.150ZApplied to files:
📚 Learning: 2026-08-09T14:55:39.968ZApplied to files:
📚 Learning: 2026-05-11T16:19:49.450ZApplied to files:
🔇 Additional comments (1)
📝 WalkthroughWalkthroughThe action now caches pnpm lockfile verification results with the pnpm store. It restores and saves verification data by lockfile hash, resolves platform-specific cache paths, normalizes Windows paths, and validates the workflow on Linux, macOS, and Windows. ChangesLockfile verification cache
Estimated code review effort: 3 (Moderate) | ~25 minutes Mergeability Score: ⚪ Minimal · up to The change adds best-effort caching for pnpm lockfile verification results without introducing a supplied merge-blocking correctness or production risk; no actionable merge-blocking risk remains after normal checks and review. Sequence Diagram(s)sequenceDiagram
participant Workflow
participant SetupAction
participant PnpmCache
Workflow->>SetupAction: Run with caching enabled
SetupAction->>PnpmCache: Restore store and verification cache
SetupAction->>PnpmCache: Save verification data during post-processing
Workflow->>PnpmCache: Verify lockfile-verified.jsonl
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
PR Summary by Qodoperf: cache pnpm's lockfile verification results across CI runs
AI Description
Diagram
High-Level Assessment
Files changed (7)
|
Confidence Score: 5/5The PR appears safe to merge because no blocking failure remains. No blocking failure remains. Reviews (6): Last reviewed commit: "feat: check the verification log before ..." | Re-trigger Greptile |
The module header explained the whole feature where naming the file's purpose is enough, and the ordering comment described `pnpm store prune` deleting the log without saying which versions do — pnpm/pnpm#13893 stops deleting it.
The log is under a kilobyte and pnpm writes it on every install, not only where supply-chain policies are configured: the integrity and tarball-URL checks are unconditional. A job that starts without it re-checks every lockfile entry against the registry — on a ~2000-entry lockfile with a warm store, 13.5s vs 1.5s with `minimumReleaseAge` and `trustPolicy` configured, and still 6.7s vs 1.6s with no policies at all. Tying that to the `cache` input made the common case slow for no saving worth counting, so the log is now restored and saved on its own key whether or not the store is cached. `cache` goes back to meaning what its name says.
Dismissed because a newer commit was pushed; Greptile will re-review the current head.
Saving in the post step left the whole job between the install and the upload. Anything running in that window — the job's tests, its build, a dependency's own install scripts — can rewrite the log on disk, and the job's own cache write would then publish a record claiming some other lockfile passed verification, for every later job to restore and trust. No cache credentials needed: the attacker rides the write the job performs anyway. The log is complete the moment the install finishes, so it is uploaded there. The post step still covers a job that installs in a step of its own, where that is the first point the log is known to be final; the save is idempotent across the two, and the process-local flags exist because main and post do not share state within a run.
Dismissed because a newer commit was pushed; Greptile will re-review the current head.
The previous commit listed a dependency's own scripts among the things that run after the install, which is where they do not run: pnpm executes them during the install, ahead of the upload, so they stay inside the window rather than being closed out of it. What keeps that narrow is that pnpm refuses to run them at all — `ERR_PNPM_IGNORED_BUILDS` — unless the repository allow-lists the package, and such a package can already run code in the job.
Dismissed because a newer commit was pushed; Greptile will re-review the current head.
Moving the upload to just after the install left one window open: pnpm runs a package's lifecycle scripts during the install, so an allow-listed dependency can still append a record claiming some other lockfile passed verification, and the upload would publish it. Writing pnpm's own record after those scripts would not help — the log is appended to, so the forged record survives whatever pnpm writes next to it. What does distinguish the two is shape: an install appends its own verdict and leaves earlier records untouched. So the log is uploaded only when every record that predated the install is still there, and no more records were added than there were installs. Both failure modes cost a re-verification in the next job and nothing else, which is also the price of pnpm compacting the log past a thousand records — rare enough in CI, where a job restores at most one record.
Dismissed because a newer commit was pushed; Greptile will re-review the current head.
Why
pnpm v11 and newer verify every lockfile entry against the configured supply-chain policies (
minimumReleaseAge,trustPolicy, …) and memoize the verdict in<cacheDir>/lockfile-verified.jsonl.cache: truecaches onlypnpm store path, so every job starts with that verdict missing and re-checks the whole lockfile against the registry.Measured on typescript-eslint's repository (2058 lockfile entries), where the store cache was warm:
On Windows it was
40.1sof a42.4sinstall. Locally, the same install with the verdict already recorded takes 1.5s instead of 13.5s — the log itself is under a kilobyte.What
pnpm installand saved in the post step, under its own key,pnpm-lockfile-verified-<OS>-<arch>-<lockfile hash>.pnpm store prune, which deletes the log along with the store's other derived state.pnpm config get cacheDir, falling back to pnpm's per-platform default —pnpm config getreports settings, not defaults, and printsundefinedwhen the setting is unset.warning, never a failed build: the worst case is that the next job re-verifies.Tests
A new job installs with a supply-chain policy configured on ubuntu, macOS and Windows, then asserts that pnpm wrote
lockfile-verified.jsonlexactly where the action looks for it — that is the part of this change most likely to drift, since pnpm resolvescacheDirper platform and does not print it.Follow-ups (not in this PR)
pnpm config get cacheDircannot report the effective default, so the action mirrors pnpm's platform logic. Apnpm cache pathcommand would remove the duplication.pnpm store prunedeleteslockfile-verified.jsonl; the Rust CLI's does not. Worth reconciling — the log is derived from the lockfile and the policies, not from the store.Written by an agent (Claude Code, claude-opus-5).
Summary by CodeRabbit
New Features
Documentation