ci(site): prod releases on a VERSION bump (UI-signed merge only); non-release merges build as a check #5
Loading…
Reference in a new issue
No description provided.
Delete branch "ctrl-agent/metronome:ci/test-and-prod-channels"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
The site's CI now publishes to prod only, and only on a release. CI serves no other environment. Store workflow untouched.
What CI deploys (operator decision, 2026-10-22)
metronome.varasys.io— changes only on a release (below).*.test.<apex>wildcard is bizon's: the project agent serves local builds there, and this workflow never deploys to it.What each event does
sites/metronome)main,VERSIONunchanged (orv<VERSION>already exists)mainthat bumpsVERSIONto an untagged X.Y.Z:sha-<12-char short>pushed once; then:v<VERSION>(new, immutable) and:prod(moved) — the byte-identical manifest copied by digest via the OCI distribution API, no rebuild$DEPLOY_COMMAND metronome prodv<VERSION>via the ambient token,target_commitish= the merge commit SHA (github.sha); nogit push; release assetsites-metronome.digestgithub.sha(the merge commit), notmain's tip at run time;concurrency: imageserialises runs; a dispatch on a non-main ref does nothing.v<VERSION>tag already pointing at this commit is a retry; an existing:v*is never overwritten and its digest is what:prodgets. The tag is read back and must name the merge commit.:latestand:mainare not pushed. A release build is stamped with the bareVERSION; a check build keeps the-dev.<ts>.g<sha>stamp./proc/<pid>/cmdlineis readable inside the job container): the Forgejo token and the zot basic auth go to curl on stdin (curl --config -), the clone usesGIT_ASKPASS,buildah loginkeeps--password-stdin, and the deploy key file lives in the trap-cleaned work dir.sites-<SITE_NAME>.digest(heresites-metronome.digest, name derived fromvars.SITE_NAME): after:v<VERSION>/:prodare set and BEFORE the doorbell, the job uploads one linesha256:<64 hex>= the promoted digest (POST …/releases/{id}/assets?name=…, multipart, token on stdin), then re-reads the release (asset listed, size = 72 bytes) and fetches it anonymously from/<repo>/releases/download/v<VERSION>/sites-metronome.digest— the exact URL the origin's gate reads — and byte-compares. Re-run safe: an existing asset with identical bytes is accepted; one with any other content is a FATAL, never overwritten.v+ the merge commit's own rootVERSIONfile. The build job readsVERSIONfrom its checkout ofgithub.sha; the release job independently readsVERSIONat that SHA through the API (/raw/VERSION?ref=<sha>) and fails unlessv$(cat VERSION)equals the tag, and the tag read-back must name that same commit.$DEPLOY_COMMAND $SITE prod. The origin'srefresh-gateaccepts exactly[sudo [-n]] [/usr/local/bin/]refresh-site <site> [prod]and refuses anything else (exit 126). Before accepting:prod, the origin verifies that:prodequals some:v*digest, that releasev<VERSION>on the public forge publishessites-metronome.digestnaming that digest, and that its tagged commit carries the instance's merge signature (myos #492).How merges to this repo must be made
Every merge of this repo is made in the Forgejo UI as a merge commit (instance-signed) — never by direct push to
main, and never by rebase-merge or squash. Only an instance-signed merge commit can be released: the release job refuses anything else up front, and the origin would refuse it too. A release PR changes onlyVERSION. Never pushv*tags by hand.Merge conditions — all three before this PR is merged
refresh-site <site> prod+ the release/signature verification).sites/metronome:prodset, and a signed cutover releasev<VERSION>on this forge for the digest it names, so the origin's verification has something true to verify.Until all three hold, merging is unsafe to rely on even though it is inert for prod today (no
VERSIONbump exists pastv0.0.68, so the release job would not run, and a non-release merge publishes nothing).Setup
None new: the same
vars.*(REGISTRY,IMAGE_REPO,SITE_NAME,DEPLOY_COMMAND,DEPLOY_ORIGIN,REGISTRY_USER) and secrets (REGISTRY_TOKEN,STATIC_DEPLOY_KEY) are reused. Release creation uses the ambient job token, asstore-release-on-merge.ymldoes. No Loki conclusion-line step: neither this workflow nor the store's ships one today.Docs in this PR
README + CLAUDE.md + the workflow header: CI deploys prod only, on a
VERSION-bump merge made in the UI; no test channel; the release contract (tag =v+ the commit'sVERSION, signed merge, assetsites-metronome.digest). Also fixed the stalestore-release.yml→store-release-on-merge.ymlname in CLAUDE.md andstore/README.md.🤖 Generated with Claude Code
ci(site): test + prod channels — build once on main, promote the same digest on a VERSION bumpto ci(site): prod releases on a VERSION bump; test is bizon's wildcard, non-release merges build as a checkci(site): prod releases on a VERSION bump; test is bizon's wildcard, non-release merges build as a checkto ci(site): prod releases on a VERSION bump (UI-signed merge only); non-release merges build as a check