Release Guide¶
Build tooling¶
Ananke Plexus uses uv for all build, test, and publish operations. twine is not a runtime dependency.
| Action | Command |
|---|---|
| Install dev env | make install / uv sync --all-extras |
| Build artifacts | make build / uv build |
| Validate metadata | uv run --with twine twine check dist/* |
| Publish to TestPyPI | make publish-testpypi |
| Publish to PyPI | make publish-pypi |
| Security scan | make trivy-scan |
1. One-time GitHub repository setup¶
- Create the package in both TestPyPI and PyPI with name
ananke-plexus. - Configure Trusted Publishers (OIDC) in each index under your PyPI account:
- Publisher type: GitHub Actions
- Owner:
neo-pragnya - Repository:
ananke-plexus - Workflow:
release-pypi.yml(orrelease-testpypi.ymlfor TestPyPI) - Environment:
pypi(ortestpypi) - Create protected GitHub environments named
pypiandtestpypiin repo Settings → Environments. - Enable required reviewers on the
pypienvironment for extra protection.
No long-lived PyPI API tokens are stored in GitHub secrets — OIDC handles the authentication automatically.
2. Pre-release quality gate¶
make install # uv sync --all-extras
make verify # ruff + mypy + pytest
make trivy-scan # Trivy filesystem CVE scan (blocks on CRITICAL/HIGH)
make coverage # coverage report
3. Local token-based publish (manual fallback)¶
Only needed if OIDC is not configured. Set UV_PUBLISH_TOKEN in .env:
cp .env.example .env
# Edit .env: set UV_PUBLISH_TOKEN and UV_PUBLISH_TOKEN_TESTPYPI
# Publish to TestPyPI first
make publish-testpypi
# Validate the TestPyPI install
uv tool install --index https://test.pypi.org/simple/ ananke-plexus
ananke version
# Publish to PyPI
make publish-pypi
4. GitHub Trusted Publishing (recommended — CI path)¶
- Bump version in
src/ananke/plexus/version.py. - Update
CHANGELOG.mdwith release notes. - Commit, push, then tag:
VERSION="$(uv run python -c 'from ananke.plexus.version import __version__; print(__version__)')"
git add src/ananke/plexus/version.py CHANGELOG.md
git commit -m "chore: release v$VERSION"
git tag "v$VERSION"
git push origin main "v$VERSION"
The workflows run in this order:
release-testpypi.yml release-pypi.yml
└─ build └─ build
└─ trivy (blocking) └─ trivy (blocking)
└─ provenance └─ provenance
└─ publish TestPyPI └─ publish PyPI
└─ GitHub Release
Build-once principle: the same dist artifacts built in the build job are downloaded by the publish job — never rebuilt between validation and publishing.
5. What the release workflows produce¶
| Artifact | Description |
|---|---|
dist/*.whl |
Python wheel |
dist/*.tar.gz |
Source distribution |
dist/sbom.cdx.json |
CycloneDX SBOM |
trivy-results.sarif |
Trivy SARIF (uploaded to GitHub Security) |
| Build attestation | GitHub artifact provenance via actions/attest-build-provenance |
6. Security gates in every release¶
Both release workflows have Trivy as a hard gate:
This means a release cannot proceed if there are unfixed CRITICAL or HIGH CVEs in the package or its dependencies.
Additionally the weekly security.yml workflow runs:
- Trivy filesystem scan (SARIF + blocking)
- Semgrep SAST
- pip-audit dependency CVE check
- Gitleaks secrets scan
7. Post-release validation¶
# Install from PyPI and smoke-test
uv tool install ananke-plexus
ananke version
ananke doctor
# Or with pip
pip install -U ananke-plexus
ananke --help
8. Trivy local usage¶
# Install Trivy: https://aquasecurity.github.io/trivy/latest/getting-started/installation/
# Table report (blocks on CRITICAL/HIGH)
make trivy-scan
# JSON report (all severities)
make trivy-scan-json
# SARIF for IDE or GitHub upload
make trivy-scan-sarif
Trivy config can be customised via .trivyignore at the repo root.