Skip to content

ci: PyPI release workflow (Trusted Publishing)#3

Merged
unidoc-ahall merged 3 commits into
masterfrom
feat/pypi-release
Jul 7, 2026
Merged

ci: PyPI release workflow (Trusted Publishing)#3
unidoc-ahall merged 3 commits into
masterfrom
feat/pypi-release

Conversation

@unidoc-ahall

Copy link
Copy Markdown
Contributor

Adds .github/workflows/release.yml: on a v* tag, builds sdist+wheel and publishes to PyPI via Trusted Publishing (OIDC) — no stored API token, matching the no-secrets-in-CI model.

After this merges + the PyPI Trusted Publisher is set up, tagging v0.1.0 publishes isms to PyPI (pip install isms).

Publishes to PyPI on a v* tag using PyPI Trusted Publishing (OIDC) — no API token
stored. Version comes from pyproject.toml; the tag is the trigger. Requires a
one-time Trusted Publisher set up on PyPI (project isms, unidoc/isms-python,
release.yml, environment pypi).
@unidoc-ahall unidoc-ahall requested a review from unidoc-alip July 7, 2026 16:01
The bare 'isms' name is rejected by PyPI's typosquat / too-similar guard, so the
published distribution is isms-sdk. The import stays 'isms' (pip install isms-sdk ->
from isms import IsmsClient, same pattern as sentry-sdk / beautifulsoup4). Updates
the README install line + an install-vs-import note, and the release workflow's
Trusted-Publisher comment (PyPI project name isms-sdk).
@unidoc-ahall

Copy link
Copy Markdown
Contributor Author

Heads-up @unidoc-alip — pushed one more commit to this PR: the PyPI distribution name is now isms-sdk (not isms).

Why: PyPI rejected isms with "This project name is too similar to an existing project" — its typosquat guard blocks new names too close to existing ones (so an exact-name 404 still isn't registrable). isms-sdk is distinct and clear.

Impact: distribution vs import are separate — the import is unchanged (pip install isms-sdkfrom isms import IsmsClient, like sentry-sdk). README documents the install≠import. python -m build verified locally → isms_sdk-0.1.0 sdist+wheel. The PyPI Trusted Publisher is already registered for isms-sdk (unidoc/isms-python, release.yml, env pypi).

@unidoc-alip unidoc-alip left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Adds a tag-triggered PyPI release workflow using Trusted Publishing (OIDC, no stored token) — solid, low-risk approach.
A follow-up commit renames the distribution to isms-sdk (PyPI rejected the bare isms name as too similar to an existing project); the import path stays isms and the README documents the install-vs-import split correctly. No security findings. Two should-fix suggestions below to harden the release workflow itself before the first real release.


findings

1. [should-fix] .github/workflows/release.yml line 34

Nothing in the workflow verifies that the pushed git tag matches pyproject.toml's version before building/publishing. A mistagged release (e.g. tag v0.2.0 while pyproject.toml is still at 0.1.0) would silently publish the wrong version to PyPI — and PyPI releases can't be overwritten once published.

Suggested fix — add a verification step before the "Build sdist + wheel" step:

  - name: Verify tag matches project version
    run: |
      tag_version="${GITHUB_REF_NAME#v}"
      project_version="$(python -c 'import tomllib; print(tomllib.load(open("pyproject.toml","rb"))["project"]["version"])')"
      if [ "$tag_version" != "$project_version" ]; then
        echo "::error::Tag v$tag_version does not match pyproject.toml version $project_version"
        exit 1
      fi

tomllib is stdlib on Python 3.11+, and the job already pins python-version: "3.13", so no extra dependency is needed. This fails the job fast, before any build or publish step runs.


2. [should-fix] .github/workflows/release.yml line 22

The publish job has no dependency on the test suite passing. tests.yml only triggers on push: branches: [master] and pull_request — it never runs on tag pushes. So tagging any commit publishes to PyPI immediately, with no lint/test gate on that exact commit.

Suggested fix — add an in-workflow test job and gate publish on it:

jobs:
  test:
    runs-on: ubuntu-latest
    timeout-minutes: 10
    steps:
      - uses: actions/checkout@v6
      - uses: actions/setup-python@v5
        with:
          python-version: "3.13"
      - run: pip install --quiet -e ".[dev]"
      - run: ruff check src tests
      - run: pytest -q

  publish:
    needs: test
    runs-on: ubuntu-latest
    environment: pypi
    ...

This keeps the release workflow self-contained (no cross-workflow workflow_run polling) and guarantees lint+tests pass on the exact tagged commit before publish can start.

Addresses Alip's review on PR #3:
- Verify the pushed tag matches pyproject.toml's version before build/publish, so a
  mistagged release can't silently publish the wrong (and unrewritable) version.
- Add an in-workflow lint+test job and gate publish on it (needs: test) — tests.yml
  never runs on tag pushes, so this guarantees lint+tests pass on the exact tagged
  commit before anything is published.
@unidoc-ahall

Copy link
Copy Markdown
Contributor Author

Thanks @unidoc-alip — both done, exactly as suggested.

1. Tag ↔ version check — added a Verify tag matches project version step (stdlib tomllib, the job already pins 3.13) as the first publish step; it fails fast before any build/publish if v<tag>pyproject.toml version. Given PyPI releases are immutable, this is the right guard.
2. Test gate — added an in-workflow test job (ruff + pytest) and publish: needs: test, so lint+tests must pass on the exact tagged commit before publish runs. Kept it self-contained (no cross-workflow workflow_run).

Release flow after merge: bump version → tag vX.Y.Z → tests gate → tag/version check → build → Trusted-Publishing publish.

@unidoc-alip unidoc-alip left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

looks good to me

@unidoc-ahall unidoc-ahall merged commit 19ab06b into master Jul 7, 2026
5 checks passed
@unidoc-ahall unidoc-ahall deleted the feat/pypi-release branch July 7, 2026 18:33
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