Skip to content

build(docker): pin the builder image to the toolchain go.mod asks for - #161

Merged
sylvesterdamgaard merged 1 commit into
mainfrom
claude/pin-docker-go-toolchain
Oct 20, 2026
Merged

sylvesterdamgaard merged 1 commit into
mainfrom
claude/pin-docker-go-toolchain

Conversation

@sylvesterdamgaard

Copy link
Copy Markdown
Contributor

Follow-up to #160, which pinned every go-version in CI but deliberately left the Dockerfile alone rather than widening a security patch release.

Dockerfile used a floating golang:1.27-alpine, so the binary inside ghcr.io/cboxdk/init is built by a different Go version than the release assets for the same tag. Verified on what we just published:

v3.8.3 artifact Go x/net
cbox-init-linux-amd64 / -arm64 (release assets) go1.26.10 v0.60.0
ghcr.io/cboxdk/init:3.8.3 (image) go1.27.3 v0.60.0

Neither is vulnerable — 1.27.3 is past the 1.27.2 that fixed CVE-2026-78667, -78669 and -97031, and I scanned the image's binary: 0 findings. So this is a determinism and auditability fix, not a security one, and it needs no release of its own.

It still matters, for two reasons. The image is a documented way to get cbox-init — the release notes show COPY --from=ghcr.io/cboxdk/init:<version> — so it is a shipped artifact, and a version whose two published artifacts are built by different toolchains cannot be audited from the pin. And a floating tag drifts silently, which is exactly how v3.8.2's release binaries ended up on 1.26.8 carrying three CVEs.

Changes

  • Dockerfile: FROM golang:1.27-alpine → golang:1.26.10-alpine, with a comment on why it is pinned and to what.
  • go.mod and ci.yml: the existing lockstep comments now also name Dockerfile, so a future toolchain bump cannot miss it.

All eight Go-toolchain references in the repo now agree on 1.26.10:

```
go.mod:14 toolchain go1.26.10
Dockerfile:11 FROM golang:1.26.10-alpine AS builder
.github/workflows/ci.yml:16 go: ['1.26.10']
.github/workflows/ci.yml:77 go-version: '1.26.10'
.github/workflows/ci.yml:112 go-version: '1.26.10'
.github/workflows/ci.yml:133 go-version: '1.26.10'
.github/workflows/ci.yml:155 go-version: '1.26.10'
.github/workflows/release.yml:25 go-version: '1.26.10'
```

The runtime stage stays alpine:3.24 on purpose, so it keeps receiving distro patches — pinning that to a patch would freeze the OS layer against security updates, which is the opposite of what we want.

Verification

Built the image from this branch and extracted the binary:

```
cbox-init: go1.26.10
dep golang.org/x/net v0.60.0
dep golang.org/x/sys v0.48.0
dep golang.org/x/text v0.42.0
```

— now matching the release assets. It runs (cbox-init version 3.8.3-pintest), and trivy image --severity CRITICAL,HIGH --ignore-unfixed on the whole image is clean:

Target Type Vulnerabilities
alpine 3.24.2 alpine 0
usr/local/bin/cbox-init gobinary 0

Local make check green: fmt, vet, lint (0 issues), tests with race, coverage 82.0% vs the 78.0% floor, govulncheck clean, sbom-check, license-check, 16/16 configs.

Changelog entry under [Unreleased]; this ships with whatever version comes next rather than needing one now.

`Dockerfile` used a floating `golang:1.27-alpine`, so the binary inside
`ghcr.io/cboxdk/init` was built by a different Go version than the release
assets for the same tag: v3.8.3's image carries go1.27.3 where its release
binaries carry go1.26.10. Neither is vulnerable -- 1.27.3 is past the 1.27.2
that fixed CVE-2026-78667, -78669 and -97031, and both scan clean -- but the
image is a documented way to get cbox-init (the release notes show copying the
binary out of it), and a version whose two published artifacts are built by
different toolchains cannot be audited from the pin. A floating tag also drifts
silently, which is how v3.8.2's release binaries ended up on 1.26.8 in the
first place.

The builder is now `golang:1.26.10-alpine`. All eight Go-toolchain references
in the repo -- go.mod's toolchain line, five `go-version` in ci.yml, one in
release.yml, and this -- now agree, and the comments in go.mod, ci.yml and
Dockerfile name each other so a future bump cannot miss one.

Verified: the image builds, runs, and its binary reports go1.26.10 with
golang.org/x/net v0.60.0, matching the release assets. `trivy image
--severity CRITICAL,HIGH --ignore-unfixed` on the result: 0 findings in both
the alpine 3.24.2 layer and the gobinary.

The runtime stage stays `alpine:3.24` so it keeps receiving distro patches.
@sylvesterdamgaard
sylvesterdamgaard merged commit c1c6b56 into main Oct 20, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant