Releasing

How Conduit is versioned, how to verify what you download, how to upgrade, and how a maintainer cuts a release.

Versioning policy

Conduit uses Semantic Versioning. It is pre-1.0: a minor version (0.x.0) may contain breaking changes, and a patch version (0.x.y) will not. Breaking changes are called out in the changelog.

The policy covers this public API:

It does not cover packages under internal/, the root Go module’s other packages (that module runs the services and provides generated types to the SDK), the UI’s HTML, or the exact ClickHouse schema. Schema changes reach existing data through migrations, which the collector applies at startup.

All artifacts of a release share one version number.

Artifact Where Version form
Images ghcr.io/tjscanlan/conduit-{gateway,collector,ui,init,demo-agent} v0.2.0
Go SDK github.com/tjscanlan/conduit/sdk/go tag sdk/go/v0.2.0, used as @v0.2.0
Python SDK conduit-observability 0.1.0

Verifying images

Images are built by the release workflow and signed with keyless cosign, so a valid signature shows the image came from this repository’s workflow at a version tag:

cosign verify ghcr.io/tjscanlan/conduit-gateway:v0.2.0 \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  --certificate-identity-regexp '^https://github\.com/tjscanlan/conduit/\.github/workflows/release\.yml@refs/tags/v'

Each image also carries an SBOM and build provenance as attestations in its manifest list. To see them:

docker buildx imagetools inspect ghcr.io/tjscanlan/conduit-gateway:v0.2.0 --raw

In production, deploy by digest rather than by tag.

Upgrading

  1. Read the changelog entries between your version and the new one.
  2. Follow Upgrading an existing deployment.

Cutting a release

Only a maintainer pushes tags.

One-time setup

On PyPI, add a trusted publisher for the project conduit-observability: owner tjscanlan, repository conduit, workflow release.yml, environment pypi. If the project doesn’t exist yet, add it as a pending publisher in your account settings. If it does, add it in the project’s settings. Consider also requiring a reviewer on the pypi environment in the repository settings.

Each release

  1. On a branch, set the new version in all of these, then merge:
    • sdk/python/pyproject.toml
    • the require github.com/tjscanlan/conduit line in sdk/go/go.mod
    • the image tags in deployments/k8s/deployment.yaml
    • the ${CONDUIT_VERSION:-vX.Y.Z} image defaults in deployments/quickstart/compose.yml (embedded in conduitctl)
    • CHANGELOG.md: move [Unreleased] into an [X.Y.Z] section and update the links at the bottom

    scripts/release-check.sh vX.Y.Z checks that these agree, and CI runs it.

  2. Tag the merge commit and push both tags at once. The SDK requires the root module at the same version, and the workflow refuses a mismatch:

    git switch main && git pull
    git tag v0.2.0 && git tag sdk/go/v0.2.0
    git push --atomic origin v0.2.0 sdk/go/v0.2.0
    
  3. Watch the release workflow. It tests the commit, builds, pushes and signs the images (gateway, collector, ui, and the quickstart’s init and demo-agent), builds the conduitctl binaries with a cosign-signed SHA256SUMS, publishes to PyPI, checks that the Go SDK resolves the way a consumer would fetch it, and creates the GitHub Release from the changelog section.

A failed run can be re-run: images are rebuilt and re-signed, and PyPI files that already exist are skipped. PyPI versions and Go module tags are permanent, so fix a bad release with a new patch version rather than by moving a tag.