Beskriv hur ett släpp går till, och vad som är särskilt här
CI / test (push) Successful in 6s

Repot kom in under den gemensamma släppprocessen i 1081260 utan att någon
dokumentation sa det. README hade Kubernetes och Development men ingenting om
vägen från en commit till något som rullar i klustret, och till skillnad från
riksdata och rd-web fanns ingen CLAUDE.md alls.

Två saker om just det här repot är värda att stå skrivna, eftersom båda
avviker från syskonrepona och båda upptäcktes mitt i ett släpp:

Pipelinen har ingen bildskanning. riksdata och rd-web kör trivy efter
publiceringen; .gitea/workflows/release.yaml här har test, binaries, image och
chart och inget mer. Ett grönt släpp är alltså inget belägg för att bilden är
fri från kända sårbarheter, och en släppnot får inte antyda det.

Wrapperchartets values.yaml har två tag:-rader, appbilden och
python-sidovagnen för säkerhetskopiering, så chart-bump behöver --image för
att veta vilken som flyttas. Utan den vägrar den, vilket är rätt.

Samtidigt: varför det inte finns några build- eller push-mål, varför chartet
publiceras enbart från taggen (766f439), och varför make test kör -race när CI
inte gör det. Helm-exemplet pekade fortfarande på 0.9.0 och går till 0.9.2.

Claude-Session: https://claude.ai/code/session_01S7R4gWTz5wh5xCY4nCSJjN
This commit is contained in:
Niklas Ye
2026-09-01 22:09:15 +02:00
parent 477454ec3c
commit 5f9c202d65
2 changed files with 82 additions and 1 deletions
+32
View File
@@ -0,0 +1,32 @@
## Release
Say **"Release"** (or "Release X.Y.Z") and the `release` skill runs it: commit, push, tag,
wait for the pipeline, then open the wrapper-chart PR against `Ryuvia/charts`. It stops
there — merging and the Flux reconcile stay manual, deliberately.
Preconditions and the plan, without side effects:
```sh
~/.claude/skills/release/scripts/release-preflight # state + suggested version
~/.claude/skills/release/scripts/release-preflight vX.Y.Z # validate that release
```
Config is `.release.conf` here plus `make release-vars`. The process itself lives in
`~/.claude/skills/release/`; why it is shaped this way is in README.md §Releasing.
Two things about this repo specifically:
- **The pipeline has no image scan.** `.gitea/workflows/release.yaml` runs `test`,
`binaries`, `image` and `chart`. A green release run is not evidence the image is
CVE-clean, and a release note must not imply it is.
- **The wrapper chart has two `tag:` lines** — the app image and the python backup sidecar —
so `chart-bump` needs `--image "$IMAGE"` to know which one moves.
## Checks
`make fmt lint test helm-lint` mirrors `.gitea/workflows/ci.yaml`, so a green gate here means
a green pipeline there. The one deliberate difference is `-race`, which CI does not run; see
the comment on the `test` target.
There are deliberately no `build`/`push`/`helm-push` targets — the workflow owns publishing,
and it builds multi-arch. Publishing happens by pushing a tag.
+50 -1
View File
@@ -57,7 +57,7 @@ with the app — chart `x.y.z` is always app `vx.y.z`:
```bash ```bash
helm upgrade --install terdut-server oci://git.ryuvia.com/niklas/terdut-server \ helm upgrade --install terdut-server oci://git.ryuvia.com/niklas/terdut-server \
--version 0.9.0 \ --version 0.9.2 \
--namespace terdut-server --create-namespace \ --namespace terdut-server --create-namespace \
--set networking.hostname=terdut.example.com --set networking.hostname=terdut.example.com
``` ```
@@ -661,3 +661,52 @@ go test ./... # run all tests
go build ./... # compile all packages go build ./... # compile all packages
go run ./cmd/terdut # run locally go run ./cmd/terdut # run locally
``` ```
`make fmt lint test helm-lint` is the gate. It mirrors `.gitea/workflows/ci.yaml` step for
step, so a green run here means a green pipeline — with one deliberate exception: `make test`
adds `-race`, which CI does not. The sweeper, the notifier goroutine and the dead man's switch
sweep all touch the same single database connection, and a race between them would surface as
a flaky incident in production rather than as a red build.
## Releasing
```
push to main → ci.yaml gofmt, go vet, go test
push tag vX.Y.Z → release.yaml same gate, then publish:
git.ryuvia.com/niklas/terdut-server:vX.Y.Z
oci://git.ryuvia.com/niklas/terdut-server X.Y.Z
PR to Ryuvia/charts → bump the wrapper chart to X.Y.Z; on merge
Flux reconciles and the release rolls out
```
Both artifacts go to the **personal** Gitea namespace rather than `ryuvia`, because Gitea
scopes package visibility to the owner with no per-package override — so `ryuvia/*` is private
because the org is. Publishing to `niklas` keeps them anonymously pullable, which is why no
pull secret is needed in the cluster. Same reasoning, and the same choice, as riksdata and
rd-web.
Saying **"Release"** runs all three rows: the `release` skill commits, pushes, tags, waits for
the pipeline, and opens the `Ryuvia/charts` PR, stopping before the merge. See
`~/.claude/skills/release/`, or `.release.conf` here for this repo's part of it.
The chart is published **only** from the tag, by the `chart` job. There used to be a second
publisher on every `charts/**` push to main, and the two raced for the same chart version with
different answers — chart 0.9.0 went out reading `appVersion: "latest"` that way. One
publisher, triggered by the tag (`766f439`). The cost is that a chart-only change has no
version of its own and rides the next app tag.
There is deliberately **no** `make build` / `make push`. The workflow builds
`linux/amd64,linux/arm64` through buildx; a local single-platform push would land on top of
the multi-arch tag and stay invisible, because the tag would still resolve — just not on
arm64. Publishing happens by pushing a tag.
Two things the release process needs to know about this repo:
- **The pipeline has no image scan**, unlike riksdata and rd-web. A green release run is not
evidence the image is CVE-clean.
- **The wrapper chart's `values.yaml` has two `tag:` lines** — the app image and the python
backup sidecar — so `chart-bump` is given `--image` to say which one moves.
The wrapper chart must have **its own `version:` bumped in the same commit**. Flux reconciles
with `reconcileStrategy: ChartVersion`, so a chart whose version did not change produces no
new artifact and the change is never deployed — with no error anywhere.