Skip to content

Stop vendored runtimes leaking into a workspace's shared node_modules - #18

Merged
arcaputo3 merged 1 commit into
agent/bun-dep-interpolatorfrom
agent/bun-vendored-guard
Aug 26, 2026
Merged

Stop vendored runtimes leaking into a workspace's shared node_modules#18
arcaputo3 merged 1 commit into
agent/bun-dep-interpolatorfrom
agent/bun-vendored-guard

Conversation

@arcaputo3

Copy link
Copy Markdown
Contributor

Stack 5/N. Base is agent/bun-dep-interpolator (#17), not main.

The bug

BunScalaJSModule.bunInstall ran mergeVendoredNodeModules(…, dest / "node_modules") unconditionally — including after the workspace branch had already symlinked that path to the shared workspace install's Task.dest.

So the merge wrote through the symlink into another task's output directory, one shared by every other member of the workspace. Silent cross-task mutation, and non-deterministic depending on which member ran first.

The fix

  • mergeFromClasspathEntry refuses a symlinked destination root, naming the task the directory actually belongs to. On its own this converts a silent corruption into a loud, diagnosable failure.
  • The merge moved into the non-workspace branch. Workspace members carrying a vendored-runtime dependency now fail with an actionable message instead of corrupting the shared install.

On the second point: sharing one node_modules across members is the point of a workspace, so merging per-member was never going to be right. Hoisting vendored trees up to the workspace install is the semantically correct behavior, but that's a feature rather than a bug fix — deliberately left out of this PR.

Why nothing caught it

BunVendoredNodeModules.mergeFromClasspathEntry no-ops unless the classpath entry carries META-INF/bun/node_modules, and no fixture combines a vendored-runtime dependency with a workspace member.

The new unit test asserts both halves: the merge throws, and nothing leaked into the shared directory.

Verification

Unit 70 passing, integration 41 passing.

🤖 Generated with Claude Code

`BunScalaJSModule.bunInstall` merged vendored node_modules into
`dest/node_modules` unconditionally -- including after the workspace branch
had symlinked that path to the shared workspace install's Task.dest. The
merge therefore wrote into another task's output, shared by every member of
the workspace.

- `mergeFromClasspathEntry` refuses a symlinked destination root and names
  the task the directory belongs to. On its own this turns a silent
  cross-task write into a loud failure.
- The merge moved into the non-workspace branch, and workspace members with a
  vendored-runtime dependency now fail with an actionable message instead.
  Sharing one node_modules across members is the point of a workspace, so
  merging per-member was never going to be right; hoisting vendored trees to
  the workspace install is a feature, not a bug fix, and is left for later.

Only reachable with a published vendored-runtime dependency -- mergeFrom-
ClasspathEntry no-ops unless the entry carries META-INF/bun/node_modules --
which is why no fixture caught it.

Unit 70 passing, integration 41 passing.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@arcaputo3
arcaputo3 merged commit 5f14695 into agent/bun-dep-interpolator Aug 26, 2026
@arcaputo3
arcaputo3 deleted the agent/bun-vendored-guard branch August 26, 2026 22:11
@arcaputo3
arcaputo3 restored the agent/bun-vendored-guard branch August 26, 2026 22:16
@arcaputo3
arcaputo3 deleted the agent/bun-vendored-guard branch August 26, 2026 22:17
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