Skip to content

sec(deps): bump the build toolchain to go1.26.6 (backend#1972) - #500

Merged
LukasWodka merged 2 commits into
developfrom
sec/1971-go-1-26-6
Aug 14, 2026
Merged

sec(deps): bump the build toolchain to go1.26.6 (backend#1972)#500
LukasWodka merged 2 commits into
developfrom
sec/1971-go-1-26-6

Conversation

@LukasWodka

@LukasWodka LukasWodka commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

govulncheck reports four CALLED stdlib vulnerabilities on go1.26.5 — reached
from this module's own code, not merely present in the dependency graph:

GO-2026-6218 net/url quadratic complexity in resolvePath
GO-2026-6090 crypto/tls post-handshake message flood
GO-2026-5972 encoding/asn1 unbounded recursion depth
GO-2026-5026 net/http x/net/idna Punycode label handling

All four are fixed in go1.26.6, and none needs a code or dependency change.
Every workflow resolves Go through go-version-file: go.mod, so this one line
moves build.yml, golangci.yml, e2e.yml, mutation.yml, release.yml and
chart-drift.yml together.

go 1.26.0 is deliberately untouched — that is the language floor, not the
toolchain, and .golangci.yml's go: "1.26" tracks it. Only the compiler moves.

Evidence, on a real toolchain rather than from release notes

GOTOOLCHAIN=auto fetched go1.26.6 and used it:

go version                 go1.26.6 darwin/amd64  (downloaded on demand)
go build ./...             exit 0
go vet ./...               exit 0
go test ./...              exit 0  (all packages ok)
govulncheck ./...          exit 0  "No vulnerabilities found."

Counterfactual, so the bump is demonstrably what fixed it rather than something
incidental — reverted the single line and re-ran the same binary:

toolchain go1.26.5  ->  exit 3, 4 vulnerabilities (the four above)
toolchain go1.26.6  ->  exit 0, none

Exit codes read explicitly: govulncheck exits 3 on findings, so "looks clean"
in the output is not the same as passing.

What is NOT in this PR

Making govulncheck a required status check. It is red-on-main today and the
prod promotion merged straight past it, which is the actual defect — filed as
backend#1972. It must be armed only AFTER this reaches main: adding the
context while main is still on go1.26.5 would block every release-train
promotion on the branch the train has to merge into.

Fix first, arm second.


Note

Low Risk
Toolchain-only security patch with no logic or dependency changes; low blast radius beyond build/reproducibility.

Overview
Pins the Go build toolchain to go1.26.6 (from go1.26.5) and bumps VERSION to 0.10.7. The language floor go 1.26.0 is unchanged.

This addresses four stdlib issues that govulncheck reports as reachable from this module (crypto/tls, encoding/asn1, net/http, net/url) with no application or dependency edits—CI and release builds already take Go from go-version-file: go.mod, so the toolchain line updates build, lint, e2e, mutation, release, and chart-drift workflows together.

go.mod comments document the CVEs, call paths, and that making govulncheck a required check is intentionally deferred until after this lands on main (backend#1972).

Reviewed by Cursor Bugbot for commit 528ddfb. Bugbot is set up for automated code reviews on this repo. Configure here.

`govulncheck` reports four CALLED stdlib vulnerabilities on go1.26.5 — reached
from this module's own code, not merely present in the dependency graph:

  GO-2026-6218  net/url        quadratic complexity in resolvePath
  GO-2026-6090  crypto/tls     post-handshake message flood
  GO-2026-5972  encoding/asn1  unbounded recursion depth
  GO-2026-5026  net/http       x/net/idna Punycode label handling

All four are fixed in go1.26.6, and none needs a code or dependency change.
Every workflow resolves Go through `go-version-file: go.mod`, so this one line
moves build.yml, golangci.yml, e2e.yml, mutation.yml, release.yml and
chart-drift.yml together.

`go 1.26.0` is deliberately untouched — that is the language floor, not the
toolchain, and .golangci.yml's `go: "1.26"` tracks it. Only the compiler moves.

## Evidence, on a real toolchain rather than from release notes

GOTOOLCHAIN=auto fetched go1.26.6 and used it:

    go version                 go1.26.6 darwin/amd64  (downloaded on demand)
    go build ./...             exit 0
    go vet ./...               exit 0
    go test ./...              exit 0  (all packages ok)
    govulncheck ./...          exit 0  "No vulnerabilities found."

Counterfactual, so the bump is demonstrably what fixed it rather than something
incidental — reverted the single line and re-ran the same binary:

    toolchain go1.26.5  ->  exit 3, 4 vulnerabilities (the four above)
    toolchain go1.26.6  ->  exit 0, none

Exit codes read explicitly: govulncheck exits 3 on findings, so "looks clean"
in the output is not the same as passing.

## What is NOT in this PR

Making `govulncheck` a required status check. It is red-on-main today and the
prod promotion merged straight past it, which is the actual defect — filed as
backend#1972. It must be armed only AFTER this reaches `main`: adding the
context while main is still on go1.26.5 would block every release-train
promotion on the branch the train has to merge into.

Fix first, arm second.
@LukasWodka LukasWodka self-assigned this Aug 14, 2026
The version-bump gate caught what I left out: v0.10.6 is already released, and
this PR changes `go.mod` — a published path — so the binary the train ships
would differ from the one v0.10.6 tagged.

The gate's own wording is the reason this matters: the train reads VERSION and
cuts the tag from it, never bumping for you, so a stale file does not fail here
— it fails the next prod hop, days later, on somebody else (backend#1561).

Patch bump: stdlib security fixes via go1.26.6, no behaviour or API change.
@LukasWodka
LukasWodka merged commit 91c517b into develop Aug 14, 2026
26 checks passed
@LukasWodka
LukasWodka deleted the sec/1971-go-1-26-6 branch August 14, 2026 09:32
LukasWodka added a commit that referenced this pull request Aug 14, 2026
…hat keeps it (backend#1972) (#501)

* ci(vulncheck): one declaration for the govulncheck pin, and a check that keeps it (backend#1972)

The version lived in THREE places -- build.yml's job, vulncheck.yml's job, and
GOVULNCHECK_VERSION in the Makefile -- held in step by a comment reading "keep the
job in lockstep". All three happened to read v1.1.4, which is exactly what made it
look fine. Two copies kept in sync by a request is not a mechanism.

Both workflows now run `make vulncheck`, so the Makefile is the single
declaration, and a green `make ci` locally cannot disagree with the PR gate about
which govulncheck ran -- the same reasoning already applied to
lint-full/GOLANGCI_LINT_VERSION.

The "keep in lockstep" comment is replaced by a machine check rather than deleted:
scripts/check-tool-pins.sh PARSES GOVULNCHECK_VERSION out of the Makefile and
fails the Lint job if any workflow hardcodes that module with an @Version. The
guard holds no version of its own, so it cannot agree with itself while
disagreeing with reality.

Mutation-proved, anchors asserted:
  reintroduce `go install ...govulncheck@v1.1.4` in build.yml   -> exit 1, names
                                                                  file and line
  delete GOVULNCHECK_VERSION from the Makefile                 -> exit 2, refuses
                                                                  to report clean
  run from an unrelated cwd                                    -> still correct
                                                                  (cd's to its root)

The two jobs still differ, deliberately, and now ONLY in the ref: vulncheck.yml
checks out develop on a schedule, build.yml judges the PR head. That difference is
stated in the file instead of being buried in duplicated steps.

DRAFT until cli#500 lands. `govulncheck` is already red on develop -- go1.26.5
carries 4 reachable stdlib CVEs -- so this branch inherits that failure. Verified
locally that the folded target reproduces it exactly:

  make vulncheck -> exit status 3, "affected by 4 vulnerabilities from the Go
  standard library", each "Fixed in: <pkg>@go1.26.6"

which also independently confirms backend#1972's counterfactual. This PR does not
change WHAT govulncheck finds, only where its version is declared.

NOT in this PR, and both belong to the ticket rather than here: adding govulncheck
to `main`'s required contexts (needs #500 on main first, plus the break-glass
decision -- enforce_admins is true there and skip-fr-gate does not bypass a
required check), and the same three-copies shape for GOLANGCI_LINT_VERSION, which
TOOLS in the new guard is structured to take as a second row.

The two actionlint SC2001 findings on build.yml are pre-existing on develop
(verified against the unmodified base) and untouched here.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* ci(vulncheck): run the pin guard in make ci/check + fail it closed on grep errors

Two Bugbot findings on the govulncheck single-declaration change (backend#1972):

- check-tool-pins ran only in the CI Lint job, so a green local `make ci` /
  `make check` could disagree with the PR about a restated pin — the exact
  local/CI divergence the Makefile-as-entry-point exists to prevent. Add it to
  both aggregate targets, beside check-style/file-budget.
- The workflow scan used `grep ... 2>/dev/null || true`, laundering a real grep
  error (rc>=2: unreadable tree, bad invocation) into an empty hit list and an
  unearned clean pass — the fail-open this guard was written against. Capture rc
  and fail closed on rc>=2, matching scan() in check-style.sh.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
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.

2 participants