Releases & versioning
KEYS and in install.sh; the first release
signed with it is the next milestone on the roadmap. Until
then, build the ISO yourself.Version numbers
Runink River uses calendar versions, not semantic versions
(RELEASE.md):
| Form | Example | Used for |
|---|---|---|
runink-os-YYYY.MM | runink-os-2026.10 | a release, its signed git tag and its version file |
runink-os-YYYY.MM.N | runink-os-2026.10.1 | a second release in the same month, such as a security release |
The version is written to VERSION in the repository and lands on an installed machine as
/etc/runink-os-version:
cat /etc/runink-os-versionmain is always the next release. There are no long-lived release branches: an older
release is superseded by the next one.
What a release contains
- The ISO,
runink-river-<date>-x86_64.iso. An ISO larger than GitHub’s 2 GiB asset limit is also published as numbered parts,<iso>.part-00,-01, and so on. SHA256SUMS, listing the ISO and every part, and its detached OpenPGP signature,SHA256SUMS.asc.- The evidence of the release gate (below): SBOMs, vulnerability and secret-scan reports, build provenance and Sigstore bundles.
- A signed git tag, verifiable with
git verify-tag runink-os-YYYY.MM.
How to check all of it: Verify a release.
Cadence
There is no fixed cadence yet; setting one is an open decision. Until then a release is
cut when main has changes users will notice and they pass the criteria below. Security
fixes are released as soon as they are ready, within the targets in
SECURITY.md; upstream kernel and OpenZFS security releases are picked up the
same way.
Release criteria
A tag is cut only when all of these hold on the commit being tagged:
- CI is green:
tier1,installer-go,river-guide,go-security, REUSE and the DCO check. make lintpasses locally, including the closure lint that CI cannot run.- The ISO builds from that commit and passes a VM install and boot, with
tests/assert-golden.shon the installed system (run by hand until the Tier 2 CI runner exists). - Every pinned upstream is checked against its advisories: the kernel and the zen patch,
OpenZFS, the distribution mirror snapshot and the Go modules (
govulncheck). An exploitable known vulnerability blocks the release until it is fixed or shown not to be exploitable, and the finding is written in the release notes. CHANGELOG.mdhas the release’s section, with Security filled in, or “None.”.
The release gate
A release stays a draft until .github/workflows/release-gate.yml has checked the exact
ISO that will be downloaded; the gate is the only thing that publishes it
(docs/VERIFY.md):
| Check | Evidence attached to the release |
|---|---|
SHA256SUMS lists and verifies every ISO | SHA256SUMS |
SHA256SUMS is signed offline by the key pinned in KEYS | SHA256SUMS.asc |
| Distribution packages have no High or Critical advisory with a fix missing (Arch Linux security tracker) | <iso>.archaudit.json, .txt, arch-security-tracker.json |
| The image’s own Go programs have no known vulnerability (govulncheck) | <iso>.govulncheck.txt |
| No secret in any file the image’s authors added or changed (gitleaks) | <iso>.gitleaks.json, <iso>.ownfiles.txt |
| SBOMs of the image contents and of the source (SPDX, CycloneDX) | <iso>.spdx.json, .cdx.json, river-source.* |
| Build provenance (SLSA) and Sigstore signatures | a GitHub attestation, *.sigstore.json |
Accepted advisories are listed as waivers in .github/release-gate/waivers.txt, each with an
owner and an expiry date; an expired waiver blocks the next release.
How a release is made
- A pull request sets
VERSION, renames## [Unreleased]inCHANGELOG.mdto the new version and date, and opens a fresh## [Unreleased]. - The ISO and the packages are built from the merged commit on a maintainer’s builder.
- The release criteria are run.
- A GitHub release is created with the changelog section as its notes and the unsigned artifacts attached. CI never holds a signing key.
- A release maintainer verifies the artifacts against their own build, signs
SHA256SUMSand the packages offline (base/river-sign, which refuses to run in CI), uploads the signatures and pushes the signed tag (git tag -s).
Release notes
Every change a user would notice adds a line under ## [Unreleased] in
CHANGELOG.md, which follows Keep a Changelog 1.1.
Sections come in this order: Security, Added, Changed, Deprecated,
Removed, Fixed. Security lists every fixed vulnerability with its CVE or GitHub
advisory ID and the reporter’s credit, and upstream security bumps with their advisory IDs.
A release without vulnerability fixes says “None.” there, so “none” cannot be confused with
“not recorded”. The GitHub release carries the same text.
Supported versions
| Version | Supported |
|---|---|
the latest runink-os-* release | yes |
main | yes (fixes land here first) |
| any older release | no: upgrade to the latest |
Once a stable cadence exists, the policy will cover the latest two releases.