Skip to content

Reconcile PEP 658 sidecar metadata with the downloaded wheel#13991

Open
dewankpant wants to merge 1 commit into
pypa:mainfrom
dewankpant:reconcile-pep658-sidecar-with-wheel-metadata
Open

Reconcile PEP 658 sidecar metadata with the downloaded wheel#13991
dewankpant wants to merge 1 commit into
pypa:mainfrom
dewankpant:reconcile-pep658-sidecar-with-wheel-metadata

Conversation

@dewankpant
Copy link
Copy Markdown

Refs #13983.

Summary

This adds a post-download consistency check between PEP 658 sidecar metadata and the embedded METADATA of the downloaded wheel.

PEP 658 metadata can be used by pip during dependency resolution before the wheel itself is downloaded. Once the wheel is available locally, pip now checks that the resolver-affecting fields from the sidecar-derived distribution match the canonical metadata embedded in the wheel. If Requires-Dist, Requires-Python, or Provides-Extra differ, pip raises MetadataInconsistent and aborts the install. If either side contains an unparseable Requires-Dist entry, pip raises MetadataInvalid, matching the existing metadata validation pattern.

This is the hardening improvement discussed in #13983. It does not change pip's threat model, but it does enforce the expectation that PEP 658 metadata used for resolution remains consistent with the downloaded artifact's canonical metadata.

Scope

  • Add _canonicalize_requirement and _reconcile_metadata_against_wheel helpers in src/pip/_internal/operations/prepare.py.
  • Invoke the reconciliation after the downloaded wheel has been prepared, gated on the link being a wheel, a sidecar distribution being stored on the requirement, and the link advertising a PEP 658 metadata_link.
  • Adjust the existing FakePackage test fixture to emit one metadata header per Requires-Dist / Provides-Extra entry.
  • Update fixtures so existing positive-path tests remain valid under the new reconciliation.
  • Add unit tests for Requires-Dist, Requires-Python, Provides-Extra, canonicalization tolerance, and invalid requirement metadata.
  • Add one functional test covering the end-to-end Requires-Dist mismatch path using the existing download_local_html_index fixture.
  • Add a news fragment.

Test plan

  • pre-commit run on all touched files: all hooks green.
  • pytest tests/unit/test_operations_prepare.py -q --no-cov: 10 passed.
  • pytest tests/functional/test_download.py -k "metadata or canonicalizes or mismatch" -q --no-cov: 15 passed.
  • Manual end-to-end smoke test with a local PEP 658-style index where the sidecar declares a Requires-Dist entry not present in the wheel metadata. Patched pip rejects the install with has inconsistent Requires-Dist.

I also ran the broader functional matrix:

pytest tests/functional/test_download.py tests/functional/test_install.py tests/functional/test_new_resolver.py -q --no-cov -p no:cacheprovider

This produced 321 passed, 2 failed, 5 skipped, 1 xfailed, 2 xpassed.

The two failed cases were:

  • tests/functional/test_install.py::test_pep518_with_user_pip
  • tests/functional/test_install.py::test_install_existing_memory_distribution

I reproduced both of the above on a clean origin/main worktree at f7bfe280f, so they are unrelated to this PR's PEP 658 metadata reconciliation path.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant