Skip to content

Automatically replace Trusted Publishing Tokens #1249

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 8, 2025

Conversation

sigmavirus24
Copy link
Member

@sigmavirus24 sigmavirus24 commented Jun 6, 2025

Closes gh-1246

@sigmavirus24 sigmavirus24 requested review from woodruffw and Copilot June 6, 2025 02:21
Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR adds automatic renewal for short-lived PyPI tokens during long-running Trusted Publishing uploads to avoid token expiration mid-operation.

  • Introduces TOKEN_USERNAME and TOKEN_RENEWAL_THRESHOLD constants.
  • Implements caching, validation, and renewal logic in Resolver (_has_valid_cached_tp_token, _make_trusted_publishing_token, make_trusted_publishing_token).
  • Adds TrustedPublishingAuthenticator to wrap HTTP Basic Auth with token renewal.
  • Updates the changelog with feature details.

Reviewed Changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
twine/auth.py Added token renewal logic, caching, constants, and new authenticator class
changelog/1246.feature.rst Documented automatic token refresh behavior
Comments suppressed due to low confidence (3)

twine/auth.py:34

  • The comment says renewal starts after 10 minutes, but TOKEN_RENEWAL_THRESHOLD is set to 5 minutes—update the comment or the constant to keep them in sync.
#: Tokens expire after 15 minutes, let's start allowing renewal/replacement

twine/auth.py:148

  • The new token renewal and caching logic lacks explicit unit tests. Consider adding tests for _has_valid_cached_tp_token, _make_trusted_publishing_token, and fallback behaviors.
def _has_valid_cached_tp_token(self) -> bool:

changelog/1246.feature.rst:6

  • Typo: "we weill" should be "we will".
and *and* we weill

@sigmavirus24 sigmavirus24 force-pushed the feature/1246 branch 5 times, most recently from 9a32402 to f4cd53d Compare June 6, 2025 23:58
@webknjaz webknjaz moved this to 🧐 @webknjaz's review queue 📋 in 📅 Procrastinating in public Jun 7, 2025
Copy link
Member

@woodruffw woodruffw left a comment

Choose a reason for hiding this comment

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

This approach makes a lot of sense to me! I'll go ahead and put up a prospective PR for pypi/warehouse#18235 to get this moving on PyPI's side too 🙂

Edit: pypi/warehouse#18238 for the above.

@sigmavirus24 sigmavirus24 force-pushed the feature/1246 branch 2 times, most recently from 454c708 to 3b9229a Compare June 8, 2025 12:29
@sigmavirus24 sigmavirus24 changed the title WIP: Automatically replace Trusted Publishing Tokens Automatically replace Trusted Publishing Tokens Jun 8, 2025
Tokens obtained via the Trusted Publishing flow are only valid for a
short period of time. As such, projects using Trusted Publishing and
trying to upload a large number of artifacts (or potentially a large number
of large artifacts) could run out of time before the token expires.

This is a first pass at solving the problem by replacing the token when
it's within 5 minutes of expiry. This also adds optional parsing from
the Warehouse API which does not currently return the expiration
timestamp. If that's unavailable, we guesstimate the remaining validity.

Closes pypagh-1246
On Python 3.9 ``importlib_metadata`` returns Optional[PackageMetadata]
instead of PackageMetadata, this leads to mypy complaining that
Optional[...] is not indexable and does not have ``get_all``. Instead,
let's just cast it for ourselves.
@sigmavirus24 sigmavirus24 enabled auto-merge (rebase) June 8, 2025 12:41
@sigmavirus24 sigmavirus24 merged commit becf1a8 into pypa:main Jun 8, 2025
24 checks passed
@github-project-automation github-project-automation bot moved this from 🧐 @webknjaz's review queue 📋 to 🌈 Done 🦄 in 📅 Procrastinating in public Jun 8, 2025
@sigmavirus24 sigmavirus24 deleted the feature/1246 branch June 8, 2025 12:43
@miketheman
Copy link
Member

Curious - I'm not an expert on the logic here, but does this now allow for a runaway/lengthy process to basically continue swapping out new tokens indefinitely?

@woodruffw
Copy link
Member

Curious - I'm not an expert on the logic here, but does this now allow for a runaway/lengthy process to basically continue swapping out new tokens indefinitely?

In principle yes, up to the job timeout window (which IIRC is 4 or 6 hours). I think this was already true for someone who wanted to grief PyPI though, since they could do the same thing in a busy loop on a CI runner.

(And this would be less noisy than that, since the rotation is every ~10 minutes versus as often as they would want with a custom script.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Automatically refresh short-lived PyPI token in long Trusted Publishing uploads
3 participants