Repository navigation
Fix workspace member globs for yarn 1 and npm (#1097) - #1480
Merged
Mikola Lysenko (mikolalysenko) merged 4 commits intoOct 13, 2026
Merged
Conversation
Assisted-by: Claude Code:claude-opus-5-5
A hosted scan or get run from a workspace member must refuse, since the member installs from the root's lock. The member check read every root's package.json "workspaces" like npm, so it disagreed with the package manager in two ways: - yarn classic (and Bun before 1.3) ignore "!" patterns, so a member excluded with "!packages/b" is still installed from the root lock. - npm and yarn match extglobs like packages/@(a|b); the matcher matched nothing. In both cases the run pinned nothing and reported success while the next install brought in the unpatched package. The check now picks the dialect from the root's lock: yarn classic vs berry by berry's __metadata key, Bun 1.3+ by the configVersion it writes into bun.lock. A root with several locks refuses when any manager lists the member; a lockless root reads the widest set. Fixes #1097 Assisted-by: Claude Code:claude-opus-5-5
Review follow-ups on the workspace dialect fix:
- A root with several locks now governs the member only through the
locks whose package manager lists it. The refusal names just those,
and a member's own npm, Bun or vlt lock is no longer called stray
when its own manager excludes the member.
- yarn berry applies "!" patterns whatever their order and reads a
leading "!(" as an extglob; yarn classic skips any "!" pattern.
- Ambiguous extglobs such as *(a|aa) no longer take exponential time.
- The lock sniff reads only the head of yarn.lock / bun.lock, reuses
the shared berry check, and needs configVersion at the top level.
Assisted-by: Claude Code:claude-opus-5-5
Mikola Lysenko (mikolalysenko)
marked this pull request as ready for review
October 13, 2026 13:20
Collaborator
Author
|
BugBot review Generated by Claude Code |
The workspace dialect check sniffs the head of yarn.lock and bun.lock. It opened them with a plain open, so a FIFO at that path could block a hosted scan or get forever. It now uses the shared regular-file opener, which fails fast on anything but a regular file. Assisted-by: Claude Code:claude-opus-5-5
Collaborator
Author
|
BugBot review Generated by Claude Code |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit bfa67a3. Configure here.
Tanmay Singla (Tanmay182003)
approved these changes
Oct 13, 2026
Mikola Lysenko (mikolalysenko)
deleted the
agent/fix-workspace-glob-dialects
branch
October 13, 2026 14:15
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
LLM Description written by Claude Code:claude-opus-5-5
Fixes #1097
Summary
A hosted
scan/getfrom a workspace member must refuse withredirect_workspace_lockfile_elsewhere, because the member installs fromthe root's lock. The member check read every root's
package.jsonworkspaceslike npm does. It now reads them the way the package managerthat owns the root's lock does.
Root cause
workspaces_include(utils/workspace_globs.rs, called fromhosted/governing_root.rs) applied npm's last-match-wins!negationand had no extglobs, for every lock. I probed it on this box:
["packages/*","!packages/b"]["!packages/b","packages/*"]["packages/@(a|b)"]["!(internal)"]So under a yarn classic (or pre-1.3 Bun) root, a
!-excluded member wasdropped. Under npm/yarn roots, an extglob matched nothing. Either way the
refusal never fired, and the run reported success with nothing pinned.
Fix
WorkspacesDialectdescribes how each manager readsworkspaces:negation is last-match-wins (npm, Bun 1.3+, vlt), unordered (yarn
berry, where a leading
!(is an extglob), or ignored (yarn classic,Bun < 1.3). Extglobs are on for npm and yarn only.
shared
is_berry_locksniff. Bun 1.3+ is detected by the top-levelconfigVersionit writes intobun.lock(1.2.23 writes none, and 1.4adds
configVersion: 0when it rewrites an older lock). Only the headof the lock is read.
names just those, and the stray-member-lock check (Hosted and vendored scans run from an npm workspace member that has a stray package-lock.json of its own rewrite that lock, which npm ignores, and report success while npm installs the unpatched package and VEX attests not_affected #1094/Hosted and vendored scans from a Bun workspace member with a stray bun.lock / bun.lockb pin that ignored lock, exit 0, and lock-only VEX attests not_affected while Bun installs the unpatched package #1101/Hosted and vendored scans from a vlt workspace member with a stray vlt-lock.json write to that lock, which vlt ignores, and exit 0 (vendored VEX then attests not_affected while
vlt cifails) #1134)no longer calls a member's own lock stray when its own manager
excludes the member. A lockless intermediate root lists a member when
any dialect does.
@ ? * + !, nested, minimatch's!(..)restsemantics) is memoized, so ambiguous groups stay polynomial.
CLI_CONTRACT.mddocuments the per-manager grammar.Bun < 1.3 (from the issue comments) is covered: a
bun.lockwithoutconfigVersion, or abun.lockbalone, ignores negation.Changed test:
package_json_workspace_non_members_are_left_aloneasserted that an empty
yarn.lockroot drops a!-negated directory.That is the #1097 bug for yarn classic, so the test now uses a berry lock
for that assertion. Berry really does drop the directory.
Test evidence
in_process_redirect_pnpm::hosted_run_from_negated_or_extglob_workspace_member_refuses(
scanandget; yarn classic / old Bun / bun.lockb negation, npm,shrinkwrap, classic and berry extglobs). Red on main 15c2c83: the
first case reports
"status":"success"withredirect_unconfirmed.Green on d7b844c.
workspace_globs::{extglob_dialects_match_like_npm_and_yarn, negation_is_per_dialect, ambiguous_extglobs_stay_fast}andgoverning_root::{package_json_workspaces_read_in_the_root_locks_dialect, lockless_intermediate_root_reads_the_widest_dialect, only_the_locks_whose_manager_lists_the_member_govern_it, bun_config_version_is_read_at_the_top_level_only}.cargo fmt --all -- --check: clean.cargo clippy --workspace --all-features -- -D warnings: clean.cargo test --workspace --all-features: 14345 passed, 13 failed. All13 are environmental. 12 are write-failure / unremovable-file tests
that can't fail as root (this sandbox runs as uid 0), and
e2e_bun_lockb::binary_shared_bundled_record_hosted_pin_is_managedneeds network to patches-api.socket.dev. None of them touch the changed
code. CI is the arbiter.
Per-issue checklist
!pattern (yarn 1 ignores it) or an extglob like packages/@(a|b) #1097!half (yarn classic, Bun < 1.3): e2e +package_json_workspaces_read_in_the_root_locks_dialect!pattern (yarn 1 ignores it) or an extglob like packages/@(a|b) #1097 extglob half (yarn and npm, per the comments): e2e +extglob_dialects_match_like_npm_and_yarn!pattern (yarn 1 ignores it) or an extglob like packages/@(a|b) #1097getentry point (comment): e2e coversgetBugbot (d7b844c) found 1 issue, the lock head read bypassing the FIFO-safe opener. Fixed in bfa67a3 with a test.
/code-review high ran on d9d05fd. All 9 findings were fixed in d7b844c:
lock filtering (3), berry negation order and
!(, extglob blowup, head-onlylock reads, reuse of
is_berry_lock, top-levelconfigVersion, and a?()simplification.Follow-up, out of scope:
npm_crawler's workspace directory expansionstill has no extglob support.
🤖 Generated with Claude Code
https://claude.ai/code/session_01FkKQZyi8RSQAgn4DdJc2DP
Generated by Claude Code