Skip to content
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

oidc-exchange: render claims if exchange fails #174

Merged
merged 4 commits into from
Aug 10, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 45 additions & 1 deletion oidc-exchange.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import base64
import json
import os
import sys
from http import HTTPStatus
Expand Down Expand Up @@ -50,6 +52,25 @@
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.
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -165,7 +203,13 @@ def assert_successful_audience_call(resp: requests.Response, domain: str):
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:
Expand Down