Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
a0e70bf
Rewrite the security bits per feedback
mgorny Jan 29, 2026
fcf92f6
Add "opt-in" to rejected ideas
mgorny Jan 29, 2026
6dd38d3
Update peps/pep-0817.rst
mgorny Jan 30, 2026
46428fd
Update peps/pep-0817.rst
mgorny Jan 30, 2026
440f682
Address @konstin's comments
mgorny Jan 30, 2026
a622aff
Rename "rationale" into "overview and rationale"
mgorny Jan 30, 2026
086f43f
Try to initially explain the install steps
mgorny Jan 30, 2026
e176655
Mention caching for `get_supported_variants()`
mgorny Jan 30, 2026
e338115
Propose some index restrictions wrt JSON files
mgorny Jan 30, 2026
4049fc4
Clarify that user information can be used instead of IT providers
mgorny Feb 2, 2026
8d81b07
Clarify installer outline further
mgorny Feb 2, 2026
748c6b2
Add an outline for installing a local wheel as well
mgorny Feb 2, 2026
e74d68f
Add clarifications for isolated environment usage
mgorny Feb 2, 2026
3b155d3
Include outline for building a variant wheel
mgorny Feb 2, 2026
18d55e3
Add an outline for index behavior
mgorny Feb 2, 2026
0281843
Add a missing Copyright section
mgorny Feb 3, 2026
2185a4d
Add a change history
mgorny Feb 3, 2026
e5318ca
Update the GROMACS plot to respect dark theme
mgorny Feb 3, 2026
e7b0cbf
Update peps/pep-0817.rst
mgorny Feb 5, 2026
8252da9
Update peps/pep-0817.rst
mgorny Feb 5, 2026
ed443f2
Address review comments
mgorny Feb 5, 2026
782a088
Add the conceptual install diagram
mgorny Feb 5, 2026
6af46cf
Start working on dark mode for the conceptual diagram
mgorny Feb 5, 2026
1da3fb2
Link the diagram
mgorny Feb 5, 2026
6c7d2c5
Adjust the diagram for dark mode
mgorny Feb 5, 2026
70ecf22
Update peps/pep-0817.rst
mgorny Feb 6, 2026
04bb5d3
Update peps/pep-0817.rst
mgorny Feb 6, 2026
8e857a6
Update peps/pep-0817.rst
mgorny Feb 6, 2026
64b31b7
Address other review comments
mgorny Feb 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
280 changes: 254 additions & 26 deletions peps/pep-0817.rst
Original file line number Diff line number Diff line change
Expand Up @@ -675,8 +675,8 @@ are used in conjunction with USE flags. For example,
build against.


Rationale
=========
Overview and rationale
======================

Wheel variant glossary
----------------------
Expand Down Expand Up @@ -752,7 +752,7 @@ wheel maintainer or queried at wheel build time from an AoT plugin.

Both kinds of plugins are usually implemented as Python packages which
implement the `provider plugin API`_, but they may also be vendored or
reimplemented by installers to improve security, as outlined in
reimplemented by installers to improve user experience, as outlined in
`Providers`_. Plugin packages may be installed in isolated or
non-isolated environments. In particular, all plugins may be returned by
the ``get_requires_for_build_wheel()`` hook of a :pep:`517` backend, and
Expand Down Expand Up @@ -1055,6 +1055,140 @@ optional. This implies that any packages using it need to provide
non-variant wheels as well.


Suggested implementation logic per type of packaging tool
---------------------------------------------------------

Installing a package from an index
''''''''''''''''''''''''''''''''''

.. figure:: pep-0817/conceptual_diagram_installers.svg
:target: _images/conceptual_diagram_installers.svg
:alt: TODO.

A conceptual diagram of installing a wheel.

When asked to install a version of a package from an index, the proposed
behavior would be to:

1. Query the remote index for the package in question.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
1. Query the remote index for the package in question.
1. **[Unchanged]** Query the remote index for the package in question.

I think it's nice to provide - here no modification, etc.

2. Initially select a package version meeting the version constraints,
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
2. Initially select a package version meeting the version constraints,
2. **[Unchanged]** Resolve the package version meeting the version constraints,

I would replace by smthg along the line of "resolve the package exactly as normal - no change expected".

  • use the word: resolve
  • state very loudly & clearly => variant has no impact on package version resolution

as usual (this does not need to take variant metadata into account).
3. Filter available wheels based on Platform Compatibility Tags.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
3. Filter available wheels based on Platform Compatibility Tags.
3. **[Unchanged]** Filter available wheels (for resolved version) based on Platform Compatibility Tags.

Copy link

Choose a reason for hiding this comment

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

PEPs use bold text sparingly, if at all - We need to follow the PEP style of writing!

4. Determine if any of the remaining wheels are variant wheels.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
4. Determine if any of the remaining wheels are variant wheels.
4. **[New Variant Step]** Determine if any of the remaining wheels are variant wheels.

If not, proceed as with non-variant wheels.
Copy link
Member

Choose a reason for hiding this comment

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

There should be a If not, proceed as with non-variant wheels and JUMP TO STEP XYZ

Copy link

Choose a reason for hiding this comment

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

That's an exit branch, the procedure for non-variant wheels is already well-known to the reader, it's well-documented in the existing specs and implemented by a number of tools.

5. If any wheels feature variant labels, download the index-level
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
5. If any wheels feature variant labels, download the index-level
5. **[New Variant Step]** If any wheels feature variant labels, download the index-level

variant metadata file, ``{name}-{version}-variants.json``. If this
file is missing, assume all variant wheels are incompatible and
proceed as with non-variant wheels.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
proceed as with non-variant wheels.
proceed as with non-variant wheels and jump to **step 10**.

6. Map the variant labels into sets of variant properties using the
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
6. Map the variant labels into sets of variant properties using the
6. **[New Variant Step]** Map the variant labels into sets of variant properties using the

index-level variant metadata file. If any of the labels present in
wheel filenames are missing in the file, assume that the respective
wheels are incompatible.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
wheels are incompatible.
wheels are incompatible. **We encourage installers to adopt `variantlib` that provides a reference implementation of this step.**

7. Obtain the ordered lists of supported variant properties using
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
7. Obtain the ordered lists of supported variant properties using
7. **[New Variant Step]** Obtain the ordered lists of supported variant properties using

providers specified in the index-level variant metadata file:
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
providers specified in the index-level variant metadata file:
providers specified in the index-level variant metadata file. **We encourage installers to adopt `variantlib` that provides a reference implementation of this step.**:


- for the enabled AoT providers, obtain them from static property
data in the index-level variant metadata file.
- for the enabled install-time providers:

- if the user provided static compatibility information, use that.
- otherwise, if the provider is vendored or reimplemented, query it
in implementation-specific manner.
- otherwise, if the Python provider package is considered secure
(either by the installer or via explicit user opt-in), install it
in an isolated environment, and query it via the plugin API.
- if none of the above applies, do not run the provider and either
consider the variant properties incompatible, or fail the
installation.

- for the disabled providers (e.g. opt-in providers that were not
enabled by the user, providers excluded via environment markers),
assume that all variant properties in the namespace are
incompatible.

8. Filter and order variants based on the lists of supported properties,
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
8. Filter and order variants based on the lists of supported properties,
8. **[New Variant Step]** Filter and order variants based on the lists of supported properties,

and select the most preferred variant. If no variant wheel matched,
use the non-variant wheels by their rules.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
use the non-variant wheels by their rules.
use the non-variant wheels by their rules. **We encourage installers to adopt `variantlib` that provides a reference implementation of this step.**

9. If multiple wheels for a given version share the same variant label,
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
9. If multiple wheels for a given version share the same variant label,
9. **[New Variant Step]** If multiple wheels for a given version share the same variant label,

order them by Platform compatibility tags and build number, and
select the best wheel.

Copy link
Member

Choose a reason for hiding this comment

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

  1. [Unchanged] Proceed with installation of the best matching and selected wheel (variant or not).


Installing a local wheel
''''''''''''''''''''''''

When asked to install a local wheel file, the proposed behavior would be
to:

1. If no variant label is present in the filename, proceed as with
non-variant wheels.
2. Verify the wheel compatibility via Platform compatibility tags.
3. Read variant metadata from ``*.dist-info/variant.json`` inside the
Copy link
Member

Choose a reason for hiding this comment

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

Important !

I think it's a bad idea honestly - I'm with you that "this should be ideal". However ... People will massively object.

If someone elects to manually install ABC => just give it to them as long as the platform tags are valid. If they make a mistake it's on them.

It's breaking a core assumption of the installer that if I'm doing pip install package.whl now I have to install a provider first ... And this will be VERY difficult to win ... Let's just drop this...

You ask A => You get A. If you mess up, that's on you

Copy link

Choose a reason for hiding this comment

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

This is a tool decision, this overview list show the behavior of how tools act today already and is the default that at least uv will implement (we will reject non-matching variants by default).

$ pip install numpy-2.4.2-pp311-pypy311_pp73-win_amd64.whl
ERROR: numpy-2.4.2-pp311-pypy311_pp73-win_amd64.whl is not a supported wheel on this platform.
$ uv pip install numpy-2.4.2-pp311-pypy311_pp73-win_amd64.whl
  × No solution found when resolving dependencies:
  ╰─▶ Because only numpy==2.4.2 is available and numpy==2.4.2 has no wheels with a matching Python version tag
      (e.g., `cp314`), we can conclude that all versions of numpy cannot be used.
      And because you require numpy, we can conclude that your requirements are unsatisfiable.

wheel file.
4. Obtain the ordered lists of supported variant properties, as when
`installing a package from an index`_.
5. Verify the wheel compatibility via supported properties.


Building a variant wheel
''''''''''''''''''''''''

In order to build a variant wheel, the build backend needs to receive a
list of variant properties and a variant label. The recommended way to
do that is to use backend-defined keys in the ``config_settings``
dictionary passed to the build backend hooks.

When building a variant wheel, the proposed behavior for the build
backend would be to:

1. Read variant provider metadata from ``pyproject.toml``.
2. Verify that all namespaces specified in the user-defined variant
properties have a corresponding provider in the metadata.
3. In the ``get_requires_for_build_wheel()`` hook, return variant
provider plugin packages along with other build dependencies.
4. In the ``build_wheel()`` hook, query the provider plugins
``get_all_configs()`` function to obtain all valid property keys and
values. Use it to verify that the specified properties are correct.
5. Convert the variant metadata from ``pyproject.toml`` to JSON, append
the mapping from variant label to variant properties and write the
result into the wheel's ``*.dist-info/variant.json`` file.
6. Build the wheel as usual, except for including the
``*.dist-info/variant.json`` and the variant label in the filename.


Publishing variant wheels on an index
'''''''''''''''''''''''''''''''''''''

Variant wheels are uploaded to an index just like regular wheels.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
Variant wheels are uploaded to an index just like regular wheels.
**Variant wheels are uploaded to an index just like regular wheels.**

Added line break is intentional

There are two possible approaches to publishing the index-level
``{name}-{version}-variants.json`` file for every package version:
it can either be prepared and uploaded by the user, or it can be
generated automatically by the index.

The file should not be changed once it is published, as clients may have
already cached it or locked to the existing hash. For this reason, if
the index is responsible for generating the file, it should use some
mechanism to defer publishing it until the release is fully uploaded
(for example, :pep:`694`).

To generate the ``{name}-{version}-variants.json`` file:

1. For the first variant wheel for a given package version, copy the
data from its ``*.dist-info/variant.json`` file.
2. For subsequent wheels, merge the data from their
Copy link
Member

Choose a reason for hiding this comment

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

Add that variantlib exposes all the tooling to do this step in one API call.

``*.dist-info/variant.json`` files into the existing data:

- disjoint keys of ``providers``, ``static-properties`` and
``variants`` dictionaries are merge together
- common keys of these dictionaries must have exactly the same value
- ``default-priorities.namespace`` list can be replaced if the new
value starts with the old value
- ``default-priorities.feature`` and ``default-priorities.value``
keys can be added if they were not present in the previous
``default-priorities.namespace`` value
- other keys must have exactly the same value


Example use cases
-----------------

Expand Down Expand Up @@ -1207,14 +1341,20 @@ without explicit user consent.

The `Providers`_ section of the specification provides further
suggestions that aim to improve both security and the user experience.
It is expected that a limited subset of popular provider plugins will
be either vendored by the installer, eliminating the use of packages
external to the tool altogether, or pinned to specific versions,
providing the same level of code auditing as the tools themselves.
Particularly, it is expected that the most popular provider plugins will
be available out of the box, and a dedicated team of maintainers
(initially including a subset of the PEP authors) will be responsible
for inspecting them for security risks and vetting the plugins as safe
to use. Installers will be able to either use a published allowlist,
vendor specific provider plugin versions, reimplement them or use them
as a Python library at their leisure.

This will lead to the majority of packages focusing on these specific
plugins. External plugins requiring explicit opt-in should be rare,
minimizing the workflow disruption and reducing the risk that users
blanket-allow all plugins.
plugins, rather than implementing competing solutions. Plugins requiring
explicit opt-in should be rare, and primarily affect expert users. This
is important to make variant usage secure-by-default. Furthermore, the
frequent disruption of workflows incentivises users to blanket-allow all
plugins (security fatigue).

Furthermore, the specification permits using static configuration as
input to skip running plugins altogether.
Expand Down Expand Up @@ -1336,16 +1476,19 @@ Providers
---------

When installing or resolving variant wheels, installers SHOULD query the
variant provider to verify whether a given wheel's properties are
variant providers to verify whether a given wheel's properties are
compatible with the system and to select the best variant through
`variant ordering`_. However, they MAY provide an option to omit the
verification and install a specified variant explicitly.

Providers can be marked as install-time or ahead-of-time. For
install-time providers, installers MUST use the provider package or an
equivalent reimplementation to query variant property compatibility. For
ahead-of-time providers, they MUST use the static metadata embedded in
the wheel instead.
install-time providers, installers MUST either query the provider for
variant property compatibility, or use user-provided compatibility
information. Installers MAY vendor or reimplement specific providers.
The format of user-provided information is left implementation-defined.

For ahead-of-time providers, they MUST use the static metadata embedded
in the wheel instead.

Providers can be marked as optional. If a provider is marked optional,
then the installer MUST NOT query said provider by default, and instead
Expand All @@ -1360,20 +1503,18 @@ markers do not match, and instead assume that their properties are
incompatible.

All the tools that need to query variant providers and are run in a
security-sensitive context, MUST NOT install or run code from any
untrusted package for variant resolution without explicit user opt-in.
security-sensitive context, MUST NOT install or run provider packages,
unless they can determine the particular provider package version to be
trusted. The exact mechanism used to do that is implementation-specific.
However, installers SHOULD ensure that the most commonly used providers
can be securely used without an explicit user opt-in.

When installing provider packages, tools SHOULD use an isolated virtual
environment.

Install-time provider packages SHOULD take measures to guard against
supply chain attacks, for example by vendoring all dependencies.

It is RECOMMENDED that said tools vendor, reimplement or lock the most
commonly used plugins to specific wheels. For plugins and their
dependencies that are neither reimplemented, vendored nor otherwise
vetted, a trust-on-first-use mechanism for every version is RECOMMENDED.
In interactive sessions, the tool can explicitly ask the user for
approval. In non-interactive sessions, the approval can be given using
command-line interface options. It is important that the user is
informed of the risk before giving such an approval.

For a consistent experience between tools, variant wheels SHOULD be
supported by default. Tools MAY provide an option to only use
non-variant wheels.
Expand Down Expand Up @@ -1721,6 +1862,16 @@ in the file, though careful merging is possible, as long as no
conflicting information is introduced, and the resolution results within
a subset of variants do not change.

The index MAY generate the index level variant metadata file
automatically from uploaded wheel metadata. If that is the case, the
file SHOULD NOT be published until it is final, and once published, it
SHOULD NOT change, as clients MAY cache it.

If the file is not generated automatically, the index MUST permit
package maintainers to upload it. Once the variant level metadata file
is uploaded, the package maintainers SHOULD NOT upload new variants for
the version in question.

The ``foo-1.2.3-variants.json`` corresponding to the package with two
wheel variants, one of them listed in the previous example, would look
like:
Expand Down Expand Up @@ -1989,6 +2140,9 @@ packages MUST be provided for plugins. However, as noted in the
needing them. In the latter case, the resulting reimplementation does
not need to follow the API defined in this section.

Plugin packages may be run in an isolated environment. They MUST NOT
make decisions based on installed packages.

A plugin implemented as Python package exposes two kinds of objects at a
specified API endpoint:

Expand Down Expand Up @@ -2164,6 +2318,9 @@ The value returned by ``get_supported_configs()`` MUST be a subset of
the feature names and values returned by ``get_all_configs()`` (modulo
ordering).

The value returned by ``get_supported_configs()`` MAY be cached
throughout multiple packages in a single install session.


Example implementation
''''''''''''''''''''''
Expand Down Expand Up @@ -2506,6 +2663,42 @@ uses.
Rejected ideas
==============

Variants being entirely or transitionally opt-in
------------------------------------------------

In discussing the security concerns, proposals were made to make variant
provider usage entirely opt-in, either permanently, or at least
initially to facilitate further testing. While such approaches may
alter who takes responsibility of vetting the provider code, and hence the maintenance
effort or number of packages/maintainers that need to be trusted,
they are not suitable as long-term solutions.

Most importantly, the opt-in mechanism would lead to far worse user
experience out-of-the-box. For variant-enabled packages, the default
experience would be installing a suboptimal or outright broken variant.
It should be noted that variant-enabled packages may not only be
installed directly, but also as dependencies of other packages.
Therefore, for optimal user experience, all packages that are
variant-enabled or that feature dependencies that are variant-enabled,
would have to document appropriate installer-specific mechanisms for
enabling the respective provider plugins.

The proliferation of this experience could have two significant
outcomes. The inability to make variants work out of the box for users
could lead to package maintainers refraining from using them, and
instead sticking to the earlier workarounds. What's even worse, it could
also lead to users eventually naively configuring their installers
to enable all variant providers unconditionally, effectively rendering
the provider usage opt-out for a large number of users, enabling all
kinds of supply chain attacks described in the `security implications`_
section.

The authors would like to emphasize that security cannot be achieved at
the cost of severely impaired user experience. Instead, the PEP attempts
to strike a balance by introducing a centrally maintained and vetted
pool of trusted providers.


An approach without provider plugins
------------------------------------

Expand Down Expand Up @@ -2605,3 +2798,38 @@ Emma Smith, Geoffrey Thomas, Henry Schreiner, Jeff Daily, Jeremy Tanner,
Jithun Nair, Keith Kraus, Leo Fang, Mike McCarty, Nikita Shulga,
Paul Ganssle, Philip Hyunsu Cho, Robert Maynard, Vyas Ramasubramani,
and Zanie Blue.


Change history
==============

- TBD
Copy link

Choose a reason for hiding this comment

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

still a TBD here

Copy link
Author

Choose a reason for hiding this comment

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

A date is supposed to go there.


- Added high-level outlines of suggested implementation logic per type of packaging tool, and a diagram for installer behavior.
- Deemphasized vendoring providers in installers. While it is still
permitted as an implementation choice, it is not presented as the
recommended solution to improve security anymore.
- Made a centrally maintained allowlist the primary solution for
enabling providers by default. Such an allowlist would be maintained
by a dedicated team, starting with a subset of the PEP authors.
- Clarified the specification to permit using user-provided
compatibility information in place of provider queries.
- Removed unnecessary UX suggestions regarding the opt-in mechanism.
- Clarified that the index level variant metadata file can be
generated by the index itself, or uploaded by the package maintainer
if index does not support that.
- Added a recommendation that no new variants are introduced once the
index level variant metadata file is published.
- Added an explicit recommendation that variant provider packages are
run in an isolated environment.
- Clarified that the value returned by ``get_supported_configs()`` may
be cached.
- Emphasized the risks of a full scale opt-in approach.
- Updated the GROMACS plot to respect dark theme.


Copyright
=========

This document is placed in the public domain or under the
CC0-1.0-Universal license, whichever is more permissive.
Loading
Loading