Repository navigation
feat: releases ship with PEP 740 attestations - #24
Merged
Merged
Conversation
uv publish uploads attestations it is given but does not create them, so no release in the org had provenance on PyPI, although the publish job already holds the OIDC token Sigstore signs with. The publish job now runs pypi-attestations sign over the built wheel and sdist before uploading. It writes <file>.publish.attestation next to each, and uv publish, with its default dist/* file set, sends them along. PyPI verifies each attestation against the Trusted Publisher and rejects the upload if one does not match, so a broken signature fails the release instead of shipping without provenance. Closes #13
AlexeyShalaev
force-pushed
the
fix/13-attestations
branch
from
October 16, 2026 14:54
29ffb11 to
d853683
Compare
Member
Author
|
Signing probe result. The workflow was temporary and has been force-pushed away; the branch is back to d853683. Run https://github.com/bedrock-python/python-library-template/actions/runs/38919502263. It rendered the template, ran
Ambient OIDC detection works on a hosted runner with |
This was referenced Oct 17, 2026
Merged
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The problem
uv publishuploads PEP 740 attestations it is given, but it does not create them. So no release in the org has provenance on PyPI (the integrity API returns 404 for idempotency-kit 0.4.1, clientwright 0.5.0, deadline-budget 0.1.3, pg-partsmith 1.8.0), even though the publish job already holds the OIDC token Sigstore signs with.The decision
Keep
uv publishand sign before it:pypi-attestations signuses the ambient GitHub OIDC credential (sigstore.oidc.detect_credential()comes before any interactive flow) and writes<file>.publish.attestationnext to each distribution. This needs no new permission: the job already hasid-token: write. PyPI checks every attestation against the Trusted Publisher and rejects the upload if one does not match, so a broken signature fails the release. It does not ship without provenance.I found one trap while testing, and the workflow comment now records it.
uv publishattaches only attestation files that are in its own file set. The template calls it with no file arguments, and the defaultdist/*includes the.attestationfiles. Someone who changes that touv publish dist/*.whl dist/*.tar.gzwould upload the distributions without their attestations, with no error.Rejected:
pypa/gh-action-pypi-publish, which creates attestations by default. It would swap the uploader and--check-urlfor a container action andskip-existingto get this one feature, and the signing step gets the feature without that.Evidence
A stand-in upload endpoint that records the form fields of each upload, for the distributions of a render of this branch. The attestation content was taken from PyPI's own provenance for
pypi-attestations0.0.30, because uv does not check the signature and PyPI does:Signing needs a GitHub OIDC token, so I can't run it locally. I ran it on this PR with a temporary workflow that renders the template, builds, runs the generated sign step as written, and verifies the result against the workflow identity. The workflow was removed afterwards; the result is in the comment below.
actionlintwith shellcheck is clean on the generated workflows. The generated gate is green.After the first release with this change, check with the
curlfrom #13:/integrity/<project>/<version>/<file>/provenanceshould return 200.Closes #13