Movatterモバイル変換


[0]ホーム

URL:


Following system colour schemeSelected dark colour schemeSelected light colour scheme

Python Enhancement Proposals

PEP 807 – Index support for Trusted Publishing

Author:
William Woodruff <william at yossarian.net>
Sponsor:
Donald Stufft <donald at stufft.io>
PEP-Delegate:
Donald Stufft <donald at stufft.io>
Discussions-To:
Discourse thread
Status:
Draft
Type:
Standards Track
Topic:
Packaging
Created:
19-Sep-2025
Post-History:
08-Aug-2025,29-Sep-2025

Table of Contents

Abstract

This PEP proposes a standard mechanism through which arbitraryPython package indices can support “Trusted Publishing,” a misuse-resistantcredential exchange scheme already implemented by the Python Package Index(PyPI).

The mechanism proposed in this PEP is designed to encapsulate PyPI’sexisting implementationof Trusted Publishing, while allowing other indices to implement the samescheme in a manner that is discoverable by and interoperable with existingPython package uploading clients.

Motivation

“Trusted Publishing” is PyPI’s term of art for using theOpenID Connect (OIDC) standardto exchange a short-livedidentity credential from a trustedthird-party service (like a CI/CD or cloud provider) for a short-lived,minimally-scopedupload credential that can be used to publishto the index.

Trusted Publishing was originally designed and enabled on PyPI in 2023 asa non-standard (PyPI-specific) feature, much like the existingupload API. It has seenwidespread adoption in that capacity: over one million files have been publishedto PyPI using a Trusted Publisher (as of September 2025), representingapproximately one in every eight files uploaded to PyPI since becomingavailable. Additionally, PyPI’s design has inspired similar designs in theRust (crates.io),Ruby (RubyGems), andJavaScript (npm) ecosystems.

The absence of a standard for Trusted Publishing presents a long-termimpediment for adoption: third-party indices (i.e. those other thanPyPI and TestPyPI) cannot easily implement Trusted Publishing withoutreferencing PyPI’s unstandardized design. This in turn poses a long-termmaturity risk similar to that of the unstandardized upload API: package uploadclients (likeTwine anduv) must either accept behavioral differencesbetween indices (leading to an accretion of hacks) or continue to rejectnon-PyPI implementations of Trusted Publishing.

Rationale

The lack of an existing standard for Trusted Publishing is the primaryrationale for this PEP.

The design proposed in this PEP closely follows PyPI’s existing implementation,with an added layer ofdiscoverythat enables uploading clients to determine whether an arbitrary indexsupports Trusted Publishing without making PyPI-specific assumptions.

The rationale for this design is as follows:

  1. The existing (unstandardized) implementation of Trusted Publishign on PyPIhas a proven track record, and is already widely adopted in uploading tools.A significant deviation from the existing design would introduceunnecessary compatibility risks.
  2. The discovery mechanism proposed in this PEP is designed to beconsistent with existing standards for machine-to-machine protocols,namelyRFC 8615 (Well-Known URIs). Additionally, this discovery mechanismis designed to allow multiple indices to be hosted under a singledomain, which is a common topology for third-party index hosts.

In sum, the rationale for this PEP is to standardize PyPI’s existinginterfacesand make them discoverable while allowing index hoststhat don’t match PyPI’s topology to implement Trusted Publishing.

Specification

This PEP’s specification contains two parts:

  • Adiscovery mechanism that package upload clients can use to determinewhether an arbitrary Python package index host supports Trusted Publishing.
  • Atoken exchange mechanism that package upload clients can use toexchange an identity credential for an upload credential.

Constraints

Unless explicitly stated otherwise, the following constraintsapply to all parts of this PEP’s specification:

  • All URLsMUST havepotentially trustworthy origins.In practice, this means that all URLsMUST use thehttpsscheme, be some variant of a local loopback (localhost,127.0.0.1, etc.), or otherwise be considereda priori trustworthyin the context of the interaction (e.g. an internal network).

    Uploading clientsMUST reject any URLs that do not meet this constraint.

  • All server-supplied URLs (i.e. those in discovery responses)MUSThave the same host subcomponent as the user-provided upload URL. UploadingclientsMUST reject any URLs that do not meet this constraint.

    In practice, this means that a discovery request tohttps://upload.example.com/.well-known/pytp/{key} can onlyreturn URLs with theupload.example.com host.

  • All client requestsSHOULD have anAccept:application/vnd.pypi.pytp.v1+json header. In the absence ofanAccept header, the receiving serverMUST behave as if this headerwere present.

    Receiving serversSHOULD respond with a406NotAcceptablestatus code if any otherAccept header is present.

  • Unless otherwise specified, all error (4xx and 5xx) responses from the serverMUST use theRFC 9457 (Problem Details for HTTP APIs) format.In particular, the serverMUST use the “Problem Details JSON Object”defined inSection 3 andSHOULD usetheapplication/problem+json media type in its responses.

Trusted Publishing Discovery

All Python package uploading is currently “endpoint driven,” in the senseuploading clients (liketwine anduv) are given an upload URL (andnot merely a domain name).

For example, to upload to PyPI, uploading clients are expected to connecttohttps://upload.pypi.org/legacy/.

The discovery mechanism proposed below takes advantage of this fact toallow single domains to advertise support for multiple indices(and their corresponding upload endpoints).

The discovery mechanism is as follows:

  1. The uploading client is given an upload URL, e.g.https://upload.example.com/legacy/.
  2. The uploading client extracts thepath component of the URL,as defined inRFC 3986. If the path component is empty,the empty string should be used.

    For the above example, the path component is/legacy/.

  3. The uploading client takes the SHA2-256 hash of the path component,producing thediscovery key.

    For the above example, the discovery key is0cace9579789849db6e16d48df183951c8f17582200d84bc93c7678d6c8f78a7.[1]

  4. The uploading client constructs adiscovery URL by taking thescheme and authority components (as defined inRFC 3986)of the upload URL and appending/.well-known/pytp/and the discovery key.

    For the above example, the discovery URL ishttps://upload.example.com/.well-known/pytp/af030c06750716b1b35852298fe852b90def13dcbd012a5fe5148470f1206bfc.

  5. The uploading client performs an HTTP GET request to the discovery URL.
  6. The server responds with a200OK status code and a bodycontaining a JSON object if the index supports Trusted Publishingfor the given upload URL. The JSON objectMUST contain the followingfields:
    • audience-endpoint: a string containing the URL of the OIDCaudience endpoint to be used during token exchange.
    • token-mint-endpoint: a string containing the URL of thetoken minting endpoint to be used during token exchange.

    For the above example, a valid response body would be:

    {"audience-endpoint":"https://upload.example.com/_/oidc/audience","token-mint-endpoint":"https://upload.example.com/_/oidc/mint-token"}

If the server does not support Trusted Publishing for the givenupload URL, itMUST respond with a404NotFound status code.

ServersMAY additionally respond with any other standard HTTPerror code in the 400 or 500 range to indicate an appropriate errorcondition.

Trusted Publishing Token Exchange

Once an uploading client has performed a successfuldiscovery flow, it can proceed to performthe actual Trusted Publishing token exchange.

Token exchange occurs in three steps:

  1. The uploading client uses theaudience endpoint obtainedduring discovery to ask the index for its expected OIDC audience.
  2. The uploading client uses the expected audience to obtain anappropriately boundidentity credential from the Trusted Publishingprovider being used (i.e. the CI/CD or cloud provider that the uploadis being performed from). The details of this step are provider-specific,and are out of scope for this PEP.[2]
  3. The uploading client uses thetoken minting endpoint obtainedduring discovery to exchange the obtained identity credentialfor a short-livedupload credential that can be used to uploadto the index.

Audience Retrieval

To retrieve the expected OIDC audience, the uploading client performsan HTTP GET request to theaudience endpoint obtained duringdiscovery.

On success, the server responds with a200OK status code and a bodycontaining a JSON object with the following field:

  • audience: a string containing the expected OIDC audience.

On failure, the serverMUST respond with a standard HTTPerror code in the 400 or 500 range to indicate the appropriate error condition.

Token Minting

After the uploading client has performedaudience retrieval and obtained anidentity credential from the Trusted Publishing provider, it canproceed to mint an upload credential.

To mint an upload credential, the uploading client performsan HTTP POST request to thetoken minting endpoint obtained duringdiscovery. The payload of thePOST requestMUST be a JSON object containing the following:

  • token: a string containing the identity credentialobtained from the Trusted Publishing provider.

On success, the server responds with a200OK status code and a bodycontaining a JSON object with the following fields:

  • token: a string containing the upload credential. The formatof the upload credential is implementation-defined and index-specific.
  • expires: anoptional integer containing a Unix timestampindicating when the upload credential expires. If this field is notpresent, the uploading clientMAY assume an expiration pointof not more than 15 minutes (900 seconds) after the time oftheir request.

    The serverMUST NOT issue temporary upload credentialsthat expire in less than 15 minutes (900 seconds) or more than6 hours (21,600 seconds) from the time of the request.

    The maximum expiry time of 6 hours is chosen to match common runtime limitson popular CI/CD providers like GitHub Actions.

    The uploading clientMAY use this time (or the minimum specifiedabove) to determine when to refresh the upload credential, if needed.

On failure, the serverMUST respond with any standard HTTPerror code in the 400 or 500 range to indicate the appropriate error condition.

Security Implications

This PEP seeks to improve the security and transparency of the Python packagingecosystem by formally standardizing the Trusted Publishing flow alreadyused by PyPI.

This PEP does not identify any positive or negative security implicationsassociated with the Trusted Publishing discovery or exchange flows themselves.

Separately from the flows, Trusted Publishingitself has asecurity model on PyPIand is considered to be a more secure alternative to long-livedAPI tokens or passwords. The primary positive security implications ofTrusted Publishing are:

  • All issued upload credentials are short-lived and can be minimally scoped,limiting the “blast radius” of a compromised credential. In particular,automatic expiry means that attackers cannot mount “harvest now, use later”campaigns against packages that use Trusted Publishing.
  • Trusted Publishing conceptually links an uploaded package to the identityof the CI/CD or cloud provider that’s authorized to upload it. This linkageis implicit from the perspective of downstream consumers, but can be madeexplicit throughPEP 740 attestations or (less formally)URL verification.

Backwards Compatibility

This PEP does not change any existing behavior and is fully backwards compatiblewith existing upload clients and indices.

Existing clients that perform PyPI’s non-standard Trusted Publishingupload flow will continue to work as before, as will existing uploadsto all indices that do not implement Trusted Publishing.

How To Teach This

This PEP is aformalization of Trusted Publishing, which has alreadyseen widespread adoption in the Python packaging ecosystem. That adoptionhas been accompanied by a variety of educational resources onadopting Trusted Publishing as an end user, including:

Rejected Ideas

“Lateral” Discovery

This PEP’s discovery mechanism uses the.well-known location schemedefined inRFC 8615. This scheme is widely adopted by machine-to-machineprotocols, including OpenID Connect itself (forOpenID Connect Discovery).

An alternative idea considered was to use a “lateral” discovery mechanism,in which the uploading client would attempt discovery by constructing aadjacent path relative to the upload URL. For example, forhttps://upload.example.com/legacy/, the uploading client wouldattempt to discover Trusted Publishing support athttps://upload.example.com/legacy/pytp (or some equivalent).

The advantage of this approach is that it doesn’t require index operatorsto have control over their (sub-)domain, which the.well-known schemeexpects (as well-known URIs can only be served from the root of a domain).

However, this approach also has downsides:

  • It assumes that arbitrary indices can provide an adjacent path withoutinterfering with existing functionality, which isn’t necessarily true.For example, a given third-party implementation may already useall routes under/legacy/{*} for other purposes.
  • It’s less consistent with existing machine-to-machine protocolconventions, which overwhelmingly use the.well-known scheme. Developinga custom location scheme here would require additional informationalmaterials for server administrators and operators who are accustomedto the.well-known scheme.

“Implicit” Discovery

Another alternative idea considered was the perform “implicit” discovery,similar to what PyPI currently does for Trusted Publishing: instead of anexplicitdiscovery step, the uploading client could jumpstraight to attempting the audience and token minting steps, andhandle any errors that arise.

The advantage of this approach is simplicity: it eliminates the networkround-trip needed for the discovery step, and eliminates the indirectionof obtaining the audience and token minting endpoints from the discoveryresponse.

This approach too has downsides:

  • It implicitly limits a given domain to a single index/upload implementation,since the implicit “discovery” step on PyPI is to construct the audienceand token minting endpoints against the base domain of the upload URL.This limitation is acceptable in the context of a single index hostlike PyPI, but does not generalize to other index topologies (likeindex hosts that provide isolated private indices).
  • It relies on entirely static endpoint construction rules forthe audience and token minting endpoints, which means significant disruptionto existing clients if those endpoints ever need to change.

Footnotes

[1]
The discovery key may be computed thusly:
>>>importhashlib>>>path="/legacy/">>>key=hashlib.sha256(path.encode("utf-8")).hexdigest()>>>print(key)0cace9579789849db6e16d48df183951c8f17582200d84bc93c7678d6c8f78a7
[2]
Widely used CI/CD and cloud providers variously implement “ambient”OIDC token retrieval mechanisms that aren’t standardized.These various mechanisms are currently abstracted over byexisting components of the Python packaging ecosystem,such as theid package.

Copyright

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


Source:https://github.com/python/peps/blob/main/peps/pep-0807.rst

Last modified:2025-11-03 20:18:50 GMT


[8]ページ先頭

©2009-2025 Movatter.jp