Release process¶
The package is published to PyPI as soclab by .github/workflows/release.yml. The workflow uses PyPI trusted publishing: PyPI accepts an OpenID Connect token from this repository, this workflow file and the pypi GitHub environment. No API token is stored anywhere. Each release also carries PEP 740 attestations signed with the same identity.
One-time setup¶
Do this once before the first release. Both halves must match exactly or PyPI rejects the upload.
PyPI, under the project's publishing settings (for the very first release, add a pending publisher at https://pypi.org/manage/account/publishing/ instead; the project is created on first upload):
| Field | Value |
|---|---|
| PyPI project name | soclab |
| Owner | prasenjitsingh5 |
| Repository name | soc-agent-assurance-lab |
| Workflow name | release.yml |
| Environment name | pypi |
GitHub, under Settings, Environments: create an environment named pypi. Add the repository owner as a required reviewer so every publish waits for one click, and restrict deployment branches and tags to tags matching v*.
Cutting a release¶
- Confirm
mainis green:make verify, plus theciandsecurityworkflows on the merge commit. - Bump the version.
pyproject.tomlis the single source;soclab.__version__reads it from the installed metadata.
uv version 0.2.0
uv lock
uv sync --extra dev
uv run soclab version
- Update
CHANGELOG.md: rename[Unreleased]to the version and date, start a new empty[Unreleased]section. Adddocs/releases/<version>-evidence.mdwith the verification record, as0.1.0-evidence.mddoes. - Open a pull request titled
chore(release): 0.2.0, let CI pass, squash-merge. - Tag the merge commit. The tag must be
vplus the package version; the workflow refuses anything else.
git checkout main && git pull
git tag -a v0.2.0 -m "soclab 0.2.0"
git push origin v0.2.0
- Publish a GitHub release for the tag. Use the changelog section as the notes.
gh release create v0.2.0 --title "soclab 0.2.0" --notes-file notes.md
Publishing the release starts the workflow. A draft release does not.
- Watch the workflow. It has three jobs:
build: checks the tag againstpyproject.toml, runsuv build, installs the wheel into an empty virtual environment and runssoclab version,soclab scenariosandsoclab demo --helpfrom a directory outside the checkout, writes a CycloneDX SBOM of that environment, and uploadsdistandsbomas artifacts.publish: waits for thepypienvironment approval, then uploadsdist/withpypa/gh-action-pypi-publishand attestations enabled.-
test-install: on a clean runner, installssoclab==<version>from PyPI (retrying while the index catches up) and runssoclab --help,soclab demo --help,soclab versionandsoclab scenarios. -
Verify on PyPI. Open https://pypi.org/project/soclab/. The new version should list both files with a verified publisher and attestation badges. Then, from any machine:
uvx soclab@0.2.0 version
- Attach the SBOM to the GitHub release. Download the
sbomartifact from the workflow run and upload both files.
gh run download <run-id> --name sbom --dir sbom
gh release upload v0.2.0 sbom/soclab-0.2.0.cdx.json sbom/soclab-0.2.0.cdx.json.sha256
Re-running and rolling back¶
- The workflow can be started by hand from the Actions tab. Choose the tag as the ref; a branch ref fails the tag check on purpose.
- PyPI never accepts a file name twice. If
publishsucceeded and something later is wrong, do not delete the release. Fix forward with a new patch version. - A broken version can be yanked on PyPI. Yanking hides it from resolvers that do not pin it and leaves pinned installs working.
- If OPA moves to a new version, update
OPA_VERSIONand every digest insoclab/policy/opa_binary.pytogether, from the.sha256files on the OPA release page, and bumpOPA_VERSIONinci.ymland the image tag indocker-compose.yml.