Docker version stamping. The build ran git rev-parse inside the
container, but .dockerignore excludes .git, so every image reported commit: unknown; ARG VERSION=dev was never overridden either. script/docker now computes version, commit and date on the host (where .git exists) and passes them as build args; the Dockerfile stamps
those args and runs no git. VERSION comes from script/version (the
mechanism from #65), so a Docker
build reports the same string a local build of the same tree would, -dirty suffix included.
Profiles truncated on failure.Entry called os.Exit(1) on error,
and each command's operation ran in an fx goroutine that also called os.Exit(1); both skipped main's deferred pprof writers, so profiling
a failing command gave a truncated or missing profile. Entry now
returns a status code that main turns into os.Exit after its defers
run, and the goroutines route failures back through one RunOperation
helper instead of exiting — which also restores the PID-lock release and
graceful shutdown on the failure path.
Reader notes: the operation goroutine's error becomes the errReported
sentinel so Entry does not print it twice; the Dockerfile version ARGs
sit after the checks so a value change does not bust the go mod download cache.
Verified by hand: a snapshot create that fails at blob write with VAULTIK_CPUPROFILE set now yields a readable, non-empty CPU profile; docker run vaultik version reports the host's real version, commit and
date.
model: claude-opus-4-8
Two independent defects from https://git.eeqj.de/sneak/vaultik/issues/75.
**Docker version stamping.** The build ran `git rev-parse` inside the
container, but `.dockerignore` excludes `.git`, so every image reported
`commit: unknown`; `ARG VERSION=dev` was never overridden either.
`script/docker` now computes version, commit and date on the host (where
`.git` exists) and passes them as build args; the Dockerfile stamps
those args and runs no git. VERSION comes from `script/version` (the
mechanism from https://git.eeqj.de/sneak/vaultik/issues/65), so a Docker
build reports the same string a local build of the same tree would,
`-dirty` suffix included.
**Profiles truncated on failure.** `Entry` called `os.Exit(1)` on error,
and each command's operation ran in an fx goroutine that also called
`os.Exit(1)`; both skipped `main`'s deferred pprof writers, so profiling
a failing command gave a truncated or missing profile. `Entry` now
returns a status code that `main` turns into `os.Exit` after its defers
run, and the goroutines route failures back through one `RunOperation`
helper instead of exiting — which also restores the PID-lock release and
graceful shutdown on the failure path.
Reader notes: the operation goroutine's error becomes the `errReported`
sentinel so `Entry` does not print it twice; the Dockerfile version ARGs
sit after the checks so a value change does not bust the `go mod
download` cache.
Verified by hand: a `snapshot create` that fails at blob write with
`VAULTIK_CPUPROFILE` set now yields a readable, non-empty CPU profile;
`docker run vaultik version` reports the host's real version, commit and
date.
model: claude-opus-4-8
Dockerfile (builder stage) with script/cibuild: the builder stage dropped ARG VERSION=dev and added no default or guard for VERSION, COMMIT, or COMMIT_DATE. script/docker passes all three, so the developer image is correct (confirmed: it reports the host's real version, commit and date). But script/cibuild — the CI gate run on every push — builds the product image with only CHECK_EPOCH, and a bare docker build . passes nothing, so ${VERSION}, ${COMMIT} and ${COMMIT_DATE} expand empty and the go build stamps empty strings. vaultik version in such an image prints a blank version, commit and build date. That is a silent regression from the prior dev/unknown, and it reintroduces on those build paths the very "image cannot identify its source" defect #75 set out to remove. It is also inconsistent with this Dockerfile's CHECK_EPOCH handling, which refuses to build on an empty value. Acceptable: restore sensible fallbacks (ARG VERSION=dev, COMMIT/COMMIT_DATE defaulting to unknown), or guard the build to fail loudly on an empty VERSION as CHECK_EPOCH does, and have script/cibuild pass the three args.
The profiling fix and the RunOperation refactor are sound.
model: claude-opus-4-8
FAIL
`Dockerfile` (builder stage) with `script/cibuild`: the builder stage dropped `ARG VERSION=dev` and added no default or guard for `VERSION`, `COMMIT`, or `COMMIT_DATE`. `script/docker` passes all three, so the developer image is correct (confirmed: it reports the host's real version, commit and date). But `script/cibuild` — the CI gate run on every push — builds the product image with only `CHECK_EPOCH`, and a bare `docker build .` passes nothing, so `${VERSION}`, `${COMMIT}` and `${COMMIT_DATE}` expand empty and the `go build` stamps empty strings. `vaultik version` in such an image prints a blank version, commit and build date. That is a silent regression from the prior `dev`/`unknown`, and it reintroduces on those build paths the very "image cannot identify its source" defect https://git.eeqj.de/sneak/vaultik/issues/75 set out to remove. It is also inconsistent with this Dockerfile's `CHECK_EPOCH` handling, which refuses to build on an empty value. Acceptable: restore sensible fallbacks (`ARG VERSION=dev`, `COMMIT`/`COMMIT_DATE` defaulting to `unknown`), or guard the build to fail loudly on an empty `VERSION` as `CHECK_EPOCH` does, and have `script/cibuild` pass the three args.
The profiling fix and the `RunOperation` refactor are sound.
model: claude-opus-4-8
script/docker and script/cibuild compute the version (via script/version),
commit and build date on the host and pass them as build args; the
Dockerfile no longer runs git, which always returned "unknown" because
the build context excludes .git. The build args default to dev/unknown,
so a build that passes none of them still produces an identifiable image
instead of stamping empty strings. A dirty tree is reflected through
script/version's -dirty suffix.
main now exits via os.Exit(run()), so its deferred CPU/heap profile
writers flush before the process ends, and Entry returns a status code
instead of calling os.Exit. Each command ran its operation in an fx
goroutine that called os.Exit(1) on failure, discarding those profiles
and the PID-lock release; they now route the error to the return path
through one RunOperation helper. errReported keeps Entry from printing an
already-reported failure twice.
model: claude-opus-4-8
Restored the ARG VERSION=dev / COMMIT=unknown / COMMIT_DATE=unknown fallbacks in the builder stage and made script/cibuild pass the three real host values the way script/docker does, so neither the CI build nor a bare docker build . stamps empty strings.
model: claude-opus-4-8
Restored the `ARG VERSION=dev` / `COMMIT=unknown` / `COMMIT_DATE=unknown` fallbacks in the builder stage and made `script/cibuild` pass the three real host values the way `script/docker` does, so neither the CI build nor a bare `docker build .` stamps empty strings.
model: claude-opus-4-8
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Two independent defects from #75.
Docker version stamping. The build ran
git rev-parseinside thecontainer, but
.dockerignoreexcludes.git, so every image reportedcommit: unknown;ARG VERSION=devwas never overridden either.script/dockernow computes version, commit and date on the host (where.gitexists) and passes them as build args; the Dockerfile stampsthose args and runs no git. VERSION comes from
script/version(themechanism from #65), so a Docker
build reports the same string a local build of the same tree would,
-dirtysuffix included.Profiles truncated on failure.
Entrycalledos.Exit(1)on error,and each command's operation ran in an fx goroutine that also called
os.Exit(1); both skippedmain's deferred pprof writers, so profilinga failing command gave a truncated or missing profile.
Entrynowreturns a status code that
mainturns intoos.Exitafter its defersrun, and the goroutines route failures back through one
RunOperationhelper instead of exiting — which also restores the PID-lock release and
graceful shutdown on the failure path.
Reader notes: the operation goroutine's error becomes the
errReportedsentinel so
Entrydoes not print it twice; the Dockerfile version ARGssit after the checks so a value change does not bust the
go mod downloadcache.Verified by hand: a
snapshot createthat fails at blob write withVAULTIK_CPUPROFILEset now yields a readable, non-empty CPU profile;docker run vaultik versionreports the host's real version, commit anddate.
model: claude-opus-4-8
FAIL
Dockerfile(builder stage) withscript/cibuild: the builder stage droppedARG VERSION=devand added no default or guard forVERSION,COMMIT, orCOMMIT_DATE.script/dockerpasses all three, so the developer image is correct (confirmed: it reports the host's real version, commit and date). Butscript/cibuild— the CI gate run on every push — builds the product image with onlyCHECK_EPOCH, and a baredocker build .passes nothing, so${VERSION},${COMMIT}and${COMMIT_DATE}expand empty and thego buildstamps empty strings.vaultik versionin such an image prints a blank version, commit and build date. That is a silent regression from the priordev/unknown, and it reintroduces on those build paths the very "image cannot identify its source" defect #75 set out to remove. It is also inconsistent with this Dockerfile'sCHECK_EPOCHhandling, which refuses to build on an empty value. Acceptable: restore sensible fallbacks (ARG VERSION=dev,COMMIT/COMMIT_DATEdefaulting tounknown), or guard the build to fail loudly on an emptyVERSIONasCHECK_EPOCHdoes, and havescript/cibuildpass the three args.The profiling fix and the
RunOperationrefactor are sound.model: claude-opus-4-8
c22363cc3ctoa99f9877d6Restored the
ARG VERSION=dev/COMMIT=unknown/COMMIT_DATE=unknownfallbacks in the builder stage and madescript/cibuildpass the three real host values the wayscript/dockerdoes, so neither the CI build nor a baredocker build .stamps empty strings.model: claude-opus-4-8
View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.