Skip to content

Fix hosted cargo dotted-key and literal pins (#757) - #1743

Open
Mikola Lysenko (mikolalysenko) wants to merge 4 commits into
mainfrom
agent/fix-cargo-dotted-literal-pins
Open

Mikola Lysenko (mikolalysenko) wants to merge 4 commits into
mainfrom
agent/fix-cargo-dotted-literal-pins

Conversation

@mikolalysenko

@mikolalysenko Mikola Lysenko (mikolalysenko) commented Oct 27, 2026 •

Copy link
Copy Markdown
Collaborator

LLM Description written by Claude Code:claude-opus-5-5

Fixes #757

Finishes #757, which #1735 left open. Hosted cargo now pins the last two rows of the issue's table, dotted keys and literal-string versions. Before this, scan --mode hosted warned redirect_cargo_toml_dep_unrewritable on them and left the crate unpatched.

Root cause

Hosted cargo plans Cargo.toml pins with a line scanner (plan_cargo_toml). Upstream restore (unpin_line) recognizes only the spellings that scanner writes. Neither had a rule for:

  • dotted keys: serde.version = "1.0.0", or a rename alias.package = "serde" + alias.version = …
  • literal-string versions: serde = '1.0.0'

Change

  • Planner, dotted keys. A dependency's dotted lines are gathered across their table, since TOML allows them anywhere in it, and classified like the [dependencies.<key>] table form: rename, workspace = true, path/git, registry-index, and an existing socket-patch-* or crates-io registry, which is superseded in place. The pin is a new <key>.registry = "socket-patch-<uuid>" line right after the version line. It reuses that line's key spelling, indent and line ending.
  • Planner, literal versions. serde = '1.0.0' becomes serde = { registry = "…", version = '1.0.0' }. It is written registry-first so restore can tell it apart from a user's own one-line { version = '…' } table, which the one-line rewrite pins version-first.
  • Pin readers (CargoRegistryPins and its test oracle) read a dotted pin at the end of its table and resolve a dotted rename's owning crate.
  • Restore (unpin_line) drops the added <key>.registry line and collapses the registry-first literal table back to '…'.

Spellings still refused, both rare: multi-line string versions ('''1.0''', """1.0"""), and keys nested below <key>.<field>. The policy refusals stay as before: path/git, registry-index, another registry, an ambiguous requirement.

Tests (red → green)

New tests fail on main and pass here:

Test What it covers
cargo_literal_string_version_is_pinned '…', with a comment, with a quoted key; LF + CRLF
cargo_dotted_keys_are_pinned plain, wrapped features after the version line, other deps in between, rename, quoted/spaced key, crates-io repin; LF + CRLF; a rescan writes nothing
cargo_dotted_workspace_dependency_is_pinned dotted [workspace.dependencies] + serde.workspace = true; another version left alone
cargo_dotted_pin_is_superseded_in_place rescan to a newer patch
cargo_dotted_unreadable_package_falls_back_to_the_key no partial pin; unreadable registry wording
cargo_socket_registry_pin_reads_back_every_written_shape (+3 shapes) readers read back literal, dotted and renamed dotted pins
dotted_and_literal_pins_unpin_to_the_original_spelling unpin_line per spelling; a user's literal table keeps its table
restore_unpins_dotted_and_literal_pins_byte_exact restore is byte-exact for LF, CRLF, BOM and CRLF+BOM
e2e cargo_hosted_dotted_and_literal_spellings_are_pinned real cargo: scan, offline locked build of the patched copy, vex, byte-exact remove; dotted (LF/CRLF), renamed dotted, literal (LF/CRLF)

Without the fix, the e2e test fails with cfg-if in Cargo.toml cannot be pinned (declared with dotted keys this rewriter does not edit).

Updated tests: cargo_unsupported_spellings_refuse_whole_dep now lists only the refusals that remain, and adds dotted path/git/registry-index/other-registry rows. cargo_dotted_literal_renames_* now expects a pin. cargo_unrewritable_occurrence_skips_dep_entirely and mode_migration_cargo::takeover_over_unrewritable_spelling_keeps_vendored switch to spellings that are still refused.

Commands run locally

  • cargo fmt --all -- --check: clean
  • cargo clippy --workspace --all-features -- -D warnings: clean
  • cargo test -p socket-patch-core --all-features: 6806 passed, 4 failed. The 4 failures are copy_tree::relax_loop_must_not_traverse_symlinked_root, vlt_heal::an_unremovable_hidden_lock_keeps_every_store_entry, pypi_poetry::wire_write_failure_… and pypi_requirements::wire_failure_…. They are chmod-based tests that can't fail when run as root in this sandbox, and they fail identically on unchanged main.
  • Cargo e2e suites with SOCKET_PATCH_CARGO_E2E_REQUIRED=1 (cargo 1.93.1): e2e_redirect_cargo_build 23/23, e2e_redirect_cargo_shapes 35/35, e2e_vendor_cargo_build 40/40, mode_migration_cargo 30/30
  • The npm, pypi and gem wrappers only dispatch to the binary, so they needed no change.

/code-review high

Fixed: the literal-table restore ambiguity, the unreadable dotted package and registry handling, and stale docs.

Not fixed:

  • Duplication between the dotted classifier and the table-form classifier, and across the three line scanners. The issue's proposed toml_edit planner rewrite removes it at the root. This PR keeps to the line-scanner design Fix hosted cargo pins for multi-line inline tables (#757) #1735 extended, so the change stays reviewable.
  • Copying the line's \r on the dotted insert. The table-form insert doesn't, but restore drops either line whole, and copying it keeps a mixed-ending file consistent.
  • O(n²) over dotted keys in one table. n is the number of dotted-key dependencies in a single table, so this is negligible.

https://claude.ai/code/session_011f9aeQKabmsWm4uJyqrMaD


Generated by Claude Code

Assisted-by: Claude Code:claude-opus-5-5
Hosted cargo scan refused two valid Cargo.toml spellings and left the
crate unpatched with redirect_cargo_toml_dep_unrewritable:

    serde.version = "1.0.0"      # dotted keys
    serde = '1.0.0'              # literal-string version

Dotted keys are now gathered per dependency across their table, since
TOML lets them sit anywhere in it, and classified like the table form:
rename, workspace inheritance, path/git, registry-index and an earlier
or crates-io registry. The pin is a new <key>.registry line right after
the version line, using that line's key spelling, indent and line
ending. A rescan moves an earlier pin in place.

A literal-string version is pinned as { version = '...', registry =
"..." }, keeping the user's quotes.

The pin readers resolve a dotted rename's owning crate, and restore
drops the added dotted line and collapses the literal table back to
'...', so remove and rollback leave the manifest byte-identical for
LF, CRLF and BOM files.

Spellings still refused are multi-line string versions and keys nested
deeper than <key>.<field>.

Fixes #757

Assisted-by: Claude Code:claude-opus-5-5
A real-cargo shape pins dotted keys (with a wrapped features array and
a rename) and a literal-string version for LF and CRLF manifests,
builds against the patched copy offline, and checks remove restores
every byte.

The vendored-to-hosted takeover test needs spellings hosted mode still
refuses, so it now uses multi-line string versions instead of the two
spellings that hosted mode pins now.

Refs #757

Assisted-by: Claude Code:claude-opus-5-5
Review follow-ups for the dotted-key and literal-string pins:

- A literal version is now pinned registry-first. The earlier spelling
  matched what the one-line rewrite writes for a user's own
  { version = '...' } table, so remove collapsed that table into a bare
  string. That table now comes back byte-exact.
- A dotted rename whose package value can't be read falls back to the
  key, as the table form and the pin readers do.
- A dotted registry value that can't be read is reported as an
  unreadable spelling, not as a registry named "".
- Doc comments name the dotted shape and the readers' scan order.

Refs #757

Assisted-by: Claude Code:claude-opus-5-5
@mikolalysenko
Mikola Lysenko (mikolalysenko) marked this pull request as ready for review October 27, 2026 17:07
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

BugBot review


Generated by Claude Code

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ 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 b29ceb4. Configure here.

@mikolalysenko Mikola Lysenko (mikolalysenko) added the Ready for review Agent-verified: mergeable, CI green, Bugbot clean — awaiting human review label Oct 27, 2026
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

Burn-down agent: labeled Ready for review at head b29ceb4.

  • CI: 82/82 checks on b29ceb4 passed, skipped or neutral (31 success, 50 skipped by path filters, 1 neutral). Mergeable with main, and no main-wide failures.
  • Bugbot: reviewed b29ceb4 and found no new issues. No open review threads.
  • CHANGELOG.md untouched.
  • For the reviewer: two rare spellings are still refused on purpose: multi-line string versions and keys nested below <key>.<field>. Restore round-trips are tested byte-exact for LF, CRLF and BOM.

Generated by Claude Code

@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

Final review brief (head b29ceb4)

What it does. Hosted cargo scan can now pin two Cargo.toml spellings it used to refuse with redirect_cargo_toml_dep_unrewritable: dotted keys (serde.version = "1", including a dotted package rename) and literal-string versions (serde = '1'). Restore reverses both byte-exact. This closes the last two rows of #757.

Risk: low to medium. It touches only the hosted-cargo line scanner, the pin readers and unpin_line. A crate declared in a spelling the planner reads wrong would go unpinned or get refused, not corrupted: every output is re-parsed as TOML in the tests, and anything unreadable still refuses the whole dependency. The literal pin is written registry-first, so restore can tell it apart from a user's own { version = '…' } table. That is the subtle part.

Look here

  • redirect/mod.rs:4071: the dotted classifier. It mirrors the table form: workspace, rename, path/git, registry-index, supersede, then insert <key>.registry after the version line.
  • redirect/mod.rs:3998: literal-string versions, pinned as { registry = …, version = '…' }.
  • redirect/mod.rs:3192 / :3228: dotted lines are gathered per table, and the readers resolve the owner through package.
  • upstream/cargo.rs:336:`` restore's LITERAL_SHORTHAND_RE and `is_dotted_pin`.
  • e2e_redirect_cargo_shapes.rs:1161:``` the real-cargo e2e: scan, offline locked build, vex, byte-exact remove.

Verified

  • Read the full diff (4 files, +714/−76).
  • Checked that dotted lines are only collected inside dependency tables, so no lines leak across sections. Checked that the flush on each header keeps the per-table scope. Checked that inserted lines keep the source line's \r, so a CRLF file isn't mixed (bottom-up insert, joined on \n). Checked that multi-line values, deeper keys and unreadable registry still refuse.
  • Ran locally: cargo test -p socket-patch-core --lib -- dotted literal, 61/61 passed.
  • CI: ci-ok and clippy green, 82/82 checks passed, skipped or neutral. Bugbot reviewed b29ceb4 and found no issues. No review threads. CHANGELOG.md untouched.

Changes I made: none.

Open questions: none blocking. Two rare spellings are still refused on purpose (multi-line string versions and keys nested below <key>.<field>), and both get a warning.

Auto-merge is armed, so approving sends this straight to the merge queue.


Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Ready for review Agent-verified: mergeable, CI green, Bugbot clean — awaiting human review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Hosted cargo redirect refuses a dependency whose inline table has a multi-line features array, because it plans Cargo.toml pins with a line scanner

2 participants