Skip to content

ci: gate release pypi-publish behind PYPI_TRUSTED_PUBLISHER var#64

Merged
ernestprovo23 merged 1 commit into
mainfrom
ci/gate-release-publish-job
Jun 13, 2026
Merged

ci: gate release pypi-publish behind PYPI_TRUSTED_PUBLISHER var#64
ernestprovo23 merged 1 commit into
mainfrom
ci/gate-release-publish-job

Conversation

@ernestprovo23

Copy link
Copy Markdown
Member

What

Gate the pypi-publish job in .github/workflows/release.yml so it skips cleanly (gray, not red) until OIDC Trusted Publishing is explicitly enabled. This unblocks attaching Sigstore-signed bundles to GitHub Releases for versions already published to PyPI by token (1.0.0, 1.0.1), where the OIDC Trusted Publisher is not yet configured.

Why

On release: published, pypi-publish mints an OIDC token and exchanges it for a PyPI upload token. With no Trusted Publisher configured, that exchange fails closed → red CI on every Release. That red failure makes it impossible to cut a GitHub Release for the already-token-published 1.0.0 / 1.0.1 to attach .sigstore bundles, even though build + sign would otherwise succeed.

Changes (surgical)

  1. Gate pypi-publish — folded vars.PYPI_TRUSTED_PUBLISHER == 'true' into the job-level if: (AND-ed with the existing event-type guard). When the variable is unset / not 'true', the job is SKIPPED (gray), not red.

    if: >-
      vars.PYPI_TRUSTED_PUBLISHER == 'true' &&
      (github.event_name == 'release' ||
       (github.event_name == 'workflow_dispatch' && github.event.inputs.publish-target != 'none'))
  2. skip-existing: true added to both pypa/gh-action-pypi-publish steps (production PyPI + TestPyPI) — so even once OIDC is enabled, re-running a Release for an already-published version no-ops on the duplicate instead of failing.

  3. sign still needs: build (verified — never depended on pypi-publish), so on any published Release it builds + Sigstore-signs + attaches .sigstore bundles regardless of the publish gate.

  4. No SHA pins changed — all uses: remain pinned to a 40-char SHA with a # vX.Y.Z comment (tests/test_workflow_pins.py: 70 passed). permissions: scoping unchanged.

  5. RELEASING.md documents the PYPI_TRUSTED_PUBLISHER gate and how to enable OIDC publishing after configuring the Trusted Publisher (gh variable set PYPI_TRUSTED_PUBLISHER --body true).

Net effect

State build pypi-publish sign (bundles attached)
Variable unset (now) runs skipped (gray) runs
PYPI_TRUSTED_PUBLISHER=true (after OIDC setup) runs runs runs

Verification

  • yamllint -d relaxed .github/workflows/release.yml — clean (exit 0; only pre-existing line-length warnings).
  • Full suite in repo .venv: 511 passed, 1 skipped, incl. tests/test_workflow_pins.py (70 passed).

… cleanly until OIDC configured)

The pypi-publish job exchanges an OIDC token for a PyPI upload token. With no
Trusted Publisher configured, that exchange fails -> red CI on every published
Release, which blocks attaching Sigstore-signed bundles to Releases for versions
already published by token (1.0.0, 1.0.1).

Gate pypi-publish behind the repo variable PYPI_TRUSTED_PUBLISHER == 'true' so it
is SKIPPED cleanly (gray, not red) until OIDC publishing is explicitly enabled,
while build + sign still run so signed bundles attach. Add skip-existing: true to
both pypa/gh-action-pypi-publish steps so re-running a Release for an already
published version no-ops on the duplicate instead of failing. sign remains
needs: build. SHA pins + version comments unchanged. RELEASING.md documents the
gate variable and how to enable it after configuring the Trusted Publisher.
@ernestprovo23 ernestprovo23 merged commit 490e37c into main Jun 13, 2026
8 of 9 checks passed
@ernestprovo23 ernestprovo23 deleted the ci/gate-release-publish-job branch June 13, 2026 19:29
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.

1 participant