Skip to content

Release workflow publishes to PyPI before release PR is approved and merged #282

@jariy17

Description

@jariy17

Problem

The release workflow (release.yml) can publish a package to PyPI before the generated release PR has been reviewed, approved, and merged to main.

Current flow

When workflow_dispatch is triggered, all jobs run in a single pipeline:

  1. prepare-release — bumps version, creates release/vX.Y.Z branch, opens a PR
  2. test-and-build — builds the package from the release branch (not main)
  3. release-approval — manual environment gate (pypi-approval)
  4. publish-pypi — publishes artifacts to PyPI, creates tag and GitHub release

The problem is that steps 2–4 proceed immediately after the PR is created, without waiting for it to be reviewed or merged. The release-approval gate is a GitHub environment approval — not PR approval — so someone can approve the environment gate while the PR is still open or unreviewed.

Consequences

  • A package version can be published to PyPI from an unmerged branch, meaning main doesn't reflect what's on PyPI
  • The PR checklist (review changelog, verify versions, check CI) can be bypassed since publishing doesn't depend on it
  • The tag is created on main (which doesn't have the version bump yet), causing a version mismatch between the tag and the published package
  • If the PR is later rejected or modified, the already-published PyPI version cannot be retracted

Expected behavior

The publish to PyPI should only happen after the release PR has been approved, merged to main, and CI passes on main.

Suggested fix

Split the workflow into two parts:

  1. Prepare workflow (workflow_dispatch) — bump version, open PR, build and test. Stop here.
  2. Publish workflow (triggered on PR merge to main with release/v* branch pattern, or a separate workflow_dispatch) — download/rebuild artifacts from main, require environment approval, then publish to PyPI and create the tag/release.

This ensures the PR review is a hard gate before anything is published.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions