# Releasing Audita The [release policy](policy/release.md) defines versioning, supported platforms, immutability, and success. This runbook implements it with [scripts/release.sh](../scripts/release.sh). Publication ends after a successful source/tag push; binary delivery runs asynchronously. ## Prerequisites Use Bash, Git, and Go 1.25.5 or newer (CI uses Go 1.25.5), with dependencies available locally or downloadable. Tests themselves are offline. Work from a checkout of `main` with permission to push that branch and tags to `origin`. For this repository, `origin` is `https://gitea.maximumdirect.net/eric/audita.git`. The script uses the checkout's configured `origin`; set it correctly before use. The remote must support atomic pushes. No CI credentials or Mac are needed locally. CI uses the existing `GITEA_RELEASE_TOKEN` secret for asynchronous asset delivery. macOS arm64 is a best-effort development environment; no macOS binary is published. ## Prepare the Candidate Choose an unused version following the policy. Write `docs/releases/.md`, beginning with `# Audita `, followed by a short summary and any compatibility or upgrade instructions relevant to the release. There are no mandatory boilerplate sections. Update affected canonical documentation with behavior changes. End each new note with these links, substituting the selected release version for ``: ```markdown [COPYRIGHT](https://gitea.maximumdirect.net/eric/audita/src/tag//COPYRIGHT) | [LICENSE](https://gitea.maximumdirect.net/eric/audita/src/tag//LICENSE) | [ATTRIBUTION](https://gitea.maximumdirect.net/eric/audita/src/tag//docs/oss/attribution.md) ``` Check that all three paths exist in the candidate source. Retire completed roadmaps when useful during preparation, preserving planned and deferred work and repairing affected links. This is ordinary preparation, not a script gate. Commit the intended changes, including the note, on `main`. The release script requires a clean index and worktree and does not create commits. There is no separate approval round. Published notes describe their tagged release; existing release history does not need to be reconstructed. ## Validate and Publish From the repository root, substitute the chosen version: ```sh bash scripts/release.sh --publish v0.2.0 ``` This single invocation: 1. Checks the version, branch, clean candidate, matching note title, and tag absence. 2. Runs the default offline test suite once, then builds both required Linux targets in a temporary directory using the same build script as CI. 3. Checks that the candidate and worktree are unchanged and that it includes the current `origin/main` history. 4. Creates the version tag at that commit and atomically pushes the exact source commit to `main` and the exact tag to `origin`. 5. Reports release success and exits without polling CI or checking asset availability. To validate a prepared candidate without remote access, creating a tag, or pushing: ```sh bash scripts/release.sh --check v0.2.0 ``` This is an optional diagnostic command, not a required step before `--publish`. Publication validates within its own invocation; it does not use persistent cached results. Both modes require the candidate note and a clean `main` checkout. ## Artifact Delivery [Woodpecker](../.woodpecker/release.yml) runs on tag events. It invokes [scripts/build-release.sh](../scripts/build-release.sh), then publishes: - `audita--linux-amd64` - `audita--linux-arm64` - `SHA256SUMS` Builds disable CGO and use the shared script's release flags. The version is in the asset name and source tag; Audita has no CLI version command. Cross-compilation checks compilation, not native execution on each architecture. The CI job status and logs show delivery progress or failure. Assets appear on the matching Gitea release page when delivery succeeds. A successful tag push must not be reported as confirmation that these files are available. For a new hosted release, the release plugin uses the checked-in note at the tag as its body, including the footer. On delivery retries it preserves existing release information and skips files that already exist. Consumers can download the binary for their Linux architecture and `SHA256SUMS` from that page, check its listed SHA-256 digest with `sha256sum`, and make it executable. Optional consumer checks are not maintainer release gates. Digests detect file mismatches; they are not an independent signature of authenticity. ## Failure and Retry **Local validation fails:** correct the issue, commit any changes, and rerun the publication command. A failure before tag creation publishes nothing. Temporary local build files are removed on exit. **Push fails or the connection is interrupted:** the script retains the local tag and reports failure rather than guessing whether publication succeeded. Inspect remote state with the actual version: ```sh git rev-parse 'v0.2.0^{commit}' git ls-remote origin refs/heads/main refs/tags/v0.2.0 ``` If the remote tag identifies the intended candidate and its source is on remote `main`, the release succeeded; no CI waiting is needed. An atomic push normally updates both refs or neither. If `main` has advanced since publication, fetch it and check candidate ancestry rather than requiring tip equality. If the tag is absent remotely and was never published or used by a release channel, remove only that unpublished local tag (`git tag -d v0.2.0`), resolve any rejected branch update, and rerun the command. If the remote tag has a different target, do not overwrite it; choose a fresh version. Never force a branch or tag update to bypass the guards. **CI delivery fails:** the release remains successful. Inspect the failed tag job's logs and retry that same tagged job for a transient failure. Publication is configured to skip existing filenames and not overwrite assets. Keep the same source and build environment when retrying; inspect any existing assets/checksum manifest before filling gaps. Do not regenerate and replace a published manifest or binary. If an existing manifest cannot describe the missing rebuilt assets, use a new version instead. A pipeline or source defect also requires a corrected commit and new version. An outage does not require moving the tag. **A released source defect is discovered:** fix it on `main` and publish a new appropriate version with a note explaining the correction. Leave the old tag and published files intact. ## Maintaining the Release Workflow The shared build script keeps local and CI build settings aligned. Tests in [scripts/release_test.go](../scripts/release_test.go) exercise publication against temporary local Git remotes, including guard failures and rejected pushes, with Go execution stubbed to avoid recursive builds/tests. They run in `go test ./...`. Changes to CI delivery should preserve explicit asset names, checksums, and non-overwriting publication. CI delivery is separate from the local success path.