Skip to content

install: ignore patchedDependencies from folder dependency's package.json#29594

Open
robobun wants to merge 4 commits into
mainfrom
farm/0ab403ae/ignore-patched-deps-in-folder-deps
Open

install: ignore patchedDependencies from folder dependency's package.json#29594
robobun wants to merge 4 commits into
mainfrom
farm/0ab403ae/ignore-patched-deps-in-folder-deps

Conversation

@robobun

@robobun robobun commented Apr 22, 2026

Copy link
Copy Markdown
Collaborator

What does this PR do?

Fixes #13531

When a package depends on another package via a local path (folder dependency, e.g. "pkg-a": "../pkgA") or as a workspace member, and that package's package.json contains patchedDependencies, bun install would fail with:

error: Couldn't find patch file: 'patches/foo@1.0.0.patch'

because the patch entries from the dependency were merged into the root lockfile's patched_dependencies map, and patch file paths are resolved relative to the installing project's root (not the dependency's directory).

Root cause

Features.patched_dependencies was defined in src/install/install.zig (only true for Features.main) but was never checked in Package.parseWithJSON. Both patchedDependencies parse blocks ran unconditionally for every package.json, including folder/link/workspace dependencies.

Fix

Gate both patchedDependencies parse blocks on comptime features.patched_dependencies, matching how trustedDependencies is already gated on features.trusted_dependencies.

This means patchedDependencies is only read from the root package.json, consistent with:

  • bun patch --commit writing to the root package.json
  • the text lockfile serializing patchedDependencies as a single top-level key
  • pnpm migration moving pnpm.patchedDependencies to the root

How did you verify your code works?

Added two regression tests in test/cli/install/bun-install-patch.test.ts:

  1. Folder dependency: pkgB depends on "../pkgA" where pkgA has patchedDependencies
  2. Workspace member: a workspace member declares patchedDependencies

Both fail on main with Couldn't find patch file and pass with this fix. Also verified that installing in pkgA directly still applies its patch correctly.

Supersedes #27895 (same fix, originally targeting #27894 which was closed as a duplicate of #13531).

@robobun

robobun commented Apr 22, 2026

Copy link
Copy Markdown
Collaborator Author
Updated 11:38 AM PT - May 4th, 2026

@robobun, your commit f5dc6ea has 2 failures in Build #51258 (All Failures):


🧪   To try this PR locally:

bunx bun-pr 29594

That installs a local version of the PR into your bun-29594 executable, so you can run:

bun-29594 --bun

@coderabbitai

coderabbitai Bot commented Apr 22, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

Guarded processing of the JSON patchedDependencies property in the lockfile parser with comptime features.patched_dependencies, and added CLI integration tests ensuring patchedDependencies declared in non-root (local/workspace member) manifests are ignored during parent installs.

Changes

Cohort / File(s) Summary
Lockfile Parser
src/install/lockfile/Package.zig
Both passes that handled the "patchedDependencies" JSON property (the counting/string capacity pass and the building/insertion pass) are now conditionally compiled behind comptime features.patched_dependencies; internal logic inside those blocks is unchanged.
Integration Tests
test/cli/install/bun-install-patch.test.ts
Added two CLI tests: one for a folder-local dependency (pkgB -> ../pkgA) and one workspace scenario. Both assert root install ignores member/local patchedDependencies (no missing-patch stderr, no patches/ output, and no patchedDependencies recorded in the root bun.lock).
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: ignoring patchedDependencies from folder dependencies' package.json, which is the core fix in this PR.
Description check ✅ Passed The description includes both required sections with comprehensive detail: 'What does this PR do?' explains the problem, root cause, and fix with reference to issue #13531; 'How did you verify your code works?' describes two regression tests added.
Linked Issues check ✅ Passed The PR fully addresses issue #13531 by gating patchedDependencies parse blocks on comptime features.patched_dependencies, preventing folder/workspace dependencies from exporting patches to the parent project and causing incorrect patch path resolution.
Out of Scope Changes check ✅ Passed All changes are directly scoped to the fix: modifications to Package.parseWithJSON in Package.zig conditionally compile patchedDependencies blocks, and two regression tests in bun-install-patch.test.ts verify the fix covers both folder and workspace dependency scenarios.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM — minimal fix that gates patchedDependencies parsing on the existing features.patched_dependencies flag, matching the established trusted_dependencies pattern.

Extended reasoning...

Overview

This PR wraps two existing patchedDependencies parse blocks in src/install/lockfile/Package.zig with if (comptime features.patched_dependencies). The Features.patched_dependencies flag was already defined in src/install/install.zig (set to true only for Features.main) but was never actually checked, so folder/link/workspace dependencies' patchedDependencies were incorrectly merged into the root lockfile. A regression test is added to bun-install-patch.test.ts.

Security risks

None. This change narrows what is read from non-root package.json files — it stops processing patchedDependencies from folder dependencies rather than adding new parsing surface. No auth, crypto, network, or filesystem-write logic is touched.

Level of scrutiny

Low. The diff is purely additive guarding (indentation + a comptime conditional) with no logic changes inside the blocks. It exactly mirrors the existing if (comptime features.trusted_dependencies) gate at line 1558 of the same file, and I verified that Features.main is the only preset with patched_dependencies = true (install.zig:156-190), so root-package behavior is unchanged.

Other factors

The PR includes a focused regression test that reproduces issue #13531 and asserts both that install succeeds and that the lockfile doesn't leak the folder dependency's patchedDependencies. No CODEOWNERS apply to these paths, no outstanding reviewer comments, and the bug-hunting system found no issues.

@github-actions

Copy link
Copy Markdown
Contributor

This PR may be a duplicate of:

  1. fix(install): ignore patchedDependencies from workspace members #27895 - Both PRs apply the same fix: gating patchedDependencies parsing in Package.parseWithJSON behind features.patched_dependencies. fix(install): ignore patchedDependencies from workspace members #27895 targets workspace members while this PR targets folder dependencies, but the code change is functionally identical and merging either would fix both issues.

🤖 Generated with Claude Code

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM — straightforward fix gating patchedDependencies parsing on features.patched_dependencies, matching the existing trustedDependencies pattern.

Extended reasoning...

Overview

This PR wraps the two patchedDependencies parse blocks in Package.parseWithJSON (src/install/lockfile/Package.zig) with if (comptime features.patched_dependencies), so that only the root package.json contributes patch entries to the lockfile. Two regression tests are added to test/cli/install/bun-install-patch.test.ts covering both the folder-dependency case (#13531) and the workspace-member case (#27894).

Security risks

None. This is a comptime feature gate on package.json parsing; it strictly reduces the set of inputs that affect the lockfile (non-root patchedDependencies are now ignored). No auth, crypto, filesystem-write, or network changes.

Level of scrutiny

Low. The Features.patched_dependencies flag already existed in src/install/install.zig (default false, only true for Features.main) but was never checked — this PR simply wires it up. The change is mechanically identical to the adjacent features.trusted_dependencies gate at Package.zig:1558, so it follows an established pattern with no ambiguity.

Other factors

  • The two CI failures (require-cache.test.ts on Windows, load-file-loader-a-lot.test.ts on Linux ASAN) are in unrelated subsystems (cli/run and js/bun/resolve) and are not caused by this change.
  • The duplicate-PR bot flagged #27895 as the same fix; this PR's test coverage is a superset (covers both folder and workspace variants).
  • No CODEOWNERS entries match the modified paths.
  • Bug-hunting system found no issues.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@test/cli/install/bun-install-patch.test.ts`:
- Around line 613-623: Remove the flaky stdout assertion by deleting or
commenting out the line that checks stdout for "pkg-a@" (the
expect(stdout).toContain("pkg-a@") in the test where stdout, stderr, and
exitCode are collected from proc); keep the existing assertions on stderr,
exitCode, and the lockfile read via Bun.file(join(filedir, "pkgB",
"bun.lock")).text() (i.e., the expect(stderr).not.toContain(...),
expect(exitCode).toBe(0), and
expect(lockfile).not.toContain("patchedDependencies")) so the regression is
still validated without asserting variable bun install output.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: b28d06ce-2c18-4887-8275-b5288dfd3378

📥 Commits

Reviewing files that changed from the base of the PR and between c30c292 and 5ff90f2.

📒 Files selected for processing (1)
  • test/cli/install/bun-install-patch.test.ts

Comment thread test/cli/install/bun-install-patch.test.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@test/cli/install/bun-install-patch.test.ts`:
- Around line 618-623: The exitCode assertion is performed before
filesystem/behavioral checks; move the exit-code assertion to the end of the
test blocks so behavioral checks run first: keep the lockfile/read and
expect(lockfile).toContain/expect(lockfile).not.toContain and any stdout/stderr
expectations before asserting exitCode (the expect({ stdout, exitCode
}).toMatchObject or expect(exitCode).toBe(0)), and update both occurrences where
exitCode is asserted early (the block checking pkgB's bun.lock and the later
block around the other lockfile checks) so exitCode is asserted last.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: bad24571-5433-4a80-8263-3507cc177bbf

📥 Commits

Reviewing files that changed from the base of the PR and between 5ff90f2 and 4c9f2d6.

📒 Files selected for processing (1)
  • test/cli/install/bun-install-patch.test.ts

Comment thread test/cli/install/bun-install-patch.test.ts

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM — minimal comptime gate matching the existing trusted_dependencies pattern, with regression tests for both folder and workspace cases.

Extended reasoning...

Overview

This PR wraps the two patchedDependencies parse blocks in Package.parseWithJSON (src/install/lockfile/Package.zig:1321 and :1653) with if (comptime features.patched_dependencies). The inner logic is unchanged — only an outer comptime guard was added. Two regression tests were added to test/cli/install/bun-install-patch.test.ts covering the folder-dependency and workspace-member scenarios from #13531.

Security risks

None. This is a comptime feature gate that narrows when a JSON property is read; it does not introduce new parsing, file access, or external input handling.

Level of scrutiny

Low. The change is mechanical and follows the exact pattern already used one block away for trustedDependencies (if (comptime features.trusted_dependencies) at Package.zig:1558). I verified in src/install/install.zig that Features.patched_dependencies defaults to false and is set to true only in Features.mainfolder, workspace, link, npm, tarball, and npm_manifest all leave it false, which is the intended semantics (only the install root's patchedDependencies is honored, consistent with bun patch --commit and the lockfile's single top-level patchedDependencies key).

Other factors

  • No bugs found by the bug-hunting system.
  • CodeRabbit's minor flakiness note about asserting on bun install stdout was addressed in 4c9f2d6 (positive assertion moved to the lockfile), and the thread is resolved.
  • No CODEOWNERS cover src/install/ or this test file.
  • The PR supersedes #27895 with the same one-line conceptual fix plus broader test coverage.

robobun added 3 commits May 4, 2026 10:36
Features.patched_dependencies was defined but never checked in
parseWithJSON, so patchedDependencies entries from folder dependencies
(and any other non-root package.json) were merged into the root
lockfile. Because patch paths are resolved relative to the project
root, install would then fail with "Couldn't find patch file" when
the patch lived in the folder dependency's directory.

Gate both patchedDependencies parse blocks on features.patched_dependencies,
which is only true for Features.main (the root package.json).

Fixes #13531
Add a second regression test covering the workspace-member variant
of the same bug (originally #27894, closed as dup of #13531).
Supersedes #27895.
bun install stdout can vary between runs; use the lockfile
for the positive assertion instead.
@Jarred-Sumner Jarred-Sumner force-pushed the farm/0ab403ae/ignore-patched-deps-in-folder-deps branch from 4c9f2d6 to 795f5c7 Compare May 4, 2026 10:36

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM — minimal comptime guard matching the existing trustedDependencies pattern, with regression tests for both folder and workspace cases.

Extended reasoning...

Overview

This PR touches two files: src/install/lockfile/Package.zig wraps the two existing patchedDependencies parse blocks in if (comptime features.patched_dependencies) { ... }, and test/cli/install/bun-install-patch.test.ts adds two regression tests (folder dependency and workspace member). The Zig change is purely a comptime guard around unchanged inner logic — the diff is indentation plus one wrapping conditional per block.

Correctness

Features.patched_dependencies already existed in src/install/install.zig (defaulting to false, set to true only in Features.main) but was never checked in parseWithJSON. This PR adds the missing check, exactly mirroring how trustedDependencies is gated on comptime features.trusted_dependencies a few lines below (Package.zig:1558). I confirmed Features.folder, Features.workspace, Features.link, Features.npm, and Features.tarball all leave patched_dependencies at its false default, so after this change only the root manifest contributes patch entries — consistent with bun patch --commit writing to root and the lockfile serializing patchedDependencies as a single top-level key.

Security risks

None. The change narrows what is read from non-root package.json files; it does not introduce new file reads, path resolution, or external input handling.

Level of scrutiny

Low-to-moderate. The production change is a two-line mechanical guard following an established in-file pattern, evaluated at compile time (so dead-code-eliminated for non-main feature sets). The behavioral change is a bug fix: previously the merged patch paths were resolved relative to the wrong directory and failed with Couldn't find patch file, so there is no working behavior being removed.

Other factors

All CodeRabbit review threads are resolved (stdout assertion moved to lockfile; assertion ordering justified to avoid ENOENT masking the real failure). CI failures (webview-chrome, v8-heap-snapshot, spawn-stdin-readable-stream, load-file-loader-a-lot) are on unrelated test files and platforms. No CODEOWNERS coverage for these paths. The bug-hunting system found no issues.

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM — minimal comptime gate matching the existing trusted_dependencies pattern, with regression coverage for both folder and workspace cases.

Extended reasoning...

Overview

Two changes: (1) wraps both patchedDependencies parse blocks in Package.parseWithJSON (src/install/lockfile/Package.zig) with if (comptime features.patched_dependencies), and (2) adds two regression tests in test/cli/install/bun-install-patch.test.ts covering folder dependencies and workspace members. The Zig diff is pure indentation inside the new guards — no logic inside the blocks changed.

Correctness

Features.patched_dependencies defaults to false and is only set to true in Features.main (src/install/install.zig:142,162); folder, workspace, link, npm, and tarball all leave it false. The new guard therefore restricts patchedDependencies parsing to the install root, exactly mirroring the adjacent if (comptime features.trusted_dependencies) block at Package.zig:1558. This is the documented intent (bun patch --commit writes to root, lockfile serializes a single top-level key) and fixes #13531 without changing root-install behavior.

Security risks

None. The change strictly narrows which manifests can inject entries into lockfile.patched_dependencies — a non-root package can no longer cause the installer to look for patch files at arbitrary root-relative paths. No auth, crypto, or untrusted-input surface is added.

Level of scrutiny

Low. The production change is a two-line comptime guard around unchanged code, following an established in-file pattern. No CODEOWNERS apply. All CodeRabbit threads are resolved (stdout assertion moved to lockfile; exitCode-before-lockfile-read ordering justified and accepted). The one inline finding is explicitly pre-existing, non-blocking, and notes this PR reduces its trigger surface.

Other factors

Tests follow the file's existing conventions (tempDirWithFiles, Bun.spawn + Promise.all, lockfile content assertions) and use the local verdaccio-served is-even fixture already exercised throughout the suite.

Comment thread src/install/lockfile/Package.zig
@robobun

robobun commented May 4, 2026

Copy link
Copy Markdown
Collaborator Author

CI status summary across builds 47275 / 51104 / 51258:

  • bun-install-patch.test.ts (the two new tests) passed on every platform that ran it; not present in any error/flaky annotation on any build.
  • All test failures are in unrelated subsystems and appear on other PRs too:
    • test-http-should-emit-close-when-connection-is-aborted.ts (Windows timeout — also on builds 51250, 51200)
    • node-https-checkServerIdentity.test.ts (x64-asan BoringSSL LeakSanitizer — from recently-landed http: fix use-after-free in onHandshake when checkServerIdentity rejects (u9sf0l) #29829)
    • earlier: load-file-loader-a-lot.test.ts (ASAN timeout), v8-heap-snapshot.test.ts (win-aarch64 crash), webview-chrome.test.ts (Chrome not installed)
  • Builds 51104/51258 also had 31–45 jobs expire in queue (BuildKite capacity), not code failures.

The actual change here is a two-line comptime features.patched_dependencies guard in src/install/lockfile/Package.zig — no interaction with HTTP/TLS/resolver/webview.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Patching falls over when using local path dependencies

1 participant