Regression coverage for:
- Bug #3: sha256: prefix comparison — tests the stripSha helper and the
imageMatch logic as used in verifyStatelessRecreated()
- Bug #7 / #6: registry file must exist and have all required fields;
no app may use deploy_mode=webhook (webhook path retired)
Run: REGISTRY_FILE=<path> node --test test/registry-loader.test.js
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- verifyStatelessRecreated(): strip sha256: prefix before comparing image SHAs
(same fix already applied to runtime-status in 2551af4, completeSelfRecreate
in 06852c2; now consistent across all three verify paths)
- verifyStatelessRecreated(): add kua-vault wrap on compose images/ps calls
(mirrors 2551af4 runtime-status fix; env interpolation was causing empty
output for vault-injected apps, making the verify always fail with
'no running container')
- start(): downgrade missing WEBHOOK_SECRET from fatal error to warning; the
Forgejo webhook path is retired in favour of the admin API — handler stays
but the startup guard no longer blocks kua-deploy from booting
- Add GET /api/v1/apps/registry so kua-mcp-core can fetch the full app list
over HTTP without depending on a filesystem path inside its container
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The prior expected_image_sha was captured via docker compose images, which returns the image of the existing (pre-recreate) container — not the freshly-built one. Switch to docker images ${project}-${service}:latest --quiet --no-trunc which returns the post-build image SHA. Also normalize sha256: prefix in completeSelfRecreate comparison so docker compose images output (sha256-prefixed) and docker inspect output (also sha256-prefixed) match cleanly.
When kua-deploy is recreating itself (target appName == kua-deploy on same host), the OLD process is about to be killed by the docker daemon mid-flight. Without a handoff, progress would be stuck at deploy:running forever and release-app would poll until timeout.
Self-recreate path: (1) pre-mark progress phase=self_recreate_pending with the freshly-built image SHA + deployStartTs + stateless services list; (2) fire-and-forget recreateService (do not await its return — the OLD process is dying anyway); (3) sleep 90s as a ceiling — if were still alive, recreate failed and we throw.
On startup, completeSelfRecreate() reads progress-kua-deploy.json; if phase is self_recreate_pending, queries its own container via docker inspect, compares running image SHA to the pre-recreate expected SHA, checks StartedAt > recreate_started_at + state=running, then writes phase=succeeded (or failed) plus a verify struct on the deploy step. Idempotent — no-op if no marker is found.
Replaces the runOnServer("docker compose up -d --force-recreate") pattern with a one-shot transient docker:cli container that runs OUTSIDE kua-deploy lifecycle. Solves the self-recreate chicken-and-egg: when the target is kua-deploy itself, the recreate completes because the transient survives kua-deploy stopping (docker daemon does the actual work).
Secrets are fetched via kua-vault export, written to a 600-perm tempfile on /app/data, passed via --env-file (docker CLI reads it from kua-deploys perspective; never on the docker run command line). Tempfile is unlinked in finally{}.
Replaces: deploy() stateless recreate (force=true), deploy() stateful up (force=false), rollback() recreate (force=true with all-services svcList).
Build step keeps runOnServer (local exec on bruno) since build doesnt kill kua-deploy. envPrefix/kvPrefix vars retained for the build command.
Split rationale: kua-deploy used to be a service in coder-core/services/kua-services/docker-compose.yml, which meant every release-app coder-core rebuilt+force-recreated kua-deploy as a side-effect. The recreate-self path is structurally racy (the compose-up process is killed mid-flight when its own container stops), causing silent false-success deploys.
This split makes kua-deploy its own deploy unit (own repo, own compose project, own release-app entry), so coder-core releases no longer touch it. Phase A (transient-container recreateService pattern) will follow to make deliberate kua-deploy self-updates also reliable.
Handoff: v2-deploy-coordination -> kua-deploy-split (.sessions.md 2026-05-21 21:35).