Repository navigation
Open
Labels
area/dev-infrakind/featureAn enhancement / feature request or implementationAn enhancement / feature request or implementation
Description
Problem
Go patch releases, including security fixes, only reach our builds when someone bumps the version by hand. Dependabot can't help:
- It doesn't update the
goortoolchaindirectives ingo.mod(Bump Go toolchain directive in go.mod files dependabot/dependabot-core#13520). - It doesn't run
go mod tidyin nested modules such ashack/tools/*. That's why only vulnerability updates are enabled today.
Go 1.27.3 shipped a security fix with no advance notice. #2984 picked it up by hand: it added toolchain go1.27.3 to all 16 go.mod files and updated the benchmarking Dockerfiles. This issue tracks automating that so the next patch release doesn't need a manual catch-up.
Constraints
- The
godirective stays at the minimum version (currently1.27.0). Raising it forces newer Go on every module that imports ours. - Patch releases should land within days, and security releases right away.
- Every pin moves together: the
go.modfiles, the workflows, and the benchmarking Dockerfiles. - Bump PRs must get CI without a human retriggering them, and we'd rather not give a homegrown Action
writeaccess or store a personal access token.
Options
Where the toolchain is pinned
toolchaindirective in eachgo.mod(what we have since Upgrade Go to 1.27.3 #2984). Go,setup-go, and Renovate support it natively, and a plaingo buildmatches CI. There are 16 copies to keep in step.- A single
.go-versionfile, as in Kubernetes and etcd. There's one pin, but local builds needGOTOOLCHAINset from it, and a verify script has to keep everything else in sync.
Who bumps it
- Renovate (Mend's GitHub App). It updates
toolchainby default and leavesgoalone.gomodTidy/gomodTidyAllcover nested modules, and a regex rule can cover.go-versionor DockerfileARGs. It needs an org admin to install, and it's a third-party app with write access. Cilium's config is a worked example. - Fixing Dependabot upstream.
- Bumping by hand, with a named owner and a checklist, as Kubernetes SIG Release does.
Tasks
- Decide where the toolchain is pinned
- Add a verify check that fails when the pins disagree
- Choose the update mechanism and set it up
- Cover the benchmarking Dockerfiles
- Decide what Dependabot still does once Go modules are automated
Metadata
Metadata
Assignees
Labels
area/dev-infrakind/featureAn enhancement / feature request or implementationAn enhancement / feature request or implementation
Activity
[-]Automate Go toolchain updates[/-][+][CI] - Automate Go toolchain updates[/+]MushuEE commentedon Oct 20, 2026
.go-version only moves the version into one file. It doesn't fix the real problem (nothing bumps Go), and it costs:
The 15 toolchain lines aren't kept in sync today. Probably want a script as presubmit check here.
MushuEE commentedon Oct 20, 2026
Proposal
Decision: keep the
toolchaindirective that #2984 added, and don't switch to a.go-versionfile.gocommand readstoolchain, so local builds,go run, and IDEs get at least the pinned version with no setup. Nothing reads.go-versionexcept CI tooling.toolchainnatively, whereas.go-versionwould need a custom regex rule that fails silently if it stops matching.GOTOOLCHAINin the build, and that works the same with either.Correction to the description: there are 15 modules, not 16. The 16th
go.modis a third-party copy under_LICENSES/. Today nothing keeps theirtoolchainlines in sync; they match because #2984 edited them all by hand.Phase 1: a verify check that the pins agree (no approvals needed)
Add a script under
hack/verify/, whichhack/verify-all.shand CI run automatically. It fails when:toolchainline differs from the rootgo.mod, or a module has none (this catches new modules)benchmarking/automation/Dockerfile(ARG GO_VERSION) orbenchmarking/locust/Dockerfile(golang:image) differs from the root'sA short allowlist covers deliberate exceptions. Each entry names the module, the reason, and a removal date.
Phase 2: Renovate, Go toolchain only
The config can land before the app is installed. Renovate ignores it until then. On install, it sees an existing config and skips the onboarding PR.
Setup:
agent-substrateorg admin installs the Mend Renovate app, after any approval needed for third-party apps."dependencyDashboardApproval": trueat the top level. Renovate then lists what it would do in a dashboard issue and opens nothing until someone approves it there. Remove it once the output looks right.Expected volume: about one PR per Go patch release, roughly monthly, per branch. Each PR covers every pin. Minor upgrades (1.28) wait for approval in the dashboard. Ordinary dependency updates, Actions pins, and image digest refreshes stay off.
Draft
.github/renovate.json5. The option names are checked against Renovate's current schema, but runrenovate-config-validatorand do a dashboard-only first run before relying on it:Later: exact Go for release images
Once release images come from a single build script, it should set
GOTOOLCHAINto the rootgo.mod'stoolchainvalue. It should also fail if the Go it actually used (go env GOVERSION) differs. Builds from a laptop and from CI then match exactly.govulncheck stays mandatory as the backstop. It scans the standard library at the pinned version, so a pin left behind a known vulnerability turns CI red even if Renovate stops working.
MushuEE commentedon Oct 20, 2026
On CNCF and Renovate: other CNCF projects already use it. OpenFeature has run the free Mend app for years, and Cilium's config is a good reference. Mend also has an optional Community (OSS) plan that projects can request (OpenFeature's request). It adds more concurrency and memory, plus Merge Confidence. A toolchain-only config doesn't need any of that, so the free app works for us.
BenTheElder commentedon Oct 20, 2026
FWIW, in most cases we don't care that all of hack/tools are on the same go version as us, and it might even break some of the tools. They're only used at dev-time.
For the root module we really care that it stays very patched, along with any plugin modules at least until they move out to their own repos.
Just a quick note, I didn't absorb all the other details yet.
MushuEE commentedon Oct 20, 2026
Ack, makes sense we can let things drift for hack and tools. Mostly trying to prevent any chance that GOTOOLCHAIN=local ever fails to build because the code is on a new go version etc which
.go-versionmight encourage mismatch. Plan is to see if we can onboard to Renovate and let it dynamically handle the patches.docs(fork): record that upstream pins the Go toolchain at 1.27.3 (#539)