Skip to content

Fix pnpm installs of read-only package files - #347

Open
aghiles-dd wants to merge 1 commit into
yarnpkg:mainfrom
aghiles-dd:aghiles/fix-readonly-pnpm-cache
Open

aghiles-dd wants to merge 1 commit into
yarnpkg:mainfrom
aghiles-dd:aghiles/fix-readonly-pnpm-cache

Conversation

@aghiles-dd

@aghiles-dd aghiles-dd commented Sep 30, 2026 •

Copy link
Copy Markdown

Problem

With Yarn 6.0.0-rc.22 and nodeLinker: pnpm, installing a tarball containing a file with mode 0555 fails with Permission denied in fs_extract_archive_impl. link_into_cas applies the read-only mode before set_safe_mtime reopens the entry for writing. The failed install leaves a read-only cache entry that subsequent installs cannot rewrite.

Changes

Set the timestamp before restoring archive permissions. When repairing an existing cache entry, temporarily allow owner writes and repair it in place, preserving its inode and existing cross-project hardlinks.

Add one regression case to the existing content-addressed index suite covering installation and repair of a read-only file, including its final permissions.

Validation

  • The new regression fails on the released 6.0.0-rc.22 binary with the original permission error.
  • All six content-addressed index integration tests pass with the patched release build, including cross-project hardlink repair.
  • ESLint and git diff --check pass.
  • A full pnpm install and subsequent install --immutable pass in the affected monorepo with the patched binary.

A fresh install of the affected monorepo with released Yarn 6.0.0-rc.22 and nodeLinker: pnpm fails with Permission denied. Reproduced using a new YARN_GLOBAL_FOLDER with an empty cache and content-addressed index.

@netlify

netlify Bot commented Sep 30, 2026

Copy link
Copy Markdown

👷 Deploy request for yarn-v6 pending review.

Visit the deploys page to approve it

Name Link
🔨 Latest commit f08346a

@github-actions

Copy link
Copy Markdown

⏱️ Benchmark Results

gatsby install-full-cold

Metric Base Head Difference
Mean 4.384s 4.337s -1.06% ✅
Median 4.373s 4.337s -0.83% ✅
Min 4.279s 4.259s
Max 4.470s 4.440s
Std Dev 0.052s 0.044s
📊 Raw benchmark data (gatsby install-full-cold)

Base times: 4.279s, 4.304s, 4.399s, 4.352s, 4.341s, 4.441s, 4.447s, 4.368s, 4.413s, 4.346s, 4.385s, 4.423s, 4.440s, 4.436s, 4.341s, 4.350s, 4.350s, 4.460s, 4.357s, 4.422s, 4.333s, 4.342s, 4.369s, 4.439s, 4.378s, 4.329s, 4.456s, 4.330s, 4.470s, 4.424s

Head times: 4.367s, 4.298s, 4.319s, 4.375s, 4.291s, 4.330s, 4.397s, 4.281s, 4.266s, 4.348s, 4.375s, 4.440s, 4.351s, 4.343s, 4.348s, 4.331s, 4.316s, 4.314s, 4.368s, 4.308s, 4.279s, 4.311s, 4.259s, 4.305s, 4.374s, 4.301s, 4.408s, 4.349s, 4.389s, 4.382s


gatsby install-cache-only

Metric Base Head Difference
Mean 1.306s 1.343s +2.82% ⚠️
Median 1.303s 1.317s +1.03% ⚠️
Min 1.289s 1.289s
Max 1.326s 2.146s
Std Dev 0.009s 0.152s
📊 Raw benchmark data (gatsby install-cache-only)

Base times: 1.321s, 1.319s, 1.311s, 1.291s, 1.294s, 1.314s, 1.311s, 1.314s, 1.303s, 1.311s, 1.300s, 1.301s, 1.323s, 1.326s, 1.301s, 1.313s, 1.304s, 1.301s, 1.298s, 1.289s, 1.301s, 1.302s, 1.305s, 1.306s, 1.302s, 1.295s, 1.304s, 1.302s, 1.299s, 1.311s

Head times: 1.296s, 1.305s, 1.289s, 1.296s, 1.300s, 1.323s, 1.315s, 1.308s, 1.324s, 1.319s, 1.316s, 1.322s, 1.317s, 1.316s, 1.314s, 2.146s, 1.329s, 1.330s, 1.317s, 1.340s, 1.317s, 1.309s, 1.320s, 1.320s, 1.298s, 1.308s, 1.316s, 1.310s, 1.332s, 1.323s


gatsby install-cache-and-lock (warm, with lockfile)

Metric Base Head Difference
Mean 0.374s 0.373s -0.18% ✅
Median 0.372s 0.371s -0.25% ✅
Min 0.363s 0.363s
Max 0.419s 0.383s
Std Dev 0.010s 0.005s
📊 Raw benchmark data (gatsby install-cache-and-lock (warm, with lockfile))

Base times: 0.366s, 0.378s, 0.367s, 0.371s, 0.376s, 0.372s, 0.370s, 0.371s, 0.374s, 0.384s, 0.373s, 0.371s, 0.378s, 0.380s, 0.381s, 0.369s, 0.368s, 0.374s, 0.382s, 0.378s, 0.373s, 0.373s, 0.419s, 0.367s, 0.366s, 0.366s, 0.363s, 0.367s, 0.372s, 0.374s

Head times: 0.365s, 0.367s, 0.373s, 0.370s, 0.371s, 0.370s, 0.380s, 0.370s, 0.370s, 0.363s, 0.371s, 0.366s, 0.374s, 0.382s, 0.370s, 0.371s, 0.373s, 0.369s, 0.381s, 0.381s, 0.380s, 0.376s, 0.378s, 0.379s, 0.379s, 0.369s, 0.372s, 0.378s, 0.371s, 0.383s

@aghiles-dd
aghiles-dd marked this pull request as ready for review September 30, 2026 14:10
@aghiles-dd
aghiles-dd requested a review from arcanis September 30, 2026 14:10
// Write through the existing path: cross-project hardlinks
// inherit the repair without losing inode identity.
if index_path.fs_exists() {
index_path.fs_set_permissions(Permissions::from_mode(mode_bits | 0o200))?;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rather than checking for existence we should rather tolerate enoent errors (see ok_missing)

This branch was successfully deployed

1 active deployment
test-reports — f08346af Deployed Sep 30, 2026 by aghiles-dd via Reporting test results #1359
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.

2 participants