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).
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:29still downloads a prebuiltgolang-migraterelease 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.testhas 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/migrateshippinggo1.25.4with all seven stdlib advisories from LeanerCloud/cloud-commitments-cli#1833 and 62 more, executing on every container start.Dockerfile.devis 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 installrefusesGOBINwhen cross-compiling and writes tobin/${GOOS}_${GOARCH}/instead, so both layouts must be resolved and the finalmvshould fail the build if neither produced a binary. Copy that shape rather than re-deriving it.Keep the version in step with
MIGRATE_VERSIONin theMakefile, 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/migratemust report the pinned toolchain. Thengovulncheck -mode=binaryagainst it, asserting on the summary line or JSON OSV entries rather than a baregrep -c.Related: LeanerCloud/cloud-commitments-cli#1833, LeanerCloud/cloud-commitments-cli#1835, LeanerCloud/cloud-commitments-cli#1836 (nothing scans the images we build).