Keep prometheus/client_golang at its v1.24.1 floor and test the latest release in CI

Merged
JE
6d ago
+181-0

Supersedes #979.

Why not bump to 1.25.0

The SDK is a library, so whatever go/go.mod requires, MVS forces on every app that imports it. client_golang 1.25.0 changes the api/prometheus/v1 signatures (Query, QueryRange, Series, LabelNames, LabelValues, api.Client). The SDK doesn't use that package, but a downstream app that does would break on its next SDK bump. The earlier head of this PR required 1.25.0, and Codex flagged it on go.mod.

So go/go.mod keeps a floor that only the SDK's own use of the dependency decides, and CI tracks the latest release separately.

Change

  • Floor: client_golang stays at v1.24.1, the version main ships. go/go.mod, go/go.sum and go.work.sum are byte-identical to main, so its indirects (common v0.70.1, procfs v0.21.1, client_model v0.6.2, x/text v0.41.0 from #999) stay where they are. The evidence is below.
  • New CI job: "Go Tests (latest dependencies)" in test.yml. Running with GOWORK=off (the module as a consumer resolves it), it does go get -t -u ./... (-t so test-only modules like otel/sdk move too), go get github.com/prometheus/client_golang@latest and go mod tidy, prints what moved, then runs go build, go vet and go test ./.... It commits nothing. It leaves out assert-lockfiles-unchanged --verify-clean on purpose, since rewriting go.mod/go.sum is its job; a comment there says so, and the floor job keeps that guard. It uses cache: false so it doesn't write latest-version modules under the floor job's go.sum cache key. Actions are pinned by SHA, the same as the other jobs.
  • Dependabot no longer proposes client_golang version updates. This is an ignore entry with all three update-types and no versions, and a comment points at the new job. Security updates are still possible. For security-only runs, dependabot-core keeps only an ignore's versions and drops update-types (IgnoreCondition#ignored_versions: return versions if security_updates_only). GitHub's docs say the same for update-types under allow ("update-types only affects version updates, not security updates"). For ignore, the docs only mark the option as one that touches security updates, which in practice means versions. That's why the entry must not get a versions list.
  • TestExpositionShape now compares the emitted bytes. It serves the registry through promhttp.HandlerFor, with Accept: text/plain; version=0.0.4 and Accept-Encoding: identity pinned, and compares the response body byte for byte against the golden string. It also checks status 200, the text/plain; version=0.0.4 content type, and that there's no content encoding. GatherAndCompare parsed the expected text and re-encoded both sides through the same encoder, so an encoder change would have passed it (Codex's second finding). promhttp exists on every version the module supports; testutil.GatherAndFormat doesn't.

Choosing the floor

These are empirical results, run on Linux amd64 with GOTOOLCHAIN=go1.26.9. For each candidate I started from main's go.mod, dropped the prometheus indirects so tidy re-resolved them at the minimum, then ran go get client_golang@vX, go mod tidy and go test ./pkg/basecamp/prometheus/..., plus govulncheck v1.8.0:

client_golanglibrary buildsSDK tests (core + testutil)govulncheck
v1.11.0yesnoGO-2022-0322 in a required module (not called)
v1.11.1 – v1.13.1yesno: testutil.CollectAndCount(reg, …) doesn't accept a *Registryclean
v1.14.0yesyesclean
v1.15.1, v1.17.0, v1.19.1, v1.20.5, v1.21.1, v1.22.0, v1.23.2, v1.24.0yesyesclean
v1.24.1 (floor)yesyesclean
v1.25.0 (latest)yesyesclean

The byte-exact TestExpositionShape passes on v1.14.0, v1.20.5, v1.23.2, v1.24.1 and v1.25.0.

The lowest technically valid floor is v1.14.0: the library alone builds on v1.11.1, and testutil as the tests use it needs 1.14. I kept v1.24.1 because it matches main: this PR then forces nothing on anyone that isn't already forced today, and going lower helps no consumer we know of. basecamp-cli doesn't require client_golang at all, and basecamp-mcp-server already requires 1.25.0. A lower floor also means the floor job tests a client_golang and prometheus/common from 2023, which no supported consumer runs. If you'd rather publish the widest compatible range, v1.14.0 passes every check above. It's a one-line go.mod change. Tidy then lowers common, procfs and client_model; at v1.15.1 it also added golang/protobuf and matttproud/golang_protobuf_extensions as indirects.

For the operator

  • Required check: "Go Tests (latest dependencies)" isn't added to the required checks, and whether to add it is your call. The case against: an upstream release can turn it red on a PR that changed nothing, which would block unrelated merges. The case for: without that, a red run is only a signal. It also only runs on PRs, pushes to main and workflow_dispatch. A weekly schedule trigger would notice breakage during quiet weeks, but test.yml has no schedule today, and adding one there would run every job.
  • #979 (dependabot's 1.25.0 bump) has no further purpose. Close it, or let dependabot close it once this ignore lands.
  • The same floor argument applies to the other direct dependencies (otel, coder/websocket, oapi-codegen/runtime, zalando/go-keyring), and dependabot still raises those floors. The latest-deps job already covers them, so extending the ignore is a cheap follow-up if you want it.

Verification

Run on Linux amd64 with GOTOOLCHAIN=go1.26.9 (go/go.mod's toolchain), at this head:

  • cd go && go build ./..., go vet ./...: ok
  • cd go && go test -count=1 ./... and go test -race -count=1 ./...: pass
  • make conformance-runner-tests-go: pass. Conformance runner: Passed 310, Failed 0, Skipped 2, Total 312
  • cd go && govulncheck ./... (v1.8.0): No vulnerabilities found
  • ./scripts/assert-lockfiles-unchanged --verify-clean: Dependency manifests match the committed tree
  • golangci-lint run (go/.golangci.yml, v2.14.0) on the prometheus package: 0 issues. actionlint and zizmor --offline on test.yml: clean
  • Latest-deps job simulated with its exact steps: it moved client_golang 1.24.1 → 1.25.0, common → v0.72.1, procfs → v0.22.0, client_model → v0.6.3, x/text → v0.43.0, x/sys → v0.49.0, x/tools → v0.51.0, protobuf → v1.36.12, godbus/dbus → v5.2.4 and others, then build, vet and every test passed.
  • Mutations: changing one expected counter value (1 → 2) fails TestExpositionShape, and so does inserting one extra space inside a sample line.