What a version means
Releases follow Semantic Versioning, and from 1.0.0 onwards the promise is the ordinary one: a major version may break a public surface, a minor adds capability compatibly, a patch fixes behaviour. What counts as public is enumerated on Extension policy —/v1/admin, the OpenAPI contract, the webhook and catalogue routes, the probes,
the environment variables, and the published images. /v1/panel and
/v1/account are not on that list and change with the panels.
The first generally available release is 1.0.0. Everything before it was
development on main with no published tag, which is why
release-please-config.json names 1.0.0 as the initial version rather than
letting the tooling start a 0.x line that would immediately be wrong.
Conventional Commits are the input
The version is derived from the commits merged since the last release, so a commit message is a release decision rather than a note.
A scope goes in parentheses and names the area:
feat(wallet):,
fix(bot):, docs(ops):. CI’s conventional-pr job checks the pull request
title, because a squash merge makes the title the commit message.
Never add a generated-by or co-author trailer, whatever a tool’s default
template says. AGENTS.md states this and it overrides the tool.
Before anything is releasable
Every pull request runs the fullCI workflow, and all of it must be green
before a merge. The jobs and what each one proves are on
Development; the release-relevant
point is that the gates a release depends on have already run by the time a tag
exists:
- the migration job applied every supported upgrade path against a real PostgreSQL, so a released schema is one an installation can actually reach;
- the compose job validated the shipped stack and both proxy examples against
the committed
.env.example, so the documented starting point still starts; - the docs job validated both language trees and their links.
Cutting a release
1
Merge to main
Release Please runs on every push to
main. It reads the commits since the
last release and opens — or updates — a release pull request.2
Review the release pull request
It contains exactly two kinds of change: the new version in
.release-please-manifest.json, and the generated CHANGELOG.md entries.
Read the changelog as a user would. A feat: whose description says nothing
an operator can act on is worth fixing in the commit history’s next entry
rather than by editing the generated file.3
Merge it
Merging the release pull request creates the
omniflow-vX.Y.Z tag and the
GitHub release. The tag carries the package name because release-please is
configured with one. Nothing else creates a tag; a hand-pushed tag would
publish images from a commit no changelog describes.4
Watch the release workflow
Release Please calls Release images in the same run, which gates,
builds, publishes, and signs without further input — see below for what can
stop it.It is called, not triggered by the tag, and the difference is why 1.0.0
shipped with no images. release-please pushes its tag with the default
GITHUB_TOKEN, and GitHub deliberately does not start workflow runs from
events that token caused. Release images still has a tag trigger, for a
tag a person pushes, and a workflow_dispatch that takes a tag so an
existing release can be built without cutting a new one — but neither is
what runs for an ordinary release.5
Verify what was published
Pull one image by digest and verify its signature with the
cosign verify
command on
Compatibility and upgrades.
Verifying the artifact rather than trusting the workflow is the whole point
of signing it.What the release workflow does
Two gates run before anything is built, and a finding in either stops the release rather than annotating it:- Source scan.
govulncheckfor Go dependency vulnerabilities, Gitleaks for secrets across the full history, and Trivy for filesystem vulnerabilities and licences atCRITICALandHIGH, ignoring unfixed findings. - CodeQL. Semantic analysis of the Go and TypeScript sources, which is a different question from whether a dependency has a known advisory.
api, bot, worker, web — built for
linux/amd64 and linux/arm64, published to GitHub Container Registry with an
SBOM and build provenance attached, and signed keyless with cosign using the
workflow’s own GitHub Actions OIDC identity. There is no signing key to manage,
rotate, or leak, and the signature is recorded in the public Rekor transparency
log.
The published image is then scanned again. That step is detection, not a
gate: a multi-arch image cannot be scanned before build-push-action pushes
it without a much more invasive two-stage build, so a finding there fails the
workflow after the image is already at the registry. Treat that failure as a
reason to publish a patch, not as a reason to assume nothing shipped.
The scheduled scan is not the release gate
Security runs on pull requests and weekly, and it uploads SARIF for the
security tab. It is informational: it reports rather than blocks. The release
workflow runs the same tools with exit-code: 1. Both exist because a finding
that appears between releases should be visible without waiting for one.
Fixing a released version
There is no maintenance branch. A fix lands onmain as a fix: commit,
Release Please cuts the next patch, and an installation upgrades forward.
Migrations are forward-only, so a rollback is a restore from the backup taken
immediately before the upgrade — the procedure is on
Backup, restore, and disaster recovery.
If a release must be withdrawn, delete the release and its tag before any
installation upgrades, and cut the next patch with the fix. Do not re-tag: the
signature and provenance are bound to a digest, and moving a tag makes both
describe something else.
Documentation ships with the change
Documentation is not a release step because it is a merge step. A behaviour change carries its English page, its Russian counterpart, and its navigation entry in the same commit, and CI’sdocs job enforces that the trees are in
step. By the time a tag exists, the documentation for what it contains is
already published — see Documentation.
Related
Development
Setting up the workspace, the generators, and every check CI runs.
Compatibility and upgrades
The version matrix, artifact verification, the upgrade window, and deprecations.
Testing strategy
What runs by default, what needs Docker, and what a financial change owes.
Extension policy
Which surfaces the version promise actually covers.