Releasing Provenant
July 12, 2026 ยท View on GitHub
This guide documents the maintainer release flow for provenant.
Overview
Releases are split into two phases:
- local release preparation with
release.sh, which refreshes the embedded license data, runs the release-time sync checks, prepares the release commit, and pushes the release tag - tag-triggered GitHub Actions publication, which creates the GitHub Release assets, publishes
provenant-clito crates.io via trusted publishing, and pushes a container image to GHCR
The published crate name is provenant-cli, while the installed binary and product name remain provenant / Provenant.
Prerequisites
Before cutting a release, make sure you have:
- A clean working tree
- The
reference/scancode-toolkit/submodule initialized via./setup.sh cargo-releaseinstalled locally- GPG signing configured for git tags
- A green
CIworkflow run onmainbefore you start release prep
For the normal release path, you do not need cargo login on your local machine. crates.io authentication is handled by the tag-triggered GitHub Actions trusted publishing flow, which verifies that the tagged commit is reachable from origin/main before it can mint the short-lived crates.io token.
Install cargo-release if needed:
cargo install cargo-release
Preflight Checks
The primary pre-release quality gate is the GitHub CI workflow in .github/workflows/check.yml. Start from a commit where that workflow is already green.
Use targeted local checks only when you need extra confidence before tagging. For example, npm run check:docs, npm run validate:urls, or a focused Rust test command can help verify the specific area you just changed without duplicating the full CI matrix locally.
Release Commands
Always start with a dry run:
./release.sh patch
When the dry run looks correct, perform the real release:
./release.sh patch --execute
Supported release types:
patchupdatesX.Y.ZtoX.Y.(Z+1)minorupdatesX.Y.ZtoX.(Y+1).0majorupdatesX.Y.Zto(X+1).0.0
What release.sh Does
On every release attempt, the script:
- verifies a clean working tree and initialized ScanCode reference submodule
- updates the pinned ScanCode checkout from
origin/developand regenerates the embedded license index artifact - checks ScanCode output-format version sync before continuing
- syncs the root package version in
Cargo.lockwithout re-resolving dependencies, then verifies release version sync aftercargo releaseupdates versioned files - in
--executemode, commits any license-data refresh withgit commit -s - runs the local
cargo releaseflow for versioning, tagging, and pushing
The exact cargo release behavior comes from [package.metadata.release] in Cargo.toml, including the CITATION.cff version replacement, Cargo.lock root-package version sync without dependency re-resolution, signed tag creation, and push behavior. The release commit written by release.sh stays versionless (chore: release) and DCO-signed.
GitHub Release Automation
Pushing the vX.Y.Z tag triggers .github/workflows/release.yml.
That workflow:
- verifies release invariants on the tagged commit, including version/tag alignment and crates.io dry-run packaging
- Re-runs embedded license index verification as a final release-time safeguard before building artifacts
- Builds release binaries for Linux, macOS (Intel and Apple Silicon), and Windows
- Packages each build under the
provenant-<platform>-<arch>naming scheme - Generates SHA256 checksum files
- Creates a GitHub Release, attaches SLSA build-provenance attestation for the release archives, and uploads all generated assets
- Publishes
provenant-clito crates.io via trusted publishing - Publishes a multi-arch container image to
ghcr.io/getprovenant/provenant, with its own SLSA build-provenance attestation - On a stable (non-prerelease) tag, bumps the Homebrew formula in
getprovenant/homebrew-tapto the new version and checksums
The GitHub Release (binaries + attestation) is produced independently of the crates.io and GHCR publishes: those jobs run in parallel and depend only on the build, so a crates.io or GHCR outage does not fail or skip the Release.
If the tag contains -, GitHub marks the release as a prerelease.
The Homebrew bump renders .github/homebrew/provenant.rb.tmpl with the release version and per-arch checksums, validates it, and commits it directly to the tap. It authenticates with the provenant-release-bot GitHub App (via the RELEASE_BOT_APP_ID and RELEASE_BOT_PRIVATE_KEY repository secrets); the app is installed on the tap repo with only contents: write.
After Starting the Release
Monitor the GitHub Actions release workflow and the resulting GitHub Releases page.
Verify:
- The tag and release commit are present on the remote
- The GitHub Release contains all expected Linux, macOS (Intel and Apple Silicon), and Windows archives and checksum files
- The crates.io publish job succeeded and the container image was pushed to GHCR
The crates.io and GHCR publish jobs are independent of the GitHub Release: if one fails, rerun only that failed job for the same version. The Release itself does not depend on them, so a publish failure never requires re-cutting the Release.
Common Failure Points
- Missing submodule setup: run
./setup.sh - Missing GPG configuration:
cargo releasecannot create the signed tag - Dirty working tree: clean up local changes before retrying
- Release tag is not reachable from
main - Release tag does not match the crate version in
Cargo.toml