From 8067cde288349b1dd8d21104dbe3730056e2c1c2 Mon Sep 17 00:00:00 2001 From: rob thijssen Date: Fri, 7 Aug 2026 16:59:49 +0300 Subject: [PATCH] fix(deploy): expand $unit locally in the health probe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Run 7 shipped everything, brought api and poller up, served /v1/ready through the proxy — and failed on the last step with exit 4. ssh gitea_ci@"$API_HOST" "systemctl is-active \$unit.service" The escaped \$unit is a leftover from when this ran inside a heredoc. Over a plain ssh it sends a literal $unit for the *remote* shell to expand, against a variable that only exists in the workflow's shell — so it ran `systemctl is-active .service`, which is exit 4, unit not found. It was checking nothing, and would have kept reporting healthy no matter what the units did. Also pass -n to both probe sshs. ssh reads stdin by default, and that is a trap waiting for whoever next pipes something into this step: the first ssh eats the rest of the script and the remaining checks silently never run. (It bit the test harness for this fix, which is how it was noticed.) And say in a comment why tireless-runner is not probed: it refuses to start until the interactive agent login exists, so probing it would make every deploy red for something the deploy cannot fix. Verified by extracting this step's body from the YAML and running it as a file, the way Actions does: {"config":"ok","database":"not_implemented","forge":"not_implemented"} tireless-api: active tireless-poller: active Refs #9 Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_013TxK1CWPkFXqdcXMJ4hVe6 --- .gitea/workflows/deploy.yaml | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/.gitea/workflows/deploy.yaml b/.gitea/workflows/deploy.yaml index bdebb37..469f195 100644 --- a/.gitea/workflows/deploy.yaml +++ b/.gitea/workflows/deploy.yaml @@ -188,11 +188,24 @@ jobs: run: | # Probe from the proxy, over the mesh — the path a user actually takes. # A loopback probe on bob would pass even if firewalld were closed. - ssh gitea_ci@"$WEB_HOST" \ + # -n on every probe ssh: without it ssh reads stdin, and a future + # edit that pipes anything into this step would have the first ssh + # swallow the rest of the script. + ssh -n gitea_ci@"$WEB_HOST" \ "curl -fsS http://$API_HOST:$API_PORT/v1/ready" + echo + # $unit unescaped: it must expand HERE, in the workflow's shell. The + # escaped form is a leftover from when this ran inside a heredoc, and + # over a plain ssh it sends a literal `$unit` for the remote shell to + # expand against nothing — `systemctl is-active .service`, exit 4. for unit in tireless-api tireless-poller; do - ssh gitea_ci@"$API_HOST" "systemctl is-active \$unit.service" + printf '%s: ' "$unit" + ssh -n gitea_ci@"$API_HOST" "systemctl is-active $unit.service" done + # tireless-runner is deliberately not probed: it refuses to start + # until the interactive agent login exists on the host, which is a + # manual step. Adding it here would make every deploy red for a + # reason the deploy cannot fix. - name: startup journal if: always()