ci: PyPI release workflow (Trusted Publishing)#3
Conversation
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).
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).
|
Heads-up @unidoc-alip — pushed one more commit to this PR: the PyPI distribution name is now Why: PyPI rejected Impact: distribution vs import are separate — the import is unchanged ( |
unidoc-alip
left a comment
There was a problem hiding this comment.
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
fitomllib 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.
|
Thanks @unidoc-alip — both done, exactly as suggested. 1. Tag ↔ version check — added a Release flow after merge: bump version → tag |
Adds
.github/workflows/release.yml: on av*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.0publishesismsto PyPI (pip install isms).