Repository navigation
Match package targets by PurlKey identity, not by lowercase (#1292) - #1294
Mikola Lysenko (mikolalysenko) merged 4 commits into
Conversation
Assisted-by: Claude Code:claude-opus-5-5
remove, rollback and get compared a versionless purl or a package name to recorded purls by lowercasing every ecosystem, while versioned purls compared through the case-preserving PurlKey. So `remove pkg:npm/jsonstream` or `remove jsonstream` also dropped (and rolled back) JSONStream's patch, and Go's Sirupsen/sirupsen logrus were one package to the ambiguity guard. utils::target now keys packages by the PurlKey spelling without the version: versionless purls match only the same package (case folded only for PyPI, NuGet and Composer), and a lowercase name reaching case-distinct packages is refused as ambiguous_target. A name typed with an uppercase letter settles on its exact-case package. The private lowercase + PEP 503 identity fold is deleted. Fixes #1292 Assisted-by: Claude Code:claude-opus-5-5
|
BugBot review Generated by Claude Code |
Assisted-by: Claude Code:claude-opus-5-5
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 9c7a1da. Configure here.
|
[agent] Two checks are red on
Both match #1293: production stopped serving the pinned minimist patch between 15:29Z and 15:49Z, and every PR and merge-group run fails the same way. Neither suite reaches the code this PR changes: the UUID path of Generated by Claude Code |
|
Ready for review (burn-down agent).
Generated by Claude Code |
Assisted-by: Claude Code:claude-opus-5-5
LLM Description written by Claude Code:claude-opus-5-5
Fixes #1292
Summary
get,removeandrollbackselect packages throughutils::target::Target. Before this PR it used two case rules. Versioned purls compared through the case-preservingPurlKey. Versionless purls, names and the ambiguity guard lowercased every ecosystem. Soremove pkg:npm/jsonstreamorremove jsonstreamalso droppedJSONStream's patch, and with rollback also restored its files. Go'sSirupsen/sirupsenlogrus counted as one package.Targetnow keys packages by one identity:package_identity, thePurlKeyspelling (canonical_base_purl) without the version.Why (leverage)
remove pkg:npm/jsonstreamalso removes JSONStream's patch #1292, a destructive command acting on a second, distinct package.utils/target.rsis deleted. Purl targets stop going through the lenientscan --packagefilter matcher, so one equivalence (PurlKey) decides "same package" for everyTargetpurl.Register row C80 (register); living document
doc/02-cli.md{{C80}}.What changed
package_identityreturnscanonical_base_purlminus the version. Case folds only for PyPI (PEP 503), NuGet and Composer. It stays case-sensitive for npm, Go, Maven, cargo and gem.Versionless purl targets match by identity equality in
matches_packageandmatches_patch. Versioned purl targets inmatches_packageusePurlKey::same, the same rulematches_patchalready used. This meansgetno longer selects a package thatremovewith the same spelling can't select.settlecounts case-distinct identities:JSONStreamandjsonstreamisambiguous_target;JSONStream).The settled target narrows to one identity (
only: Option<String>); before, it narrowed with afull_name_onlyflag.Names are still matched case-insensitively (
LODASH→lodash).package_spec_matches(used byscan --packageand socket.yml) is unchanged.CLI_CONTRACT.md: the target-grammar paragraph documents the case rule and the new ambiguity case.Deleted
The lowercase + PEP 503 fold in
package_identity, and thepackage_spec_matchescalls for purl targets. Production:utils/target.rs+78/−34 (mostly doc comments). Tests: +113 core, +55 CLI. Contract: 2 lines.Behavior
These changes are limited to case-distinct packages in case-sensitive ecosystems:
pkg:npm/jsonstreamno longer selectspkg:npm/JSONStream@…. The same holds for Go, Maven, cargo and gem.ambiguous_target. Before, it selected both.@version.Everything else is unchanged, including the PyPI/NuGet/Composer spelling folds (existing #926/#1024 tests are green).
Tie-break, open to review: #1292's acceptance asks that
jsonstreambe ambiguous butJSONStreamsettle on itself. I implemented that as "an uppercase letter in the typed name means exact case". All-lowercase is how users type any name, so it stays ambiguous.Test evidence
cargo clippy --workspace --all-features -- -D warnings: clean.cargo test -p socket-patch-core --lib: 6093 passed, 4 failed. The 4 are the known root-sandbox failures, which also fail on main (relax_loop_must_not_traverse_symlinked_root,an_unremovable_hidden_lock_keeps_every_store_entry,wire_write_failure_maps_error_and_leaves_lock_untouched,wire_failure_rolls_back_already_written_files).purl_targets_agree_on_case_in_every_ecosystem: a table over npm, golang, maven, cargo, gem, pypi, nuget and composer, checking versioned and versionless targets withmatches_patchandmatches_package;case_distinct_packages_are_two_packages;package_identity_drops_version_and_qualifiers.cargo test -p socket-patch-cli --all-features --test in_process_target_ambiguity: 9 passed.utils/target.rsfrommain,remove_never_reaches_a_case_distinct_packageandrollback_refuses_a_lowercase_name_reaching_case_distinct_packagesFAIL. Both pass on this branch.Risk
Medium-low. One file of logic. The selection only narrows: a target never selects more than it did before.
🤖 Generated with Claude Code
https://claude.ai/code/session_01WeCUZpHUvuy3cinyNW94My
Note
Medium Risk
Changes selection for
get/remove/rollbackon case-distinct packages in case-sensitive ecosystems—previously a single lowercase target could affect the wrong patch; behavior narrows rather than broadens.Overview
Fixes #1292 by unifying how
get,remove, androllbackdecide “same package” inutils::target::Target.Package identity now comes from
canonical_base_purl/PurlKey: case is preserved for npm, Go, Maven, cargo, and gem; PyPI, NuGet, and Composer still fold per ecosystem rules. Versionless purl targets and patch matching use that identity instead of lowercasing everything or going throughpackage_spec_matches. Versioned purlmatches_packageusesPurlKey::same, aligned withmatches_patch.Ambiguity / settle: lowercase names that would hit multiple case-distinct packages (e.g.
jsonstream→JSONStreamandjsonstream) exit with ambiguity; a name with an uppercase letter settles to exact-case spelling (JSONStream). Narrowing is stored inonly: Option<String>instead offull_name_only.Docs (
CLI_CONTRACT.md) and in-process CLI tests cover the new behavior; core unit tests exercise per-ecosystem case rules.Reviewed by Cursor Bugbot for commit 9c7a1da. Configure here.
Generated by Claude Code