9.2 KiB
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, not as current documentation.
Related Links
- Werkdock
CHANGELOG.md0.2.0 (repositorymi/werkdock) — the release notes this PR adapts to:importreplacesload -i --namefor rootfs archives,loadis reserved for docker/OCI image archives, image names gained docker-style tags. - ADR 0008 — the bwrap build runtime;
docs/configuration.md, notes onbuilds.<name>.werkdock.
The Problem
Werkdock moves its CLI closer to docker run --rm.
For the rootfs archives Werkator uses, the verb is now werkdock import ARCHIVE IMAGE (docker import semantics).
werkdock load -i ARCHIVE --name IMAGE still works but is a compatibility path with a note on stderr, and is announced to go away once Werkator has switched.
Werkator ships the werkdock binary with its deployment, but nothing forces the two to be updated together: an installation may run a new Werkator against an older werkdock for a while, or the other way round.
And the shipping itself was unreliable, which is the second half of the same subject.
tools/remote built the werkdock binary only when the file was missing, so the first build won forever: a binary built weeks ago survived every git pull in the werkdock checkout and was uploaded in silence on every deployment since.
On 2026-09-10 this put werkdock 0.1.0-dev on the production instance twice in one morning while the checkout it came from had been at 0.2.0 for days.
The evidence was on screen both times — the deployment prints the version it unpacks — and was read as a fact about the host rather than as the symptom it was.
Without that fix this PR would change nothing in practice: the new code would meet the old binary, fall back, and go on using load -i.
Non-Goals
- No switch of the existence check from
werkdock imagestowerkdock inspect:imagesprints the bare name for untagged images on every werkdock version, the exact-line match keeps working, andinspectwould tie Werkator to the new werkdock. - No tagged image name (
werkator-buildenv:<hash>): it would re-import every build environment on the webspace and orphan the old image, for no functional gain today. - None of the new
runflags (--mount,--entrypoint,--network host): Werkator's invocation needs none of them. - No build of werkdock from this repository. It has been its own repository since step 21 session E; this only decides which of its builds gets uploaded.
- No checksum or provenance tracking for the binary. The question is "is this binary older than its sources", not "which commit is it from".
The Scenarios
Feature: rootfs archives are imported with werkdock's docker-shaped verb
Background
- The build environment is a rootfs archive named by
builds.<name>.werkdock.rootfs. - Werkator creates the werkdock image
werkator-buildenv-<hash>from it once per source. - Werkdock answers an unknown verb with
werkdock: unknown command "import"and exit code 125, its code for its own errors.
Scenario#50.01: A missing image is imported with werkdock import
So that Werkator uses the verb werkdock names for rootfs archives, and the deprecated path can be removed on werkdock's side.
- Given
werkdock imagesdoes not list the image - When a build starts
- Then Werkator runs
werkdock import ARCHIVE werkator-buildenv-<hash>- and runs no
werkdock load.
- and runs no
Verified by
- WerkdockBuildRunnerTest "imports the image once when werkdock does not know it yet"
- WerkdockBuildRunnerTest "downloads a URL rootfs once before importing it"
Scenario#50.02: An older werkdock without the verb still works
So that Werkator and werkdock can be updated in either order.
- Given the installed werkdock answers
importwithunknown commandand exit 125 - When a build starts with a missing image
- Then Werkator falls back to
werkdock load -i ARCHIVE --name werkator-buildenv-<hash>- and logs the fallback.
Verified by
Scenario#50.03: A real import failure is not masked by the fallback
So that a broken archive fails the build with werkdock's message, as before.
- Given
werkdock importfails for any other reason (any other exit code, or exit 125 withoutunknown command) - When a build starts with a missing image
- Then the build fails with that command's output
- and no
werkdock loadruns.
- and no
Verified by
Scenario#50.04: An existing image is neither imported nor loaded
- Given
werkdock imageslists the image - When a build starts
- Then neither
importnorloadruns.
Verified by
Feature: the uploaded werkdock is the werkdock that is checked out
Background
WERKDOCK_REPOis the werkdock checkout, by default a sibling of this repository.WERKDOCK_BINARYis the binary within it, by default$WERKDOCK_REPO/dist/werkdock.
Scenario#50.05: A binary older than its sources is rebuilt
- Given a werkdock checkout whose Go sources are newer than the built binary
- When any command that uploads werkdock runs
- Then the binary is rebuilt before the upload
- Given a binary newer than every source
- Then nothing is built — a deployment does not wait for a compiler with nothing to do
- Given no binary at all
- Then it is built, as before
Scenario#50.06: A binary named elsewhere is taken as given
So that a prebuilt binary stays the deployer's decision.
- Given
WERKDOCK_BINARYpointing outside the default path in the checkout - Then it is uploaded as it is and never overwritten
- Given no werkdock checkout at all
- Then there is nothing to build from, and the named binary is used
Scenario#50.07: The version is on the screen before it is on the host
- Given any upload of werkdock
- Then the version being uploaded is printed first
- and a binary that cannot report its version says so instead of failing the deployment
The Solution
WerkdockBuildRunner.ensureImage calls the new importImage: werkdock import ARCHIVE IMAGE through the non-throwing run, then either returns, falls back to load -i --name on exactly the unknown-verb signature (exit 125 plus unknown command on stderr), or rethrows the import's result as a GitCommandException — the same exception and message the old code produced.
The fallback is keyed on werkdock's own error signature rather than on parsing werkdock version: the signature is what actually decides whether the verb exists, and it needs no version table in Werkator.
For the binary, timestamps decide, not hashes: a git pull, a branch switch and an edit all touch exactly the files that would produce a different binary, so a source newer than the binary is the honest signal that the binary is behind. .git is excluded from the search, or every fetch would look like a change.
Only the default path inside the checkout is ever written — a WERKDOCK_BINARY pointing elsewhere is a deliberate choice of a prebuilt binary, and overwriting it would be a surprise; without a go.mod there is nothing to build from at all.
The version is printed before the upload. The rebuild rule makes the stale case unlikely, but the line is what makes it visible, and this failure stayed silent for weeks precisely because nobody had to look.
Open Questions
- When to drop the fallback: once every installation runs a werkdock with
import, theload -i --namebranch and its test go, and werkdock can remove the compatibility path. - A binary newer than its sources but built from another branch still passes. The printed version is what would catch it, and only if someone reads it.
- No version bump and no release-notes entry for the deployment half: nothing in the shipped application changes there, and a release note that tells the user nothing is noise.
Additional Changes
docs/configuration.mdanddocs/deployment.mdsay "imported" where they said "loaded", and name the fallback and the reason the image name stays untagged.tools/remote:ensure_werkdock_binaryrebuilds a stale binary and prints the version it uploads; its header anddocs/deployment.mdsay so.- One
PR#000placeholder inwerkator.cssthat PR#48 left behind: its rename covered Markdown, Kotlin, YAML and HTML, but not the stylesheet.
Prerequisite PRs
- Werkdock 0.2.0 (repository
mi/werkdock), which introducesimport; against an older werkdock the fallback path runs. Released on werkdock's main on 2026-09-10.
Follow-up PRs
- Remove the fallback (see Open Questions).