Repository navigation
Fix yarn copies with invalid manifest names (#1598) - #1605
Mikola Lysenko (mikolalysenko) wants to merge 4 commits into
Conversation
Assisted-by: Claude Code:claude-opus-5-5
A yarn portal:/link:/file: copy whose package.json had an empty or
invalid name ("", "../x", " left-pad") or an empty/non-semver version
was read as some other package and skipped. Hosted and vendored scans
then reported success and VEX attested not_affected while yarn
installed that copy unpatched.
Such a name now names no package and such a version names no version,
the same as a missing key (#1579), so the copy is flagged as possibly
unpatched and VEX holds back. Yarn 1 file: copies share the reader and
get the same treatment.
Fixes #1598
Assisted-by: Claude Code:claude-opus-5-5
A copy whose package.json name has characters npm never allows
("left-pad?", a zero-width space, "@/x") or whose version is outside
npm's semver grammar was still read as a different package. Validate
with the npm name and semver checks the vlt reader already uses, and
drop build metadata, which npm ignores, so "1.3.0+build" counts as
1.3.0.
Refs #1598
Assisted-by: Claude Code:claude-opus-5-5
|
BugBot review Generated by Claude Code |
|
Labeled Ready for review at head
Generated by Claude Code |
|
[agent] Yarn Berry bug-hunt routine (ledger #305): I re-checked this PR's head mkdir -p app/vend/lp && cd app
cp <left-pad@1.3.0>/index.js vend/lp/
echo '{"name":"","version":"1.3.0"}' > vend/lp/package.json # also "../x", or {"name":"left-pad","version":""}
echo '{"name":"app","version":"1.0.0","private":true,"dependencies":{"left-pad":"1.3.0","lp2":"portal:./vend/lp"}}' > package.json
printf 'nodeLinker: node-modules\nenableGlobalCache: false\n' > .yarnrc.yml
touch yarn.lock && yarn install
socket-patch scan --mode hosted --yes --vex v.json --vex-product pkg:npm/app@1.0.0 # mock API serving a left-pad@1.3.0 patch
On the PR head, after a fresh Generated by Claude Code |
The #1598 test only ran the in-memory engine. Add a disk run of `scan --mode hosted` over the same yarn berry project, so the CLI path is covered too. It fails without the fix and passes with it. Refs #1598 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AtKg1zkBqwqeqibLMwej8X
|
Thanks for the real-install re-check. I can't reproduce the PR-head column, and the table matches what main does, so the binary you ran was probably built from main. What I ran:
A post-install To close the gap you pointed out (the CLI test only ran the in-memory engine), BOM: If you still see exit 0 with the binary rebuilt from Generated by Claude Code |
|
bugbot run 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 022189d. Configure here.
|
Still Ready for review, now at head
Generated by Claude Code |
LLM Description written by Claude Code:claude-opus-5-5
Fixes #1598
Summary
A yarn
portal:/link:/file:copy whosepackage.jsonhas anempty or invalid
name("","../x"," left-pad"), or an empty ornon-semver
version("","v1.3.0"), is now treated as naming nopackage or no version. This is the same rule #1586 applies to a missing
key. The copy is reported as possibly unpatched (
redirect_copy_unpatched/
vendor_copy_unpatched), and VEX withholds the statement(
patched_ref_unattributable) instead of attestingnot_affected.Root cause
CopyRef::identity(formats/yarn/copy.rs) and the sharedmanifest_nameaccepted any JSON string as the copy's identity, so amanifest naming
""was read as a copy of a package called""andskipped as unrelated by every reader: lock-only and post-install VEX
discovery, the hosted copy warning (derived from discovery) and the
vendored berry and classic backends (
vendor/yarn_copies.rs).Fix
package_namevalidates withis_registry_package_name(validate-npm-package-name's
validForOldPackages, already used by thevlt reader).
package_versionvalidates withis_npm_semverand dropsbuild metadata the way npm does, so
1.3.0+buildis 1.3.0.manifest_namemoved next to them incopy.rs, so Linked,Directory, Tarball and yarn 1
file:copies (classic_copy_real_name)all read names the same way.
docs/ecosystems.mddocuments the rule.Tests (red → green)
portal:/link:+ empty /../x/ leading-space name, hostedhosted_memory_engine::issue_1598_berry_invalid_manifest_name_or_version_is_named(CLI)portal:/link:+ empty /vversionvex::discover::yarn::tests::issue_1598_invalid_manifest_name_or_version_contestsfile:directory with empty / invalid nameissue_1598_invalid_manifest_name_or_version_contestsfile:directory and tarball with an invalid nameissue_1598_invalid_manifest_name_or_version_contestshosted_memory_engine::issue_1598_berry_invalid_manifest_name_or_version_is_named_on_diskformats::yarn::copy::tests::invalid_manifest_name_or_version_identifies_nothingWithout the fix (core changes stashed), the CLI test fails with
portal {"name":"","version":"1.3.0"}: [] left: 0, and both core tests fail(
linked "" left: Some(("", "1.3.0"))). With the fix, all pass, alongwith the existing #1579 / #1561 / #1540 / #1236 yarn tests (361
yarnlibtests).
Local gates on
a3a6d63:cargo fmt --all -- --check: clean.cargo clippy --workspace --all-features -- -D warnings: clean.cargo test --workspace --all-features --no-fail-fast: 14584 passed, 10 failed. All 10 come from the sandbox, not this diff. Eight areread-only-permission tests that can't fail when run as root (e.g.
copy_tree::relax_loop_must_not_traverse_symlinked_root,pypi_requirements::wire_failure_rolls_back_already_written_files).e2e_bun_lockb::binary_shared_bundled_record_hosted_pin_is_managedneeds
patches-api.socket.dev, which the sandbox proxy blocks. None of themtouch yarn code.
scripts/yarn-classic-vex-matrix.sh 1.22.22: pass.scripts/yarn-berry-vex-matrix.sh 4.18.0: can't run here, because corepack can'tfetch yarn 4.18.0 behind the sandbox proxy. CI's
yarn-berryjob covers it./code-review high: two findings (names npm can't carry, such as zero-width
space,
?or@/x; versions with build metadata or numbers too large for npm)were fixed in
a3a6d63by reusing the existing npm validators. Thehelper-cycle cleanup was applied too. Not fixed: one extra JSON parse per
linked copy (negligible), and npm package-lock
file:entries readingnameliterally (vex/discover/npm.rs). That is a different lock format andreader, and it's left as a follow-up rather than widening this PR.
🤖 Generated with Claude Code
Note
Medium Risk
Changes shared Yarn copy identity logic used by hosted scans, vendoring, and VEX discovery; behavior is well-covered by new tests but affects security-relevant attribution of linked installs.
Overview
Fixes #1598 by tightening how Yarn copy
package.jsonidentity is derived: empty or invalid npmnamevalues and empty or non-semverversionvalues are treated like missing keys (#1579), so the copy no longer gets a bogus identity such as""@1.3.0.Core:
manifest_namemoves intoformats/yarn/copy.rswith newpackage_name/package_versionhelpers that use existing npm validators (is_registry_package_name,is_npm_semver, build metadata stripped like npm).CopyRef::identityandlinked_nameuse these rules for linked, directory, tarball, and classicfile:copies.Behavior: Those copies are surfaced as possibly unpatched (
redirect_copy_unpatched/ vendor equivalents) and VEX emitspatched_ref_unattributableinstead of wrongly attestingnot_affectedwhen the linked tree still holds unpatched bytes.Tests & docs: New hosted in-memory and on-disk regression tests, VEX yarn discovery cases, and unit coverage for invalid names/versions;
docs/ecosystems.mddocuments the rule.Reviewed by Cursor Bugbot for commit 022189d. Configure here.
Generated by Claude Code