From 87662b82de4d2857bf433b2986f6828ec4d53114 Mon Sep 17 00:00:00 2001 From: Sviatoslav Sydorenko Date: Wed, 20 Nov 2024 14:55:06 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=94=8F=F0=9F=93=A6=20Sign=20distribution?= =?UTF-8?q?=20packages=20on=20release?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch integrates an invocation of the `pypi-attestations` tool[[1]] into the release automation before calling Twine. When used locally and not within a known Trusted Publishing setup, it will invoke an OAuth flow, opening a browser window, prompting the caller to authenticate via GitHub. Once authorized and browser window closed, it will proceed to signing the distribution packages[[2]] locally using Sigstore. The resulting signatures are produced in the format outlined in PEP 740 [[3]]. Twine is then called with `--attestations` which is what will actually attach the digital signatures to the release on PyPI. [1]: https://docs.pypi.org/attestations/producing-attestations/#using-pypi-attestations [2]: https://packaging.python.org/en/latest/glossary/#term-Distribution-Package [3]: https://peps.python.org/pep-0740/ --- packaging/release.py | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/packaging/release.py b/packaging/release.py index 8ca0fabe4cf..cf4b5fbb90c 100755 --- a/packaging/release.py +++ b/packaging/release.py @@ -668,6 +668,7 @@ def ensure_venv() -> dict[str, t.Any]: ansible_requirements = ANSIBLE_REQUIREMENTS_FILE.read_text() release_requirements = """ +pypi-attestations # https://docs.pypi.org/attestations/producing-attestations/#using-pypi-attestations build twine """ @@ -1460,7 +1461,32 @@ def publish(repository: str, prompt: bool = True) -> None: display.show("") raise ApplicationError("Publishing was aborted by the user.") from None - run("twine", "upload", "-r", repository, sdist_file, wheel_file, env=env, cwd=CHECKOUT_DIR) + run( + # NOTE: This initializes the OAuth flow and will use the + # NOTE: GitHub-provided OIDC identity to sign. + # Ref: https://docs.pypi.org/attestations/producing-attestations/#using-pypi-attestations + "python", + "-Im", "pypi_attestations", + "sign", + sdist_file, + wheel_file, + capture_output=True, + cwd=CHECKOUT_DIR, + env=env, + ) + run( + "twine", "upload", + "--attestations", + "--disable-progress-bar", + "-r", repository, + sdist_file, + sdist_file.with_suffix(f"{sdist_file.suffix}.publish.attestation"), + wheel_file, + wheel_file.with_suffix(f"{wheel_file.suffix}.publish.attestation"), + capture_output=True, + cwd=CHECKOUT_DIR, + env=env, + ) @command