Skip to content

Commit 1469ee8

Browse files
committed
Add amendments to 694 for scanning in staged releases and add legacy API changes to use staged releases
1 parent 69a447a commit 1469ee8

1 file changed

Lines changed: 73 additions & 1 deletion

File tree

peps/pep-0694.rst

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
PEP: 694
22
Title: Upload 2.0 API for Python Package Indexes
3-
Author: Barry Warsaw <barry@python.org>, Donald Stufft <donald@stufft.io>, Ee Durbin <ee@python.org>
3+
Author: Barry Warsaw <barry@python.org>, Donald Stufft <donald@stufft.io>, Ee Durbin <ee@python.org>, Cary Hawkins <hawkinscary23@gmail.com>
44
PEP-Delegate: Dustin Ingram <di@python.org>
55
Discussions-To: https://discuss.python.org/t/pep-694-pypi-upload-api-2-0-round-2/101483
66
Status: Draft
@@ -29,6 +29,9 @@ Along with standardization, the upload API provides additional useful features s
2929
* "staging" a release, which can be used to test uploads before publicly publishing them,
3030
without the need for `test.pypi.org <https://test.pypi.org/>`__;
3131

32+
* entering the publishing session workflow from the existing legacy upload API, so that staging is
33+
available to publishers before their tooling adopts this API;
34+
3235
* artifacts which can be overwritten and replaced, until a session is published;
3336

3437
* detailed status on the state of artifact uploads;
@@ -285,6 +288,14 @@ The unguessable :ref:`stage preview URL <staged-preview>` is a separate capabili
285288
governed by this authorization check; it grants read-only preview access to any client that holds the token,
286289
so that (for example) a CI job can install-test a staged release without project upload credentials.
287290

291+
As one such stricter policy, an index **MAY** require *additional* authorization, beyond upload permission, to
292+
:ref:`publish <publishing-session-completion>` or :ref:`cancel <publishing-session-cancellation>` a session,
293+
while still allowing session creation and file upload with upload permission alone. This lets a publisher
294+
separate duties: an automated system can be given a credential that can create a session and upload files to
295+
it but cannot publish it, while the authorization to publish is held elsewhere, so that compromise of the
296+
automated system alone does not result in a published release. How such an additional authorization is
297+
expressed, and whether it is offered at all, is determined by the index operator.
298+
288299

289300
.. _session-errors:
290301

@@ -743,6 +754,20 @@ change: deferred processing resolves to either ``published`` on success or ``err
743754
resolves to ``error``, the session remains editable and the reason is reported in the session's ``notices``,
744755
as described in :ref:`publishing-session-states`.
745756

757+
The ``processing`` state **MAY** be used to run asynchronous review of a session's files before it is
758+
published, such as malware scanning. If the review completes without an adverse result, the session resolves
759+
to ``published`` as normal. If the review does not complete within a period chosen by the index, the server
760+
**MAY** treat it as though it had completed without an adverse result and publish the session, so that a
761+
backlogged or unavailable review system does not indefinitely prevent publication. If the review produces an
762+
adverse result, the session resolves to ``error`` with the reason reported in the session's ``notices``; the
763+
server **MAY** decline to publish such a session on any subsequent retry, in which case it is eventually
764+
:ref:`canceled <publishing-session-cancellation>` and its data discarded. Where a session has resolved to
765+
``error`` because of an adverse result, an index **MAY** provide a way for the publisher to request that the
766+
result be re-examined. Such a re-examination **SHOULD** be performed by a human, to confirm whether the
767+
adverse result was a false positive; if it was, the index **SHOULD** allow the session to be published. The
768+
review itself, including which checks run, how long they are allowed to take, and how such requests are
769+
handled, is determined by the index operator and is out of scope for this specification.
770+
746771
A publish attempt that fails *synchronously* (i.e. within the publish request itself) is returned to the
747772
client as an :ref:`error response <session-errors>` and leaves the session in its current editable state; it
748773
does **not** move the session to ``error``.
@@ -1348,6 +1373,42 @@ changes to the installer tool required.
13481373
The details of this user experience are left to installer tool maintainers.
13491374

13501375

1376+
.. _legacy-interop:
1377+
1378+
Legacy Upload API Interoperability
1379+
----------------------------------
1380+
1381+
Publishers cannot use the features of this API until their upload tooling adopts it, and the legacy API is
1382+
expected to remain available for a long time. To make staging available to those publishers sooner, an index
1383+
**MAY** allow a legacy upload to create a publishing session, so that everything from session creation onward
1384+
happens exactly as described in this PEP.
1385+
1386+
An index that supports this **MUST** document it, and **SHOULD** accept a ``staged`` field with the value
1387+
``true`` in the legacy ``multipart/form-data`` upload request. When that field is present, the index creates a
1388+
publishing session in the ``open`` state for the uploaded file's project and version, adds the file to it as a
1389+
:ref:`completed <file-upload-session-states>` file upload, and does not publish it. The index **SHOULD**
1390+
return the :ref:`publishing session creation response body <publishing-session-response>` from that upload,
1391+
including the ``links`` and ``session-token`` keys, so that the publisher can then use the endpoints in this
1392+
PEP to :ref:`preview <staged-preview>`, :ref:`publish <publishing-session-completion>`, or :ref:`cancel
1393+
<publishing-session-cancellation>` the session. An index **MAY** also create a session for an upload based on
1394+
its own policy or the project's configuration, without the field being present; this allows a project to
1395+
require that its releases are staged in a way that an upload client cannot bypass.
1396+
1397+
Because the legacy API uploads a single file per request, subsequent legacy uploads for the same project and
1398+
version **SHOULD** be added to the same open session, so that the release is still published as a unit.
1399+
1400+
A legacy client that is unaware of this PEP cannot issue a :ref:`publish request
1401+
<publishing-session-completion>`. Where an index has created a session on such a client's behalf, and the
1402+
session is subject only to automated processing, the index **MAY** publish the session itself once that
1403+
processing resolves without an adverse result, or once the period allowed for it elapses (see
1404+
:ref:`publishing-session-completion`). An index **MUST NOT** publish a session this way if the publisher has
1405+
configured the project to require a separate publishing authorization (see :ref:`authentication`).
1406+
1407+
Aside from how the session is created, this section changes no part of this API: the :ref:`state machine
1408+
<publishing-session-states>`, the status endpoints, stage previews, and the publish and cancel actions are the
1409+
same whether the session was created through this API or through a legacy upload.
1410+
1411+
13511412
.. _file-upload-mechanisms:
13521413

13531414
File Upload Mechanisms
@@ -1847,6 +1908,17 @@ as experience is gained operating Upload 2.0.
18471908
Change History
18481909
==============
18491910

1911+
* `01-Aug-2026 <https://discuss.python.org/t/pre-pep-staged-releases-separated-from-pep-694/107804/58>`__
1912+
1913+
* Add :ref:`Legacy Upload API Interoperability <legacy-interop>`, allowing a legacy upload to create a
1914+
publishing session (via a ``staged`` field, or by index or project configuration that an upload client
1915+
cannot bypass) so that staging is usable before upload tooling adopts this API, and allowing an index to
1916+
publish such a session itself once automated processing resolves or its window elapses.
1917+
* Note that the ``processing`` state **MAY** be used for asynchronous review such as malware scanning, with
1918+
an index-chosen window after which the review is treated as having produced no adverse result.
1919+
* Allow an index to require additional authorization, beyond upload permission, to publish or cancel a
1920+
session, so that duties can be separated.
1921+
18501922
* `29-Jul-2026 <https://discuss.python.org/t/pep-694-pypi-upload-api-2-0-round-4/108320>`__
18511923

18521924
* Add an **Atomic Publication and Conflicts** section. Specify that publication is atomic with respect to

0 commit comments

Comments
 (0)