Repository navigation
Roll back a vendored PDM 0.x dependency declared with extras - #2060
Mikola Lysenko (mikolalysenko) wants to merge 2 commits into
Conversation
`rollback` refused to undo socket-patch's own vendoring of a PyPI
package in a PDM 0.x project that declares it with extras
(`urllib3 = {version = "==1.26.18", extras = ["socks"]}`):
refusing to revert pkg:pypi/urllib3@1.26.18: for pdm.lock, the
ledger record for it would change entries other than urllib3's
own, which is not an edit socket-patch makes
PDM's lock_version 2 format keeps file hashes in `[metadata.files]`,
keyed `<name> <version>`, and a unit with extras has a key of its own,
`<name>[<extras>] <version>`. Vendoring rewrites both. The revert's
confinement check, new in 5.1.0 (#2052), read a key's package as its
first word, so `urllib3[socks]` counted as another package's entry
and the restore was refused. Nothing was written: the project stayed
vendored until its lock was restored from version control.
The check now drops the `[<extras>]` suffix before it compares names.
Another package's extras key is still refused.
Test: confinement_allows_a_pdm_revert_in_every_native_format runs the
PDM lock writer over every native lock fixture and holds the check to
accepting the revert. It fails on 0.12.3-extras without this change.
Found by depscan's PDM patch backtest on the 5.1.0 bump (PDM 0.12.3,
extras, vendored). The same cell passes with this build.
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Review follow-up for the extras rollback fix. The check's reading of a `[metadata.files]` key is now `pdm_lock::files_key_package`, next to `legacy_files_key`, which builds the key, with a test that every key the writer builds for the PDM 0.x fixtures reads back as its unit's package. The two can no longer drift apart unnoticed, which is how the 5.1.0 refusal shipped. The `[<extras>]` suffix is dropped only for `files` / `hashes` keys. A `sources` key is read as before, so `"six[socks]"` under `[tool.uv.sources]` is not six's own entry. Tests: revert_round_trip_restores_a_legacy_lock_with_extras vendors and reverts urllib3 in the native PDM 0.12.3 extras lock through wire_pdm and revert_pdm, the path that failed. Without the fix it fails with the refusal users saw. The confinement sweep takes its fixture list from pdm_lock's tests instead of a copy. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
PR SummaryMedium Risk Overview Adds Adds unit and integration tests: key parsing over native fixtures, confinement accepting reverts across all rewritable PDM lock formats, and a Reviewed by Cursor Bugbot for commit 0baea26. Configure here. |
Final review briefWhat it does: Risk: low. The change is confined to how the confinement check names Look here:
Verified: I read the full diff. Changes I made: none. Open questions: none blocking. Consider a follow-up issue for the pre-existing Auto-merge is armed, so approving sends it straight to the merge queue. Generated by Claude Code |
What was wrong
In 5.1.0,
rollbackrefuses to undo socket-patch's own vendoring of a PyPI package in a PDM 0.x project that declares it with extras, for exampleurllib3 = {version = "==1.26.18", extras = ["socks"]}:Nothing is written, so no file is damaged, but the project stays vendored until its lock is restored from version control.
scan --mode vendoredon the same project succeeds, and the hosted flow is not affected.Cause
PDM's
lock_version = "2"format keeps file hashes in[metadata.files], keyed<name> <version>. A unit with extras has a key of its own,<name>[<extras>] <version>, and vendoring rewrites both:The revert's confinement check, added in #2052, compares the lock before and after the restore with the package's own entries taken out of both. It read a key's package as its first word, so
urllib3[socks]counted as another package's entry, the two sides differed, and the restore was refused.Fix
pdm_lock::files_key_packagereads a[metadata.files]key back to its package, dropping the[<extras>]suffix. It sits next tolegacy_files_key, which builds the key, so the writer and the check share one definition.drop_packageuses it forfiles/hasheskeys only. Asourceskey is read as before, and another package's extras key is still refused.Testing
revert_round_trip_restores_a_legacy_lock_with_extrasvendors and reverts urllib3 in the native PDM 0.12.3 extras lock throughwire_pdmandrevert_pdm, the path that failed. Without the fix it fails with the refusal above.confinement_allows_a_pdm_revert_in_every_native_formatruns the PDM lock writer over every native lock the rewriter takes and holds the check to accepting the revert. Without the fix it fails on0.12.3-extras.files_key_package_reads_back_every_legacy_keychecks that every key the writer builds for the PDM 0.x fixtures reads back as its unit's package.cargo test -p socket-patch-core --lib -- vendor::pypi utils::pdm_lock utils::poetry_lock vendor::common: 595 pass.cargo clippy --locked --workspace --all-features -- -D warningsandcargo fmt --checkare clean.scan --mode vendored, install, thenrollback), shapesextrasanddirect: the released 5.1.0 binary fails0.12.3 extras vendored, and a build of this branch passes all four cells.Review findings not fixed here
/code-review highfound no bug in the change. Two findings are left out:drop_packagedecides that a table is keyed by package from its parent key alone, so it also treats the inline{file, hash}tables of afiles = [...]array, and a pylockhashes = { sha256 = … }table, as keyed by package. When the vendored package is itself namedfile,hash,urlorsha256, those keys are taken out of every package's entries on both sides, and a tampered ledger record that changes another package's hash would pass the check. It needs a patch for a package with one of those names and a tampered committed ledger. Closing it changes what the check accepts, so it should be its own PR with its own tests; I read the code path but did not write a failing test.pep508_nameinstead of a new helper. It would also acceptsix@xorsix/diras six's key. The new helper accepts only whatlegacy_files_keywrites.How it was found
depscan's PDM patch backtest failed
0.12.3 extras vendoredon Linux and Windows when the submodule moved to v5.1.0 (SocketDev/depscan#30174). That bump needs this fix before its CI can pass.🤖 Generated with Claude Code