Repository navigation
sec(build): Dockerfile.dev still downloads a prebuilt migrate binary, and an older one (v4.17.0) #203
Description
Surfaced while verifying LeanerCloud/cloud-commitments-cli#1835. Same defect class as LeanerCloud/cloud-commitments-cli#1833, in a file that does not ship to production.
What
Dockerfile.dev:29 still downloads a prebuilt golang-migrate release rather than compiling it on the pinned toolchain, and it is pinned to an older version than production used: v4.17.0 (production was v4.19.1 before LeanerCloud/cloud-commitments-cli#1835 replaced the download entirely).
Dockerfile.test has no such download and needs no change.
Why it matters, and why it is not urgent
This is the exact mechanism behind LeanerCloud/cloud-commitments-cli#1833: an upstream prebuilt binary carries whatever toolchain upstream built it with, so no base-image bump touches it. On production that meant /usr/local/bin/migrate shipping go1.25.4 with all seven stdlib advisories from LeanerCloud/cloud-commitments-cli#1833 and 62 more, executing on every container start.
Dockerfile.dev is a developer image. It does not reach production, which is why LeanerCloud/cloud-commitments-cli#1835 deliberately left it alone rather than widening a security PR's diff. But an older prebuilt release is very likely to carry at least the same advisories, and developer machines run it against local databases.
Fix direction
Mirror what LeanerCloud/cloud-commitments-cli#1835 did in the production Dockerfile:
RUN CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} \
go install -tags=postgres github.com/golang-migrate/migrate/v4/cmd/migrate@<version>Note the wrinkle LeanerCloud/cloud-commitments-cli#1835 hit: go install refuses GOBIN when cross-compiling and writes to bin/${GOOS}_${GOARCH}/ instead, so both layouts must be resolved and the final mv should fail the build if neither produced a binary. Copy that shape rather than re-deriving it.
Keep the version in step with MIGRATE_VERSION in the Makefile, as the production Dockerfile's comment now says.
Verification bar
Build the dev image and read the binary, do not infer from the tag: go version -m /usr/local/bin/migrate must report the pinned toolchain. Then govulncheck -mode=binary against it, asserting on the summary line or JSON OSV entries rather than a bare grep -c.
Related: LeanerCloud/cloud-commitments-cli#1833, LeanerCloud/cloud-commitments-cli#1835, LeanerCloud/cloud-commitments-cli#1836 (nothing scans the images we build).
Activity
sec(build): build the shipped image on go1.26.6, including the migrat…
fix(ci): drop lib/pq by moving golang-migrate onto the pgx/v5 driver (#…
sec(ci): unprotect only the RDS instance each state owns before destr…
sec(build): build the shipped image on go1.26.6, including the migrat…
fix(ci): drop lib/pq by moving golang-migrate onto the pgx/v5 driver (#…
sec(ci): unprotect only the RDS instance each state owns before destr…
IAmJSD commentedon Oct 20, 2026
Claiming: working on this
sec(build): build Dockerfile.dev's migrate from source like the produ…