Skip to content

feat(publish-py): add token auth mode as escape hatch from OIDC#10

Merged
jadb merged 2 commits into
mainfrom
feat/publish-py-token-fallback
May 16, 2026
Merged

feat(publish-py): add token auth mode as escape hatch from OIDC#10
jadb merged 2 commits into
mainfrom
feat/publish-py-token-fallback

Conversation

@jadb
Copy link
Copy Markdown
Contributor

@jadb jadb commented May 16, 2026

Adds optional pypi-auth=token mode (gated on PYPI_REGISTRY_TOKEN secret) to publish-py.yml, plumbed through publish-on-tag.yml. Default unchanged.

Motivation: hop-top/poly-uri's py publish failed 8x with PyPI invalid-publisher despite claims matching the pending publisher row exactly. After 3 delete+recreate cycles, error persisted. PyPI pending-publisher matching drift — needs PyPI support to fully resolve. Token mode unblocks py releases now and helps with bootstrap (PyPI's project-scoped trusted publishers can only be added AFTER first publish).

Changes:

  • publish-py.yml: split into publish-oidc (default, existing) and publish-token (new, no environment binding, no id-token permission needed) jobs gated on pypi-auth input.
  • publish-on-tag.yml: optional PYPI_REGISTRY_TOKEN secret + pypi-auth ecosystem field, forwarded.
  • SKILL.md: new PyPI auth modes section + OIDC trap callout (workflow_ref is caller filename, not reusable — most common config error). ecosystems field table updated.

Backwards compatible: existing callers untouched.

Test plan:

  • hop-top/poly-uri opts into pypi-auth=token against this branch, ships hop-top-uri@0.2.0-alpha.1 to PyPI.
  • Once published, switch back to OIDC with project-scoped trusted publisher; verify next publish works.

Adds optional `pypi-auth` input (`oidc` | `token`, default `oidc`) and
`PYPI_REGISTRY_TOKEN` secret to `publish-py.yml`. When `pypi-auth: token`,
the workflow publishes via twine with the supplied API token and skips
the GitHub Environment binding entirely.

Motivation: hop-top/poly-uri couldn't get PyPI OIDC trusted publishing
to match despite repeatedly correct claims (owner, repo, workflow
filename `publish.yml`, environment `pypi`). After multiple
delete-and-recreate cycles of the pending publisher, PyPI continued to
return `invalid-publisher: Publisher with matching claims was not
found`. The cause appears to be drift in PyPI's pending-publisher
matching that doesn't surface in the UI. Rather than block the py
release on debugging PyPI internals, callers can opt into token auth.

Wires through `publish-on-tag.yml`:
  - new `PYPI_REGISTRY_TOKEN` secret (optional)
  - new `pypi-auth` field in ecosystem entry (optional, default oidc)

SKILL.md updated with:
  - PyPI auth modes section explaining oidc vs token tradeoffs
  - OIDC trap callout: trusted publisher must match the CALLER
    workflow filename, NOT the reusable's (workflow_ref claim comes
    from the caller).
Copilot AI review requested due to automatic review settings May 16, 2026 05:21
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds an optional PyPI API-token authentication path to the shared Python publishing workflow (as an escape hatch when PyPI OIDC trusted publishing fails), wires that option through publish-on-tag, and documents the new modes in SKILL.md.

Changes:

  • Split publish-py into publish-oidc (default) and publish-token (new) jobs selected by a new pypi-auth input.
  • Plumb pypi-auth and optional PYPI_REGISTRY_TOKEN through publish-on-tag.
  • Document PyPI auth modes and common OIDC misconfiguration (“workflow_ref is caller filename”) in SKILL.md.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
SKILL.md Documents PyPI auth modes (oidc vs token) and updates the ecosystems field reference.
.github/workflows/publish-py.yml Adds pypi-auth input + optional token secret; introduces separate OIDC/token publish jobs.
.github/workflows/publish-on-tag.yml Forwards pypi-auth and optional PYPI_REGISTRY_TOKEN into the Python publish reusable.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +40 to 42
publish-oidc:
if: ${{ inputs.pypi-auth == 'oidc' }}
runs-on: ubuntu-latest
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 3rd commit. New validate job runs a case statement on inputs.pypi-auth and fails the workflow with an explicit error before any publish job is dispatched. Both publish-oidc and publish-token now needs: validate.

Comment on lines +94 to +98
- name: Publish (API token)
uses: pypa/gh-action-pypi-publish@release/v1
with:
packages-dir: ${{ inputs.working-directory }}/dist/
password: ${{ secrets.PYPI_REGISTRY_TOKEN }}
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 3rd commit. publish-token now has a first step that reads secrets.PYPI_REGISTRY_TOKEN into a local env var and exits with ::error:: if empty, before checkout/setup/build. Wording in the message points at the caller's publish-on-tag secrets-passthrough as the most likely root cause.

Two failure modes Copilot review flagged:

1. Typoed `pypi-auth` value (e.g. `oicd`) skips both publish-oidc and
   publish-token, leaving the workflow green with nothing published.
   Add a `validate` job that fails fast on unknown values; both publish
   jobs depend on it.

2. `pypi-auth: token` with missing/empty `PYPI_REGISTRY_TOKEN` secret
   reaches the `pypa/gh-action-pypi-publish` step with empty password
   and dies with a confusing twine error. Add a preflight step that
   checks the secret and fails with a clear message before any other
   work.
@jadb jadb merged commit 600c4f6 into main May 16, 2026
1 check passed
@jadb jadb deleted the feat/publish-py-token-fallback branch May 16, 2026 05:31
@jadb jadb mentioned this pull request May 16, 2026
jadb added a commit to hop-top/poly-uri that referenced this pull request May 16, 2026
PyPI OIDC trusted publishing failed 8x with `invalid-publisher` despite
claims matching the pending publisher exactly. hop-top/.github#10 (in
@v0 since v0.4.0) adds token-auth as an escape hatch — use it for py
until the PyPI side is sorted. Wires PYPI_REGISTRY_TOKEN through from
the org-level secret.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants