|
| 1 | +import base64 |
| 2 | +import json |
1 | 3 | import os
|
2 | 4 | import sys
|
3 | 5 | from http import HTTPStatus
|
|
50 | 52 | Token request failed: the server refused the request for the following reasons:
|
51 | 53 |
|
52 | 54 | {reasons}
|
| 55 | +
|
| 56 | +This generally indicates a trusted publisher configuration error, but could |
| 57 | +also indicate an internal error on GitHub or PyPI's part. |
| 58 | +
|
| 59 | +{rendered_claims} |
| 60 | +""" |
| 61 | + |
| 62 | +_RENDERED_CLAIMS = """ |
| 63 | +The claims rendered below are **for debugging purposes only**. You should **not** |
| 64 | +use them to configure a trusted publisher unless they already match your expectations. |
| 65 | +
|
| 66 | +If a claim is not present in the claim set, then it is rendered as `MISSING`. |
| 67 | +
|
| 68 | +* `sub`: `{sub}` |
| 69 | +* `repository`: `{repository}` |
| 70 | +* `repository_owner`: `{repository_owner}` |
| 71 | +* `repository_owner_id`: `{repository_owner_id}` |
| 72 | +* `job_workflow_ref`: `{job_workflow_ref}` |
| 73 | +* `ref`: `{ref}` |
53 | 74 | """
|
54 | 75 |
|
55 | 76 | # 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):
|
121 | 142 | )
|
122 | 143 |
|
123 | 144 |
|
| 145 | +def render_claims(oidc_token: str) -> str: |
| 146 | + _, payload, _ = oidc_token.split(".", 2) |
| 147 | + claims = json.loads(base64.urlsafe_b64decode(payload)) |
| 148 | + |
| 149 | + def _get(name: str) -> str: |
| 150 | + return claims.get(name, "MISSING") |
| 151 | + |
| 152 | + return _RENDERED_CLAIMS.format( |
| 153 | + sub=_get("sub"), |
| 154 | + repository=_get("repository"), |
| 155 | + repository_owner=_get("repository_owner"), |
| 156 | + repository_owner_id=_get("repository_owner_id"), |
| 157 | + job_workflow_ref=_get("job_workflow_ref"), |
| 158 | + ref=_get("ref"), |
| 159 | + ) |
| 160 | + |
| 161 | + |
124 | 162 | repository_url = get_normalized_input("repository-url")
|
125 | 163 | repository_domain = urlparse(repository_url).netloc
|
126 | 164 | token_exchange_url = f"https://{repository_domain}/_/oidc/github/mint-token"
|
@@ -165,7 +203,13 @@ def assert_successful_audience_call(resp: requests.Response, domain: str):
|
165 | 203 | for error in mint_token_payload["errors"]
|
166 | 204 | )
|
167 | 205 |
|
168 |
| - die(_SERVER_REFUSED_TOKEN_EXCHANGE_MESSAGE.format(reasons=reasons)) |
| 206 | + rendered_claims = render_claims(oidc_token) |
| 207 | + |
| 208 | + die( |
| 209 | + _SERVER_REFUSED_TOKEN_EXCHANGE_MESSAGE.format( |
| 210 | + reasons=reasons, rendered_claims=rendered_claims |
| 211 | + ) |
| 212 | + ) |
169 | 213 |
|
170 | 214 | pypi_token = mint_token_payload.get("token")
|
171 | 215 | if pypi_token is None:
|
|
0 commit comments