Files
werkregie/doc/prs/2026-10-14-PR#69-werkator-deploy.md
claude-code 1ee7a87150
werkator build succeeded after 01:04
Werkator deploys a green main to mih09 (#69)
Co-authored-by: claude-code <claude-code@javagil.de>
2026-10-14 14:07:19 +02:00

5.3 KiB

PR#69: Werkator Deploys a Green main to mih09

WARNING: This document describes only the change applied in this PR. It may already be outdated once the next PR is merged. Historic PR documentation is not maintained along with new PRs; treat it as a snapshot.

  • Werkator's docs/configuration.md, "Follow-up builds": a deployment is a build with afterSuccessOf; the repository says what it does, the host when, where and with which key.
  • werkrevisor PR#70: Hostsharing refuses ssh connections that follow too quickly.

Problem

So far a coding agent deployed the server on mih09 by hand, with scp and ssh after each merge. The auto mode of Claude Code now refuses such a production deploy, so 0.41.1 and 0.42.0 were merged but not deployed. A deploy that depends on the rights of an agent session is not reliable.

Non-Goals

  • No deploy of the relays; they run on the user's machines.
  • No deploy of a branch other than main.
  • No change to how the server runs: unit, port, configuration and .htaccess stay.

Specification

Feature: Werkator deploys a green main to mih09

Scenario#69.01: a green main build deploys its commit

… so that what runs on mih09 is the last green main, without an agent or the human.

  • Given the host part of the build deploy on mih09 and a green build default of main at version 0.43.0
  • When Werkator runs the build deploy
  • Then https://werkregie.javagil.de serves version 0.43.0, and the previous runtime stays as werkregie-dashboard.prev
Verified by

Scenario#69.02: a runtime that does not answer is rolled back

… so that a broken deploy leaves the previous version running.

  • Given a bundle whose service does not answer with its version within the waiting time
  • When the receiver installs it
  • Then the previous runtime runs again, and the build deploy fails
Verified by

Scenario#69.03: a bundle whose launcher fails does not stop the service

… so that a JRE that does not start on the host costs no downtime.

  • Given a bundle whose launcher fails
  • When the receiver checks it
  • Then the service keeps running unchanged, and the build deploy fails
Verified by

Scenario#69.04: the deploy key can only deploy

… so that a stolen deploy key gives no shell on the server.

  • Given the deploy key of Werkator on the server
  • When a connection with this key asks for a shell command
  • Then the server does not run the command, only the deploy of a bundle
Verified by
  • manual: after the setup on mih09, ssh werkregie-deploy whoami < /dev/null as Werkator's user ran the receiver, which failed on the empty bundle with exit 2; whoami did not run.

Solution

  • .werkator.yml defines the build deploy: dashboard/packaging/werkregie-deploy, status werkator/deploy, no artifacts. It has no trigger in the repository; the host part on mih09 sets afterSuccessOf: default on main and pins it, so that no branch deploys itself (Werkator's docs/configuration.md, "Follow-up builds").
  • werkregie-deploy builds the runtime bundle of the tested commit and pipes it over one ssh connection to the alias werkregie-deploy. The host names the server and the key under this alias in the ssh configuration of the build's home, since a native build of Werkator has no env of its own. It tries a refused connection again, 4 times in all, as werkrevisor's tools/deploy-rootfs does since werkrevisor PR#70.
  • werkregie-deploy-receive is the forced command of the key on the server, installed once by the human: it unpacks the bundle beside the running one, runs bin/werkregie-dashboard version, stops the service, keeps the running runtime as werkregie-dashboard.prev, swaps, starts, and waits up to 120 s until /api/dashboard answers with the new version; otherwise it puts the previous runtime back. The demo answer of /api/dashboard carries the version and needs no token.
  • The human set up the host part before the merge, as in the README of the dashboard, except the trigger: a trigger without the definition of main would run the build command of default as deploy. mih09 offers an RSA host key only, so ssh-keyscan -t ed25519 found none.
  • DeployReceiveTest runs the receiver against a temporary directory, with systemctl and curl as stubs.
  • The README of the dashboard holds the setup of the human, AGENTS.md says that the agent only checks the deploy, and the risk analysis names the deploy key.
  • Version 0.43.0; the deploy of this PR is the first one. It installs 0.43.0, which holds the changes of PR#66 and PR#68, merged but never deployed.

Open Questions

None.