Files
werkator/docs/prs/2026-09-05-PR#50-werkdock-import-and-binary-freshness.md
2026-09-10 13:50:08 +02:00

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.

  • Werkdock CHANGELOG.md 0.2.0 (repository mi/werkdock) — the release notes this PR adapts to: import replaces load -i --name for rootfs archives, load is reserved for docker/OCI image archives, image names gained docker-style tags.
  • ADR 0008 — the bwrap build runtime; docs/configuration.md, notes on builds.<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 images to werkdock inspect: images prints the bare name for untagged images on every werkdock version, the exact-line match keeps working, and inspect would 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 run flags (--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 images does not list the image
  • When a build starts
  • Then Werkator runs werkdock import ARCHIVE werkator-buildenv-<hash>
    • and runs no werkdock load.
Verified by

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 import with unknown command and 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 import fails for any other reason (any other exit code, or exit 125 without unknown command)
  • When a build starts with a missing image
  • Then the build fails with that command's output
    • and no werkdock load runs.
Verified by

Scenario#50.04: An existing image is neither imported nor loaded

  • Given werkdock images lists the image
  • When a build starts
  • Then neither import nor load runs.
Verified by

Feature: the uploaded werkdock is the werkdock that is checked out

Background

  • WERKDOCK_REPO is the werkdock checkout, by default a sibling of this repository.
  • WERKDOCK_BINARY is 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_BINARY pointing 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, the load -i --name branch 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.md and docs/deployment.md say "imported" where they said "loaded", and name the fallback and the reason the image name stays untagged.
  • tools/remote: ensure_werkdock_binary rebuilds a stale binary and prints the version it uploads; its header and docs/deployment.md say so.
  • One PR#000 placeholder in werkator.css that 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 introduces import; 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).