Repository navigation
Read Cargo.toml package name and version through one shared toml_edit reader #693
Description
[agent] Filed by the scheduled architecture audit routine (ecosystems and formats). Register: E15.
Kind: refactor. Source: review §1 recommendation 1 and Part 5.4 ("Cargo"); register E15.
Problem
Five places read a Cargo.toml [package] table, with three different parsers. Two of them are hand-rolled line scanners, although toml_edit is already a dependency of socket-patch-core.
| Reader | Parser | Used for |
|---|---|---|
crawlers/cargo_crawler.rs#L12-L113:`` parse_cargo_toml_name_version + `parse_table_header` + `extract_string_value` |
line scanner ("no TOML crate dependency") | crate identity in crawl_all (#L399-L407) and find_by_purls (#L285-L302) |
vex/product.rs#L167-L170 parse_cargo_toml → scan_toml_section |
a second line scanner (also used for pyproject.toml) |
the VEX product purl |
vendor/cargo_tag.rs#L132-L155 version_literal |
toml_edit, [package] or legacy [project] |
tagging the vendored copy's version |
vendor/cargo.rs#L1665-L1680 path_crate_version |
toml_edit, [package] only |
the version a [patch] path points at |
vendor/cargo.rs#L82-L101 declared_cargo_minor |
toml_edit, ad hoc .get("package").get("rust-version") |
the declared cargo floor |
They have drifted. I ran one set of manifests through the crawler, VEX product detection and cargo_tag on 045d7ec, in a throwaway integration test that I ran twice and did not commit. toml_edit parses all of these inputs:
Cargo.toml |
crawler | VEX product | cargo_tag |
|---|---|---|---|
[package] name/version |
("old", "0.1.0") |
pkg:cargo/old@0.1.0 |
tags it |
| same, with a UTF-8 BOM | None |
pkg:cargo/old@0.1.0 (strips the BOM) |
tags it |
legacy [project] table |
None |
None |
tags it |
dotted keys (package.name = …) |
None |
None |
tags it |
[package] junk (invalid TOML) |
("old", "0.1.0") |
None |
refuses (Unparseable) |
So a crate whose manifest cargo_tag reads can be invisible to the crawler, and the crawler accepts a manifest that cargo rejects. In a cargo vendor directory the crawler's fallback (the directory name) carries no version, so such a crate cannot be discovered at all. The VEX scanner and the crawler also disagree with each other on BOMs.
Normalized crates.io manifests always use a plain [package] table, so real registry crates hit none of these rows today. The point of this issue is the duplicate parsers and the rules that have already drifted, not a live wrong answer.
Symptoms
- Vendored cargo warns cargo_multi_version_old_cargo ("declares no rust-version") when the root package inherits rust-version from [workspace.package] #651:
declared_cargo_minorreads[package].rust-versionwith an ad hoctoml_editlookup and missesrust-version.workspace = true. A shared reader that models workspace inheritance ({ workspace = true }→[workspace.package]) fixes this once forversionandrust-versionalike.
Impact: low risk, small size. Deleting the hand-rolled scanner removes a class of "valid TOML the scanner misreads" bugs (the crawler has already needed fixes for header comments and single quotes, according to its own comments).
Proposed change
Add one pure reader in formats/cargo/manifest.rs (or formats/cargo/mod.rs), built on toml_edit:
pub(crate) struct PackageFields { name: Option<String>, version: Inherit<String>, rust_version: Inherit<String>, workspace: Option<String> }
pub(crate) enum Inherit<T> { Literal(T), Workspace, Absent }
pub(crate) fn package_fields(doc: &DocumentMut) -> Option<PackageFields> // [package], else legacy [project]Then:
- Delete
parse_cargo_toml_name_version,parse_table_headerandextract_string_valuefromcargo_crawler.rs(about 100 lines plus their unit tests). The crawler parses withtoml_edit(BOM handled by the parser) and keeps its directory-name fallback forInherit::Workspace.tests/crawler_cargo_e2e.rsandcargo_crawler/oracle.rsswitch to the shared reader. vex/product.rsparse_cargo_tomlusespackage_fields(scan_toml_sectionstays forpyproject.toml, which is E38's).cargo_tag::version_literaltakes its item from the shared lookup and keeps only the span and quote logic.path_crate_versionuses the shared reader. Its[project]blind spot goes away.
plan_cargo_toml's regex dependency scanner in patch/redirect/mod.rs is the other half of E15. It is out of scope here and will be filed separately.
Size and scope
formats/cargo/(new reader, about 60 lines),crawlers/cargo_crawler.rs(−100),vex/product.rs,vendor/cargo_tag.rs,vendor/cargo.rs.- Estimated diff: about 150 production lines added, 130 removed, plus tests.
- Out of scope: the hosted
plan_cargo_tomlscanner, pyproject parsing, Cargo.lock (already shared throughformats::cargo), and the Vendored cargo warns cargo_multi_version_old_cargo ("declares no rust-version") when the root package inherits rust-version from [workspace.package] #651 warning text. Vendored cargo warns cargo_multi_version_old_cargo ("declares no rust-version") when the root package inherits rust-version from [workspace.package] #651 can land here if the reader modelsrust-versioninheritance; otherwise it stays separate.
Acceptance criteria
- One
[package]reader informats/cargo. No hand-rolled TOML scanner readsCargo.tomlincrawlers/orvex/product.rs. - A table test over the rows above (plain, BOM,
[project], dotted keys, inlinepackage = { … },version.workspace = true, invalid TOML): crawler, VEX product andcargo_tagagree on every row. -
version.workspace = truestill falls back to the directory name in the registry layout (existing crawler tests). - Green:
cargo test -p socket-patch-core(crawler_cargo_e2e, thecargo_crawleroracle,vex::product,vendor::cargo_tag,vendor::cargo) andcargo clippy --workspace --all-targets.
Dependencies
- Rebase over Read NuGet and Cargo crawler project files through the FIFO-safe reader (#592) #602 (FIFO-safe reads in
cargo_crawler.rs). It touches the same read call sites but not the parser. - It blocks nothing. It is a step toward review recommendation 1 (one codec per format).
Activity
audit-ecosystems: E13, E15 filed (#693, #694); new E54 (#695)
Refactor queue: rank #693, #694, #695
mikolalysenko commentedon Oct 3, 2026
[agent] Shares root cause with #651:
Cargo.toml[package]fields are read through several ad hoc lookups, none of which models{ workspace = true }inheritance (declared_cargo_minor,vendor/cargo.rs:82-101, is the one #651 hits). Will be fixed together.Triaged as
priority:p2(Cargo). Not a duplicate; no open PR covers it (#602 touches the same crawler read sites, not the parser).Generated by Claude Code
mikolalysenko commentedon Oct 8, 2026
[agent] Claiming this issue for the architecture refactor routine (highest leverage: the only scoring candidate whose files no open PR touches; it collapses three Cargo.toml
[package]parsers into one). Branch: arch-refactor/693-cargo-manifest-reader. Claim-ID: 2026-10-08T05:55:51Z-7c41a9Slice taken: the shared
formats::cargo::manifestreader, used by the crawler, VEX product detection andcargo_tag. What's left:vendor/cargo.rs(path_crate_version,declared_cargo_minor, and #651'srust-versioninheritance), because five open PRs change that file.Generated by Claude Code
mikolalysenko commentedon Oct 8, 2026
[agent] Draft PR: #1110.
Generated by Claude Code
refactor: #1110 for #693 slice 1; re-rank at ea09714