Skip to content

perf: cache pnpm's lockfile verification results - #30

Merged
zkochan merged 4 commits into
mainfrom
cache-lockfile-verification
Aug 28, 2026
Merged

perf: cache pnpm's lockfile verification results#30
zkochan merged 4 commits into
mainfrom
cache-lockfile-verification

Conversation

@zkochan

@zkochan zkochan commented Aug 13, 2026

Copy link
Copy Markdown
Member

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: true caches only pnpm 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:

? Verifying lockfile against supply-chain policies (2058 entries)...
✓ Lockfile passes supply-chain policies (2058 entries in 16.6s)
Done in 17.6s using pnpm v12.0.0-rc.4

On Windows it was 40.1s of a 42.4s install. Locally, the same install with the verdict already recorded takes 1.5s instead of 13.5s — the log itself is under a kilobyte.

What

  • The verdict is restored before pnpm install and saved in the post step, under its own key, pnpm-lockfile-verified-<OS>-<arch>-<lockfile hash>.
  • No prefix fallback on restore: the verdict is only valid for the exact lockfile it was recorded for, so an older entry could never be reused. (pnpm re-verifies anyway if it does not trust a record, so a stale one is safe, just useless.)
  • Saving runs before pnpm store prune, which deletes the log along with the store's other derived state.
  • The cache directory comes from pnpm cache path, which pnpm reports in v11 as well as v12.
  • Every failure in this path is a 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.jsonl where the action looks for it — that the log is named and placed as expected on every platform.

Follow-ups (not in this PR)

  • The TypeScript CLI's pnpm store prune deletes lockfile-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

    • Added automatic caching for pnpm lockfile verification results, independently of pnpm store caching.
    • Cache entries are keyed by lockfile, operating system, and architecture, with safeguards for cache integrity and growth.
    • Added cross-platform support and verification for Linux, macOS, and Windows.
    • Added outputs for installed runtimes and whether the pnpm store cache matched.
    • Updated pnpm version references to stable 12.0.0.
  • Documentation

    • Clarified runtime installation, caching, installation, and output behavior.
    • Documented lockfile verification caching and its performance characteristics.

@coderabbitai

coderabbitai Bot commented Aug 13, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 1625e1bb-8462-4887-9a3c-b8818ae1cd1b

📥 Commits

Reviewing files that changed from the base of the PR and between ec0bd77 and 528c969.

⛔ Files ignored due to path filters (1)
  • dist/index.js is excluded by !**/dist/**
📒 Files selected for processing (7)
  • .github/workflows/test.yaml
  • README.md
  • action.yml
  • src/cache-restore/index.ts
  • src/cache-restore/run.ts
  • src/index.ts
  • src/lockfile-verification-cache/index.ts

📝 Walkthrough

Walkthrough

The 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.

Changes

Lockfile verification cache

Layer / File(s) Summary
Verification cache implementation
src/lockfile-verification-cache/index.ts
Adds lockfile-specific restore and save operations. Resolves configured or platform-specific pnpm cache directories. Validates verification-log records before saving.
Cache restore and lifecycle integration
src/cache-restore/..., src/index.ts
Restores verification data independently of store caching. Snapshots verification state after runtime installation and saves it before store processing.
Windows path normalization
src/windows-path/index.ts
Adds normalization for Windows extended-length drive and UNC paths.
Stable pnpm coverage and cache documentation
.github/workflows/test.yaml, action.yml, README.md
Updates pnpm references to 12.0.0. Adds cross-platform lockfile verification checks and documents verification-cache behavior.

Estimated code review effort: 4 (Complex) | ~45 minutes

Mergeability Score: ⚪ Minimal · up to ec0bd

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 VerificationCache
  participant PnpmStore
  Workflow->>SetupAction: Run with pnpm 12.0.0
  SetupAction->>VerificationCache: Restore by lockfile hash
  SetupAction->>PnpmStore: Restore store cache when requested
  SetupAction->>VerificationCache: Snapshot and save verification log
  SetupAction->>PnpmStore: Prune and save store cache
  Workflow->>VerificationCache: Check lockfile-verified.jsonl
Loading

Suggested reviewers: blankparticle, stanzilla

Poem

A rabbit checks each lockfile line,
Then stores the proof in cache so fine.
Windows paths shed their extended shell,
Across three systems, tests run well.
“Stable pnpm!” the bunny sings.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 60.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: caching pnpm lockfile verification results.
  • Fix all pre-merge checks with AI
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cache-lockfile-verification

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

perf: cache pnpm's lockfile verification results across CI runs

✨ Enhancement 🧪 Tests 📝 Documentation 🕐 20-40 Minutes

Grey Divider

AI Description

• Adds a second GitHub Actions cache for pnpm's lockfile supply-chain verification log
 (lockfile-verified.jsonl), keyed on OS, arch and lockfile hash.
• Restores the verdict before pnpm install and saves it before pnpm store prune, which would
 otherwise delete it.
• Resolves pnpm's cacheDir via pnpm config get cacheDir, falling back to pnpm's per-platform
 defaults when unset.
• Extracts the Windows extended-length path fix into a shared windows-path module reused by both
 caches.
• Treats every failure in the new caching path as a non-fatal warning.
• Adds a new CI job across ubuntu/macOS/Windows that configures a supply-chain policy and asserts
 the verification log lands where the action expects it.
• Updates README and action.yml docs to describe the new caching behavior.
Diagram

graph TD
  A["cache-restore/run.ts"] --> B["lockfile-verification-cache"]
  B --> C["pnpm config get cacheDir"] --> D[(lockfile-verified.jsonl)]
  B --> E[[GitHub Actions Cache]]
  F["index.ts runPost"] --> G["saveVerificationCache"] --> E
  F --> H["pnpm-store-prune"] --> D
  B --> I["windows-path"]
  subgraph Legend
    direction LR
    _mod([Module]) ~~~ _db[(Cache file)] ~~~ _ext{{External service}}
  end
Loading
High-Level Assessment

Caching the verification log as a separate, precisely-scoped cache entry (rather than folding it into the store cache or widening the store cache's restore-key fallback) is the correct approach: the verdict is only valid for an exact lockfile match, so allowing prefix-fallback reuse (as the store cache does) would be unsafe, and combining it with the store cache would force unnecessary invalidation of the much larger store whenever only the policy config changes. Deriving cacheDir via pnpm config get with a hardcoded per-platform fallback is a reasonable stopgap given pnpm currently offers no command that reports the effective default; the PR explicitly flags this duplication as a known follow-up pending a pnpm cache path command upstream.

Files changed (7) +185 / -23

Enhancement (3) +109 / -21
index.tsNew module caching pnpm's lockfile verification log +95/-0

New module caching pnpm's lockfile verification log

• Introduces restoreVerificationCache and saveVerificationCache, which read/write GitHub Actions Cache entries for pnpm's lockfile-verified.jsonl, keyed by OS/arch/lockfile hash with no restore-key fallback. Resolves pnpm's cacheDir via 'pnpm config get cacheDir', falling back to a hardcoded per-platform default when unset, and treats all failures as warnings.

src/lockfile-verification-cache/index.ts

run.tsWire lockfile verification cache restore into the store cache flow +10/-21

Wire lockfile verification cache restore into the store cache flow

• Splits runRestoreCache into runRestoreStoreCache plus a call to restoreVerificationCache, both keyed on the same lockfile hash, and imports removeWindowsExtendedPathPrefix from the new windows-path module instead of defining it locally.

src/cache-restore/run.ts

index.tsSave verification cache before pnpm store prune in post step +4/-0

Save verification cache before pnpm store prune in post step

• Calls saveVerificationCache() at the start of runPost, ahead of pruneStore and saveCache, since pnpm store prune deletes the verification log along with other derived store state.

src/index.ts

Refactor (1) +19 / -0
index.tsExtract Windows extended-path stripping into shared module +19/-0

Extract Windows extended-path stripping into shared module

• Moves removeWindowsExtendedPathPrefix out of cache-restore/run.ts into its own module so it can be reused by the new lockfile-verification-cache code.

src/windows-path/index.ts

Tests (1) +43 / -0
test.yamlAdd cross-platform CI job asserting the verification log location +43/-0

Add cross-platform CI job asserting the verification log location

• Adds a matrix job (ubuntu/macOS/Windows) that appends a minimumReleaseAge policy to pnpm-workspace.yaml, runs the action with cache: true, and asserts pnpm wrote lockfile-verified.jsonl at the path the action expects on each OS.

.github/workflows/test.yaml

Documentation (2) +14 / -2
README.mdDocument lockfile verification caching +10/-1

Document lockfile verification caching

• Updates the cache input description and adds a section explaining that caching now covers both the pnpm store and the lockfile verification results, and why the latter matters on large repositories.

README.md

action.ymlUpdate cache input description to mention verification results +4/-1

Update cache input description to mention verification results

• Expands the 'cache' input's description to state that it also caches pnpm's lockfile verification results against supply-chain policies, keyed on the lockfile hash.

action.yml

@greptile-apps

greptile-apps Bot commented Aug 13, 2026

Copy link
Copy Markdown

Confidence Score: 5/5

The PR appears safe to merge because no blocking failure remains.

No blocking failure remains.

Reviews (9): Last reviewed commit: "fix: keep the pnpm pin the Windows store..." | Re-trigger Greptile

Comment thread src/index.ts Outdated
greptile-apps[bot]
greptile-apps Bot previously approved these changes Aug 13, 2026
@greptile-apps
greptile-apps Bot dismissed their stale review August 13, 2026 14:57

Dismissed because a newer commit was pushed; Greptile will re-review the current head.

greptile-apps[bot]
greptile-apps Bot previously approved these changes Aug 13, 2026
@greptile-apps
greptile-apps Bot dismissed their stale review August 13, 2026 15:03

Dismissed because a newer commit was pushed; Greptile will re-review the current head.

greptile-apps[bot]
greptile-apps Bot previously approved these changes Aug 13, 2026
@greptile-apps
greptile-apps Bot dismissed their stale review August 13, 2026 15:09

Dismissed because a newer commit was pushed; Greptile will re-review the current head.

greptile-apps[bot]
greptile-apps Bot previously approved these changes Aug 13, 2026
@greptile-apps
greptile-apps Bot dismissed their stale review August 13, 2026 15:14

Dismissed because a newer commit was pushed; Greptile will re-review the current head.

greptile-apps[bot]
greptile-apps Bot previously approved these changes Aug 13, 2026
pnpm v11+ verifies every lockfile entry against the configured
supply-chain policies and memoizes the verdict in
`<cacheDir>/lockfile-verified.jsonl`. `cache: true` caches only the store,
so every job re-checks the whole lockfile against the registry — 16.6s on
a 2058-entry lockfile with a warm store, 40.1s of a 42.4s install on
Windows.

Restore the log before the install and save it under its own key, keyed
on the exact lockfile hash with no prefix fallback: a verdict is only
valid for the lockfile it was recorded for. It is cached regardless of
`cache`, being a fraction of a kilobyte. Every failure in this path is a
warning — the worst case is that the next job re-verifies.

Saving runs before `pnpm store prune`, which deletes the log along with
the store's other derived state, and immediately after the install that
wrote it, so nothing the job runs afterwards ends up in what other jobs
restore.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01R7B41egL5GwZk1gw2DU7sY
@zkochan
zkochan force-pushed the cache-lockfile-verification branch from 7f46262 to 9dce9c1 Compare August 28, 2026 21:47
@greptile-apps
greptile-apps Bot dismissed their stale review August 28, 2026 21:47

Dismissed because a newer commit was pushed; Greptile will re-review the current head.

greptile-apps[bot]
greptile-apps Bot previously approved these changes Aug 28, 2026
`pnpm cache path` reports it directly, in v11 as well as v12 — v11 being
the oldest release this action installs — so the per-platform default no
longer has to be mirrored here. It also removes the `pnpm config get`
detour, which reports settings rather than defaults and prints
`undefined` for an unset `cacheDir`. The warning v11 emits about global
config goes to stderr, so stdout is just the path.

The regression job now compares against `pnpm cache path` too, rather
than deriving the location a second way in shell.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01R7B41egL5GwZk1gw2DU7sY
@greptile-apps
greptile-apps Bot dismissed their stale review August 28, 2026 21:51

Dismissed because a newer commit was pushed; Greptile will re-review the current head.

greptile-apps[bot]
greptile-apps Bot previously approved these changes Aug 28, 2026
`pnpm cache path` is not in every release the action installs: 11.22.0
has it, 12.0.0-rc.4 does not, and the regression job pinned rc.4 — which
is how CI caught this. Ask pnpm first and fall back to `pnpm config get
cacheDir`, then to pnpm's per-platform default, for releases that cannot
answer.

The job derives the location in shell again rather than reading it back
from `pnpm cache path`, so it still guards that fallback against pnpm's
own behaviour on all three platforms.

Bump every pinned 12.x prerelease across the workflow, the README and
action.yml to the released 12.0.0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01R7B41egL5GwZk1gw2DU7sY
@greptile-apps
greptile-apps Bot dismissed their stale review August 28, 2026 21:55

Dismissed because a newer commit was pushed; Greptile will re-review the current head.

The blanket bump to 12.0.0 flattened this one too, but pnpm 12.0.0
reports a plain `D:\.pnpm-store\v11` for that store-dir — only an older
release still emits the `\\?\` prefix the job exists to cover, so the
assertion failed. Restore 12.0.0-rc.0 and say in the comment that the pin
is load-bearing.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01R7B41egL5GwZk1gw2DU7sY
@zkochan
zkochan merged commit 0e9f373 into main Aug 28, 2026
36 of 37 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant