mirror of
https://github.com/pypa/gh-action-pypi-publish.git
synced 2024-11-25 10:01:02 -05:00
Merge pull request #143 from trail-of-forks/tob-rewrite-oidc-refs
This patch updates the user-facing OIDC mentions with the new "Trusted Publishing" term to make it cohesive with how the PyPI docs names things now.
This commit is contained in:
commit
0bf742be3e
3 changed files with 28 additions and 18 deletions
27
README.md
27
README.md
|
@ -62,20 +62,25 @@ The secret used in `${{ secrets.PYPI_API_TOKEN }}` needs to be created on the
|
||||||
settings page of your project on GitHub. See [Creating & using secrets].
|
settings page of your project on GitHub. See [Creating & using secrets].
|
||||||
|
|
||||||
|
|
||||||
### Publishing with OpenID Connect
|
### Trusted publishing
|
||||||
|
|
||||||
> **IMPORTANT**: This functionality is in beta, and will not work for you
|
> **IMPORTANT**: This functionality is in beta, and will not work for you
|
||||||
> unless you're a member of the PyPI OIDC beta testers' group. For more
|
> unless you're a member of the PyPI trusted publishing beta testers' group.
|
||||||
> information, see [warehouse#12965].
|
> For more information, see [warehouse#12965].
|
||||||
|
|
||||||
This action supports PyPI's [OpenID Connect publishing]
|
> **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.
|
||||||
|
|
||||||
|
This action supports PyPI's [trusted publishing]
|
||||||
implementation, which allows authentication to PyPI without a manually
|
implementation, which allows authentication to PyPI without a manually
|
||||||
configured API token or username/password combination. To perform
|
configured API token or username/password combination. To perform
|
||||||
[OIDC publishing][OpenID Connect Publishing] with this action, your project's
|
[trusted publishing] with this action, your project's
|
||||||
OIDC publisher must already be configured on PyPI.
|
publisher must already be configured on PyPI.
|
||||||
|
|
||||||
To enter the OIDC flow, configure this action's job with the `id-token: write`
|
To enter the trusted publishing flow, configure this action's job with the
|
||||||
permission and **without** an explicit username or password:
|
`id-token: write` permission and **without** an explicit username or password:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
jobs:
|
jobs:
|
||||||
|
@ -83,7 +88,7 @@ jobs:
|
||||||
name: Upload release to PyPI
|
name: Upload release to PyPI
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
permissions:
|
||||||
id-token: write # IMPORTANT: this permission is mandatory for OIDC publishing
|
id-token: write # IMPORTANT: this permission is mandatory for trusted publishing
|
||||||
steps:
|
steps:
|
||||||
# retrieve your distributions here
|
# retrieve your distributions here
|
||||||
|
|
||||||
|
@ -91,7 +96,7 @@ jobs:
|
||||||
uses: pypa/gh-action-pypi-publish@release/v1
|
uses: pypa/gh-action-pypi-publish@release/v1
|
||||||
```
|
```
|
||||||
|
|
||||||
Other indices that support OIDC publishing can also be used, like TestPyPI:
|
Other indices that support trusted publishing can also be used, like TestPyPI:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- name: Publish package distributions to TestPyPI
|
- name: Publish package distributions to TestPyPI
|
||||||
|
@ -268,4 +273,4 @@ https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/banner-direc
|
||||||
https://github.com/vshymanskyy/StandWithUkraine/blob/main/docs/README.md
|
https://github.com/vshymanskyy/StandWithUkraine/blob/main/docs/README.md
|
||||||
|
|
||||||
[warehouse#12965]: https://github.com/pypi/warehouse/issues/12965
|
[warehouse#12965]: https://github.com/pypi/warehouse/issues/12965
|
||||||
[OpenID Connect Publishing]: https://pypi.org/help/#openid-connect
|
[trusted publishing]: https://docs.pypi.org/trusted-publishers/
|
||||||
|
|
|
@ -13,7 +13,7 @@ _GITHUB_STEP_SUMMARY = Path(os.getenv("GITHUB_STEP_SUMMARY"))
|
||||||
# The top-level error message that gets rendered.
|
# The top-level error message that gets rendered.
|
||||||
# This message wraps one of the other templates/messages defined below.
|
# This message wraps one of the other templates/messages defined below.
|
||||||
_ERROR_SUMMARY_MESSAGE = """
|
_ERROR_SUMMARY_MESSAGE = """
|
||||||
Trusted publisher (OIDC) exchange failure:
|
Trusted publishing exchange failure:
|
||||||
|
|
||||||
{message}
|
{message}
|
||||||
|
|
||||||
|
@ -24,11 +24,14 @@ publishing, then you should double-check your secret configuration and variable
|
||||||
names.
|
names.
|
||||||
|
|
||||||
Read more about trusted publishers at https://docs.pypi.org/trusted-publishers/
|
Read more about trusted publishers at https://docs.pypi.org/trusted-publishers/
|
||||||
|
|
||||||
|
Read more about how this action uses trusted publishers at
|
||||||
|
https://github.com/marketplace/actions/pypi-publish#trusted-publishing
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Rendered if OIDC identity token retrieval fails for any reason.
|
# Rendered if OIDC identity token retrieval fails for any reason.
|
||||||
_TOKEN_RETRIEVAL_FAILED_MESSAGE = """
|
_TOKEN_RETRIEVAL_FAILED_MESSAGE = """
|
||||||
OIDC token retrieval failed: {identity_error}
|
OpenID Connect token retrieval failed: {identity_error}
|
||||||
|
|
||||||
This generally indicates a workflow configuration error, such as insufficient
|
This generally indicates a workflow configuration error, such as insufficient
|
||||||
permissions. Make sure that your workflow has `id-token: write` configured
|
permissions. Make sure that your workflow has `id-token: write` configured
|
||||||
|
@ -71,7 +74,7 @@ def die(msg: str) -> NoReturn:
|
||||||
with _GITHUB_STEP_SUMMARY.open("a", encoding="utf-8") as io:
|
with _GITHUB_STEP_SUMMARY.open("a", encoding="utf-8") as io:
|
||||||
print(_ERROR_SUMMARY_MESSAGE.format(message=msg), file=io)
|
print(_ERROR_SUMMARY_MESSAGE.format(message=msg), file=io)
|
||||||
|
|
||||||
print(f"::error::OIDC exchange failure: {msg}", file=sys.stderr)
|
print(f"::error::Trusted publishing exchange failure: {msg}", file=sys.stderr)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
@ -94,12 +97,14 @@ def assert_successful_audience_call(resp: requests.Response, domain: str):
|
||||||
case HTTPStatus.FORBIDDEN:
|
case HTTPStatus.FORBIDDEN:
|
||||||
# This index supports OIDC, but forbids the client from using
|
# This index supports OIDC, but forbids the client from using
|
||||||
# it (either because it's disabled, limited to a beta group, etc.)
|
# it (either because it's disabled, limited to a beta group, etc.)
|
||||||
die(f"audience retrieval failed: repository at {domain} has OIDC disabled")
|
die(
|
||||||
|
f"audience retrieval failed: repository at {domain} has trusted publishing disabled",
|
||||||
|
)
|
||||||
case HTTPStatus.NOT_FOUND:
|
case HTTPStatus.NOT_FOUND:
|
||||||
# This index does not support OIDC.
|
# This index does not support OIDC.
|
||||||
die(
|
die(
|
||||||
"audience retrieval failed: repository at "
|
"audience retrieval failed: repository at "
|
||||||
f"{domain} does not indicate OIDC support",
|
f"{domain} does not indicate trusted publishing support",
|
||||||
)
|
)
|
||||||
case other:
|
case other:
|
||||||
status = HTTPStatus(other)
|
status = HTTPStatus(other)
|
||||||
|
@ -124,7 +129,7 @@ assert_successful_audience_call(audience_resp, repository_domain)
|
||||||
|
|
||||||
oidc_audience = audience_resp.json()["audience"]
|
oidc_audience = audience_resp.json()["audience"]
|
||||||
|
|
||||||
debug(f"selected OIDC token exchange endpoint: {token_exchange_url}")
|
debug(f"selected trusted publishing exchange endpoint: {token_exchange_url}")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
oidc_token = id.detect_credential(audience=oidc_audience)
|
oidc_token = id.detect_credential(audience=oidc_audience)
|
||||||
|
|
|
@ -44,7 +44,7 @@ if [[ "${INPUT_USER}" == "__token__" && -z "${INPUT_PASSWORD}" ]] ; then
|
||||||
# No password supplied by the user implies that we're in the OIDC flow;
|
# No password supplied by the user implies that we're in the OIDC flow;
|
||||||
# retrieve the OIDC credential and exchange it for a PyPI API token.
|
# retrieve the OIDC credential and exchange it for a PyPI API token.
|
||||||
echo \
|
echo \
|
||||||
'::notice::Attempting to perform OIDC credential exchange' \
|
'::notice::Attempting to perform trusted publishing exchange' \
|
||||||
'to retrieve a temporary short-lived API token for authentication' \
|
'to retrieve a temporary short-lived API token for authentication' \
|
||||||
"against ${INPUT_REPOSITORY_URL} due to __token__ username with no" \
|
"against ${INPUT_REPOSITORY_URL} due to __token__ username with no" \
|
||||||
'supplied password field'
|
'supplied password field'
|
||||||
|
|
Loading…
Reference in a new issue