Skip to content

Commit 71a0032

Browse files
committed
oidc-exchange: render claims if exchange fails
Signed-off-by: William Woodruff <[email protected]>
1 parent 413a8d5 commit 71a0032

File tree

1 file changed

+45
-1
lines changed

1 file changed

+45
-1
lines changed

oidc-exchange.py

+45-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import base64
2+
import json
13
import os
24
import sys
35
from http import HTTPStatus
@@ -50,6 +52,25 @@
5052
Token request failed: the server refused the request for the following reasons:
5153
5254
{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}`
5374
"""
5475

5576
# 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):
121142
)
122143

123144

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+
124162
repository_url = get_normalized_input("repository-url")
125163
repository_domain = urlparse(repository_url).netloc
126164
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):
165203
for error in mint_token_payload["errors"]
166204
)
167205

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+
)
169213

170214
pypi_token = mint_token_payload.get("token")
171215
if pypi_token is None:

0 commit comments

Comments
 (0)