mirror of
https://github.com/pypa/gh-action-pypi-publish.git
synced 2024-11-25 01:51:14 -05:00
Clarify the error during OIDC exchange on PRs from forks
This specializes the token retrieval error handling, providing an alternative error message when the error cause is something that we know can't possibly work due to GitHub's own restrictions on PRs from forks. PR #203 Closes #202 Ref https://github.com/python-pillow/Pillow/pull/7616 Co-authored-by: Sviatoslav Sydorenko <webknjaz@redhat.com>
This commit is contained in:
parent
edfa8f355b
commit
e53eb8b103
1 changed files with 43 additions and 1 deletions
|
@ -47,6 +47,20 @@ permissions:
|
|||
Learn more at https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect#adding-permissions-settings.
|
||||
"""
|
||||
|
||||
# Specialization of the token retrieval failure case, when we know that
|
||||
# the failure cause is use within a third-party PR.
|
||||
_TOKEN_RETRIEVAL_FAILED_FORK_PR_MESSAGE = """
|
||||
OpenID Connect token retrieval failed: {identity_error}
|
||||
|
||||
The workflow context indicates that this action was called from a
|
||||
pull request on a fork. GitHub doesn't give these workflows OIDC permissions,
|
||||
even if `id-token: write` is explicitly configured.
|
||||
|
||||
To fix this, change your publishing workflow to use an event that
|
||||
forks of your repository cannot trigger (such as tag or release
|
||||
creation, or a manually triggered workflow dispatch).
|
||||
"""
|
||||
|
||||
# Rendered if the package index refuses the given OIDC token.
|
||||
_SERVER_REFUSED_TOKEN_EXCHANGE_MESSAGE = """
|
||||
Token request failed: the server refused the request for the following reasons:
|
||||
|
@ -165,6 +179,29 @@ def render_claims(token: str) -> str:
|
|||
)
|
||||
|
||||
|
||||
def event_is_third_party_pr() -> bool:
|
||||
# Non-`pull_request` events cannot be from third-party PRs.
|
||||
if os.getenv("GITHUB_EVENT_NAME") != "pull_request":
|
||||
return False
|
||||
|
||||
event_path = os.getenv("GITHUB_EVENT_PATH")
|
||||
if not event_path:
|
||||
# No GITHUB_EVENT_PATH indicates a weird GitHub or runner bug.
|
||||
debug("unexpected: no GITHUB_EVENT_PATH to check")
|
||||
return False
|
||||
|
||||
try:
|
||||
event = json.loads(Path(event_path).read_bytes())
|
||||
except json.JSONDecodeError:
|
||||
debug("unexpected: GITHUB_EVENT_PATH does not contain valid JSON")
|
||||
return False
|
||||
|
||||
try:
|
||||
return event["pull_request"]["head"]["repo"]["fork"]
|
||||
except KeyError:
|
||||
return False
|
||||
|
||||
|
||||
repository_url = get_normalized_input("repository-url")
|
||||
repository_domain = urlparse(repository_url).netloc
|
||||
token_exchange_url = f"https://{repository_domain}/_/oidc/mint-token"
|
||||
|
@ -182,7 +219,12 @@ debug(f"selected trusted publishing exchange endpoint: {token_exchange_url}")
|
|||
try:
|
||||
oidc_token = id.detect_credential(audience=oidc_audience)
|
||||
except id.IdentityError as identity_error:
|
||||
die(_TOKEN_RETRIEVAL_FAILED_MESSAGE.format(identity_error=identity_error))
|
||||
cause_msg_tmpl = (
|
||||
_TOKEN_RETRIEVAL_FAILED_FORK_PR_MESSAGE if event_is_third_party_pr()
|
||||
else _TOKEN_RETRIEVAL_FAILED_MESSAGE
|
||||
)
|
||||
for_cause_msg = cause_msg_tmpl.format(identity_error=identity_error)
|
||||
die(for_cause_msg)
|
||||
|
||||
# Now we can do the actual token exchange.
|
||||
mint_token_resp = requests.post(
|
||||
|
|
Loading…
Reference in a new issue