Merge PRs #174 #175 and #172 into unstable/v1

This commit is contained in:
Sviatoslav Sydorenko 2023-08-10 18:57:00 +02:00
commit ade57f54dc
No known key found for this signature in database
GPG key ID: 9345E8FEA89CA455
3 changed files with 61 additions and 12 deletions

View file

@ -25,7 +25,8 @@ tag, or opt-in to [use a full Git commit SHA] and Dependabot.
### Trusted publishing
> **NOTE**: Trusted publishing is sometimes referred to by its
> [!NOTE]
> Trusted publishing is sometimes referred to by its
> underlying technology -- OpenID Connect, or OIDC for short.
> If you see references to "OIDC publishing" in the context of PyPI,
> this is what they're referring to.
@ -61,10 +62,11 @@ jobs:
uses: pypa/gh-action-pypi-publish@release/v1
```
> **Pro tip**: instead of using branch pointers, like `unstable/v1`, pin
versions of Actions that you use to tagged versions or sha1 commit identifiers.
This will make your workflows more secure and better reproducible, saving you
from sudden and unpleasant surprises.
> [!NOTE]
> Pro tip: instead of using branch pointers, like `unstable/v1`, pin versions of
> Actions that you use to tagged versions or sha1 commit identifiers.
> This will make your workflows more secure and better reproducible, saving you
> from sudden and unpleasant surprises.
Other indices that support trusted publishing can also be used, like TestPyPI:
@ -76,7 +78,8 @@ Other indices that support trusted publishing can also be used, like TestPyPI:
```
_(don't forget to update the environment name to `testpypi` or similar!)_
> **Pro tip**: only set the `id-token: write` permission in the job that does
> [!NOTE]
> Pro tip: only set the `id-token: write` permission in the job that does
> publishing, not globally. Also, try to separate building from publishing
> — this makes sure that any scripts maliciously injected into the build
> or test environment won't be able to elevate privileges while flying under
@ -96,7 +99,8 @@ This GitHub Action [has nothing to do with _building package
distributions_]. Users are responsible for preparing dists for upload
by putting them into the `dist/` folder prior to running this Action.
> **IMPORTANT**: Since this GitHub Action is docker-based, it can only
> [!IMPORTANT]
> Since this GitHub Action is docker-based, it can only
> be used from within GNU/Linux based jobs in GitHub Actions CI/CD
> workflows. This is by design and is unlikely to change due to a number
> of considerations we rely on.
@ -187,9 +191,10 @@ default) setting as follows:
skip-existing: true
```
> **Pro tip**: try to avoid enabling this setting where possible. If you
have steps for publishing to both PyPI and TestPyPI, consider only using
it for the latter, having the former fail loudly on duplicates.
> [!NOTE]
> Pro tip: try to avoid enabling this setting where possible. If you
> have steps for publishing to both PyPI and TestPyPI, consider only using
> it for the latter, having the former fail loudly on duplicates.
### For Debugging

View file

@ -1,3 +1,5 @@
import base64
import json
import os
import sys
from http import HTTPStatus
@ -50,6 +52,25 @@ _SERVER_REFUSED_TOKEN_EXCHANGE_MESSAGE = """
Token request failed: the server refused the request for the following reasons:
{reasons}
This generally indicates a trusted publisher configuration error, but could
also indicate an internal error on GitHub or PyPI's part.
{rendered_claims}
"""
_RENDERED_CLAIMS = """
The claims rendered below are **for debugging purposes only**. You should **not**
use them to configure a trusted publisher unless they already match your expectations.
If a claim is not present in the claim set, then it is rendered as `MISSING`.
* `sub`: `{sub}`
* `repository`: `{repository}`
* `repository_owner`: `{repository_owner}`
* `repository_owner_id`: `{repository_owner_id}`
* `job_workflow_ref`: `{job_workflow_ref}`
* `ref`: `{ref}`
"""
# Rendered if the package index's token response isn't valid JSON.
@ -121,6 +142,23 @@ def assert_successful_audience_call(resp: requests.Response, domain: str):
)
def render_claims(token: str) -> str:
_, payload, _ = token.split(".", 2)
claims = json.loads(base64.urlsafe_b64decode(payload))
def _get(name: str) -> str: # noqa: WPS430
return claims.get(name, "MISSING")
return _RENDERED_CLAIMS.format(
sub=_get("sub"),
repository=_get("repository"),
repository_owner=_get("repository_owner"),
repository_owner_id=_get("repository_owner_id"),
job_workflow_ref=_get("job_workflow_ref"),
ref=_get("ref"),
)
repository_url = get_normalized_input("repository-url")
repository_domain = urlparse(repository_url).netloc
token_exchange_url = f"https://{repository_domain}/_/oidc/github/mint-token"
@ -165,7 +203,13 @@ if not mint_token_resp.ok:
for error in mint_token_payload["errors"]
)
die(_SERVER_REFUSED_TOKEN_EXCHANGE_MESSAGE.format(reasons=reasons))
rendered_claims = render_claims(oidc_token)
die(
_SERVER_REFUSED_TOKEN_EXCHANGE_MESSAGE.format(
reasons=reasons, rendered_claims=rendered_claims,
),
)
pypi_token = mint_token_payload.get("token")
if pypi_token is None:

View file

@ -14,7 +14,7 @@ cffi==1.15.1
# via cryptography
charset-normalizer==3.2.0
# via requests
cryptography==41.0.2
cryptography==41.0.3
# via secretstorage
docutils==0.20.1
# via readme-renderer