A release is a tag: let it happen without a workstation #75
No reviewers
Labels
No labels
No milestone
No project
No assignees
3 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Grandiras/Ponente!75
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "issue-73-remote-release"
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?
Fixes #73.
A release is now a tag. Production follows
:lateston the same host-side timer the dev stack already uses, sogit tag vX.Y.Z && git pushis the entire release — no deploy step, no workstation, and therefore doable from a phone or by an agent dispatched from an issue.This is already live: production is armed and following
:latestas of this PR.Why the shape
An agent could always tag; it could never deploy.
deploy.shneedsdeploy/.env(one workstation) and an SSH route to the podman socket. Measured from a job container inside dind, which is where CI and dispatched agents run:host.containers.internal:22:22:22The first row corrects the previous PR, which claimed flatly that no route exists.
host.containers.internalis a route from a plain container — it only fails inside dind, where the name is the dind daemon rather than the machine. That distinction is now written down in all three places, because it looks exactly like the fix.So the direction stays inverted and the release rides an invariant the repo already had:
:latestmoves forv*tags and for nothing else. Not a weaker gate — deciding to push a version tag was always the decision; only the hand that randeploy.shafterwards is gone.Pinning: the part that has to be right
deploy.sh vX.Y.Zwrites the version into the server's env copy, andupdate.shstands down on a pinned version. Without both halves a rollback is undone within the minute, because the timer still sees:lateston the broken release.Verified end to end on production, which was safe to use as the test rig because
:latestandv2.3.0are the same digest — no code moved at any point:IMAGE_TAGlatest:latestdeploy.sh v2.3.0)v2.3.0:v2.3.0ponente is pinned to v2.3.0; leaving it alone, exit 0deploy.sh)latest:latestExit 0 rather than 1 is deliberate: a unit that failed every minute would bury a real failure in a wall of red.
update.shalso now checksAPP_PUBLIC_URL/healthzafter the container reports healthy. The container's own healthcheck talks to localhost, so it cannot see whether caddy-docker-proxy followed the recreate — and it has to, because a recreated container gets a new address.The trade, stated plainly
SERVER_STATE_DIRis now set for production too, so its secrets sit in a0600file in the podman user's home as well as in container environment. Production kept nothing there precisely so there was nothing to drift or steal. Something on the server has to recreate containers unattended for a workstation-free release to exist, and that means it needs the values. Unset it and everything still works; the stack simply cannot release itself.Agent instructions
deploy/README.md: Releasing without a workstation, Pinning and why a rollback holds, What still needs deploy.sh, plus four new troubleshooting entries.:latestis moved by the workflow run, not by where the tag points, so that changes nothing and destroys the record of what shipped.IMAGE_TAGindeploy/.envto the version just released. That pins production, and the next release is built, published and never deployed with everything looking green.What still needs a workstation
Only what is not a code release, because the timer recreates just the app container from the compose file the server already holds: a compose or env change, a first deploy, an immediate rollback, and
check-env-keys.sh(that file is not in the repo). A tag alone will not apply a compose change — the release succeeds and the feature is inert.🤖 Generated with Claude Code
🤖 Reviewing this PR — follow along in the action run; the reply will link the full session transcript.
📜 Live transcript — updating every ~5 minutes while the task runs.
✅ Verdict: approve — no blocking issues found.
Large, mostly-documentation PR with two real functional changes:
deploy/autoupdate/update.sh(pinned-tag handling now exits 0 instead of 1, plus a new public/healthzcheck after the container reports healthy) anddeploy/deploy.sh(writing the deployed tag into the env file that's synced to the server, so a rollback pin actually sticks). I traced both scripts end-to-end against the diff and the resulting file content on the PR branch: the pinning logic, theenvval/IMAGE_TAGprecedence, theSERVER_STATE_DIRinstance-name check, and the--helpline range (sed -n '2,11p') are all internally consistent, andAPP_PUBLIC_URLis already a required var in both.env.examplefiles so the new outward healthcheck has what it needs for both stacks. The extensive prose updates (README, CLAUDE.md, deploy/README.md, SKILL.md,.env.example) accurately reflect what the scripts do — the reordering of the release skill's Phase B (config check before tag) matches the stated rationale that the tag is now the irreversible step. No correctness bugs or security issues found; theSERVER_STATE_DIRtradeoff for production (secrets now also live in a 0600 file on the server) is clearly called out rather than silently introduced.⏱ 1m 8s · 11 turns · tokens: 75.8k in / 5.0k out (+948.8k cache-read)
📜 Full session transcript