[agent] Filed by the scheduled architecture audit routine (CLI and core). Register: discussion #560 register.
Kind: bug. Source: new finding; register C44.
Problem
Verified on main @ 045d7ec. The same ecosystem scope filter accepts different spellings depending on where it is set:
- Flag/env:
--ecosystems / SOCKET_ECOSYSTEMS goes through parse_supported_ecosystem, which requires an exact, case-sensitive match on cli_name() with no trim (args.rs#L33-L44).
- Config: socket.yml
patches.ecosystems trims, lowercases and offers a "did you mean" hint (socket_yml.rs#L602-L631).`` The test every_key_parses pins `ecosystems: [NPM, pypi]` as valid.
- Third copy:
vendor::ecosystem_in_scope does its own exact cli_name() == eco lookup (vendor.rs#L343-L352).
The sibling filter shows the intended shape: --min-severity and socket.yml minSeverity share one parser (policy::parse_min_severity → socket_yml::parse_severity_name, which trims and ignores case), so --min-severity High and minSeverity: High agree.
Proof by execution (debug CLI built from 045d7ec, run twice):
$ socket-patch list --json --ecosystems NPM
error: invalid value 'NPM' for '--ecosystems <ECOSYSTEMS>': unsupported ecosystem `NPM` (supported: npm, pypi, …) # exit 2
$ socket-patch list --json --ecosystems "npm, pypi"
error: invalid value ' pypi' for '--ecosystems <ECOSYSTEMS>': unsupported ecosystem ` pypi` … # exit 2
$ SOCKET_ECOSYSTEMS=PyPI socket-patch list --json # exit 2
$ cargo test -p socket-patch-core --lib policy::socket_yml::tests::every_key_parses # ok: [NPM, pypi] → ["npm","pypi"]
--min-severity High and --min-severity " high" both parse.
Symptoms
None filed. Impact: a user who copies ecosystems: [NPM, PyPI] from socket.yml into SOCKET_ECOSYSTEMS, or writes -e "npm, pypi", gets a usage error (exit 2) from the flag while the file form works. That is an inconsistent CLI surface with a small blast radius (p3).
Proposed change
- Add
Ecosystem::from_cli_name(&str) -> Option<Ecosystem> in crawlers/types.rs (trim + ASCII-lowercase) and one shared rejection message with the "did you mean" hint.
- Use it in
parse_supported_ecosystem (which stores the canonical cli_name()), in socket_yml ecosystems, and in vendor::ecosystem_in_scope.
- Delete: the exact-match lookup in
args.rs, the inline known/to_lowercase loop in socket_yml.rs and the lookup in vendor.rs.
- Contract: accepting more spellings is additive, and the
value_delimiter = ',' behavior pinned in CLI_CONTRACT stays. Add one sentence to the --ecosystems row ("case-insensitive; surrounding spaces ignored").
Size and scope
crawlers/types.rs, cli/src/args.rs, policy/socket_yml.rs, commands/vendor.rs and CLI_CONTRACT.md. About 60 production lines. Out of scope: other enum flags.
Acceptance criteria
Dependencies
None. Touches commands/vendor.rs lightly; no conflict with the arch-refactor PRs.
[agent] Filed by the scheduled architecture audit routine (CLI and core). Register: discussion #560 register.
Kind: bug. Source: new finding; register C44.
Problem
Verified on main @
045d7ec. The same ecosystem scope filter accepts different spellings depending on where it is set:--ecosystems/SOCKET_ECOSYSTEMSgoes throughparse_supported_ecosystem, which requires an exact, case-sensitive match oncli_name()with no trim (args.rs#L33-L44).patches.ecosystemstrims, lowercases and offers a "did you mean" hint (socket_yml.rs#L602-L631).`` The testevery_key_parsespins `ecosystems: [NPM, pypi]` as valid.vendor::ecosystem_in_scopedoes its own exactcli_name() == ecolookup (vendor.rs#L343-L352).The sibling filter shows the intended shape:
--min-severityand socket.ymlminSeverityshare one parser (policy::parse_min_severity→socket_yml::parse_severity_name, which trims and ignores case), so--min-severity HighandminSeverity: Highagree.Proof by execution (debug CLI built from
045d7ec, run twice):--min-severity Highand--min-severity " high"both parse.Symptoms
None filed. Impact: a user who copies
ecosystems: [NPM, PyPI]from socket.yml intoSOCKET_ECOSYSTEMS, or writes-e "npm, pypi", gets a usage error (exit 2) from the flag while the file form works. That is an inconsistent CLI surface with a small blast radius (p3).Proposed change
Ecosystem::from_cli_name(&str) -> Option<Ecosystem>incrawlers/types.rs(trim + ASCII-lowercase) and one shared rejection message with the "did you mean" hint.parse_supported_ecosystem(which stores the canonicalcli_name()), insocket_ymlecosystems, and invendor::ecosystem_in_scope.args.rs, the inlineknown/to_lowercaseloop insocket_yml.rsand the lookup invendor.rs.value_delimiter = ','behavior pinned in CLI_CONTRACT stays. Add one sentence to the--ecosystemsrow ("case-insensitive; surrounding spaces ignored").Size and scope
crawlers/types.rs,cli/src/args.rs,policy/socket_yml.rs,commands/vendor.rsandCLI_CONTRACT.md. About 60 production lines. Out of scope: other enum flags.Acceptance criteria
--ecosystems NPM,-e "npm, pypi"andSOCKET_ECOSYSTEMS=PyPIparse to["npm"],["npm","pypi"]and["pypi"](args unit test).--ecosystems bogusand the empty-token message stay as they are; socket.yml[npn]keeps its "did you meannpm" hint, and the flag gains the same hint.every_key_parses,ecosystems_flag_splits_and_validatesand the socket.yml error-path table (patches.ecosystems[0]) stay green.grep -rn "cli_name() ==" crates/*/srchas no production matches outsidefrom_cli_name.Dependencies
None. Touches
commands/vendor.rslightly; no conflict with thearch-refactorPRs.