refactor(pkg/dockerutil): extract shared Docker helpers from db plugins#9
Merged
Conversation
ikeikeikeike
added a commit
that referenced
this pull request
Jun 17, 2026
CI on main has been red since v0.2.1 because the Λ-5a Docker backend
landed three classes of lint debt that local `make format-changed`
never caught (errcheck excludes ${io.Closer} family but not the moby
SDK's *client.Client.Close, and unused helpers slipped past
`go vet`):
- defer cli.Close() / defer rc.Close() in 4 plugins: wrap each in a
`_ = ...Close()` thunk so errcheck stops complaining without losing
the cleanup semantics
- removeIfExists in 4 plugin docker.go files: dead code since the
Λ-5d hardening replaced it with the upOrReuse / start-fail-cleanup
pair, but the function definitions stayed behind
- (*Provider).dockerCleanup in 4 plugin docker.go files: dead code
because each plugin's public Cleanup() goes through the nix code
path's os.RemoveAll directly; the docker variant was never wired
`os` import auto-pruned by goimports in mysql / postgres / redis
docker.go after dockerCleanup removal (elasticsearch keeps os for
its MkdirAll + chown helper).
Local verification:
golangci-lint run ./... 0 issues
go test ./... all packages pass
Unblocks PR #8 (Λ-5b auto-detect) and PR #9 (Λ-5c dockerutil pkg)
both of which inherited these warnings from main.
Each db plugin (mysql, postgres, redis, elasticsearch) shipped identical
copies of the generic Docker plumbing — client construction, image
pull-if-missing, container lookup-by-name, force-remove, --resume-idempotent
reuse, host port probe, and the com.bough.* label schema. Four times
~110 lines of verbatim duplication that any v0.2.x bug-fix had to apply
in lockstep across four files.
This change introduces pkg/dockerutil with five small files (client,
image, container, network, labels) plus unit tests for the daemon-free
helpers (Labels schema, IsPortFree contract). Each plugin's docker.go
now imports pkg/dockerutil and keeps only its engine-specific concerns:
mysqladmin/pg_isready/redis-cli/HTTP readiness probes, MYSQL_*/POSTGRES_*
env schemes, ES ulimits + datadir chown, persistence/JVM/disk-threshold
flags.
Net diff in plugins: -443 / +73 lines. pkg/dockerutil adds ~218 lines of
production code + ~282 lines of tests. Schema-stability comments on
Labels() pin the com.bough.* keys as public API so future renames break
the build instead of silently leaking containers past `bough remove`.
Verification:
- go build ./... clean
- go test ./... — 6 unit tests in pkg/dockerutil pass, all plugin tests
still pass
- go test -tags integration ./pkg/dockerutil/... — 5 integration tests
(LookupByName found/missing, RemoveIfExists idempotency, UpOrReuse
skip-running + remove-stopped) all green against real Docker daemon
- _smoke-docker-{mysql,postgres,redis} cycle through Up→ReadyCheck→
Down→Cleanup against real images in 38s / 8s / 3s respectively
- golangci-lint: net -4 issues (removed 3 unused removeIfExists from
plugins; the 6 residual unused/errcheck warnings on cli.Close +
unused dockerCleanup match the pre-refactor baseline)
Inherits the wrap-Close + remove-unused-dockerCleanup pattern from hotfix/v0.2.2-lint-cleanup; needed because the rebase took --theirs on the conflicting docker.go files which carried this branch's pre- rebase shape.
ikeikeikeike
force-pushed
the
feat/L5c-dockerutil-pkg
branch
from
June 17, 2026 01:24
8ccf330 to
e2e629e
Compare
ikeikeikeike
added a commit
that referenced
this pull request
Jun 21, 2026
…guard + signing docs honest Three review #23 follow-ups (#9, #14, #16) collected into one commit because they share the same theme: undo the v0.6 plan's overreach in the host-side CLI surface and the docs that backed it. #16 — `bough instinct export` was a Μ-1.12 stub that returned "not yet wired". The CLI advertised the command in `--help` though, so an operator who tried it hit a dead end with no fix-it pointer. Wire it through Coordinator.Export (new method, mirrors the Import flow: delegates to backend.Export, emits an audit event keyed `export`). Same scope-inference shape as newInstinctPromoteCmd so the two commands see the same default scope. #14 — internal/cli/capability.writeEmissions was joining emitter-supplied filenames straight into outDir. v0.6.0 ships three first-party emitters that all produce safe filenames, but the emitter registry is plugin-extensible from v0.6.x, and a buggy or malicious emitter returning `../../etc/foo` would have landed bytes outside the operator's --out-dir. Add the standard archive/tar-style traversal guard: filepath.Clean → absolute-or-".." reject → filepath.Rel(outDir) verify the canonical path stays inside. #9 — internal/config/config.go and docs/SIGNING.md both claimed v0.6 consumes `require_signed: true` as a spawn-time refuse-to-spawn gate. The Ν-1.8 implementation actually shipped the `bough plugin verify` CLI only; the spawn-time gate lands in v0.6.x per the four-stage timeline already documented in docs/SIGNING.md "Timeline" table. Revert the config docstring and the SIGNING.md "Configuration" para so the contract bough advertises matches what it enforces. All three change unit + conformance tests still pass: go test ./conformance/... → 6 packages, all ok go test ./internal/... → all ok go test -tags=conformance ./plugins/memory/sqlite/... → ok
ikeikeikeike
added a commit
that referenced
this pull request
Jun 21, 2026
…guard + signing docs honest Three review #23 follow-ups (#9, #14, #16) collected into one commit because they share the same theme: undo the v0.6 plan's overreach in the host-side CLI surface and the docs that backed it. #16 — `bough instinct export` was a Μ-1.12 stub that returned "not yet wired". The CLI advertised the command in `--help` though, so an operator who tried it hit a dead end with no fix-it pointer. Wire it through Coordinator.Export (new method, mirrors the Import flow: delegates to backend.Export, emits an audit event keyed `export`). Same scope-inference shape as newInstinctPromoteCmd so the two commands see the same default scope. #14 — internal/cli/capability.writeEmissions was joining emitter-supplied filenames straight into outDir. v0.6.0 ships three first-party emitters that all produce safe filenames, but the emitter registry is plugin-extensible from v0.6.x, and a buggy or malicious emitter returning `../../etc/foo` would have landed bytes outside the operator's --out-dir. Add the standard archive/tar-style traversal guard: filepath.Clean → absolute-or-".." reject → filepath.Rel(outDir) verify the canonical path stays inside. #9 — internal/config/config.go and docs/SIGNING.md both claimed v0.6 consumes `require_signed: true` as a spawn-time refuse-to-spawn gate. The Ν-1.8 implementation actually shipped the `bough plugin verify` CLI only; the spawn-time gate lands in v0.6.x per the four-stage timeline already documented in docs/SIGNING.md "Timeline" table. Revert the config docstring and the SIGNING.md "Configuration" para so the contract bough advertises matches what it enforces. All three change unit + conformance tests still pass: go test ./conformance/... → 6 packages, all ok go test ./internal/... → all ok go test -tags=conformance ./plugins/memory/sqlite/... → ok
ikeikeikeike
added a commit
that referenced
this pull request
Jul 4, 2026
This was referenced Jul 16, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
pkg/dockerutil/packagecom.bough.*label schemapkg/dockerutil/adds 218 prod + 282 test linesFiles
Test plan
go build ./...cleango test ./...— 6 unit tests pass + all 4 plugin tests still passgo test -tags integration ./pkg/dockerutil/...— 5 integration tests green against real Docker daemon_smoke-docker-mysqlcompletes Up → ReadyCheck → Down → Cleanup in 38s_smoke-docker-postgrescompletes full cycle in 8s_smoke-docker-rediscompletes full cycle in 3s_smoke-docker-elasticsearch(skipped — JVM warmup budget, plugin unit tests + reuse of identical glue cover it)golangci-lint run— net -4 issues (removed 3 unusedremoveIfExists+ 1 minor errcheck on test cleanup; the 6 residualunused dockerCleanup+errcheck cli.Closematch the pre-refactor baseline)Depends on
main