From 7c3f4c825c335534b2bf8da193cc2e025b32db80 Mon Sep 17 00:00:00 2001 From: korya <148461+korya@users.noreply.github.com> Date: Mon, 10 Aug 2026 16:31:05 -0400 Subject: [PATCH 1/3] chore(go): Raise the module to Go 1.26 and pin the build toolchain Go supports a release until two newer ones exist, and go1.27rc2 is already published -- so 1.25 stops receiving security backports the moment 1.27 ships. 1.26 is the line to be on. The version arrives as two directives rather than one because they answer different questions. `go 1.26` is the minimum this module supports, a policy that moves on Go's EOL schedule. `toolchain go1.26.5` is what builds it, and it names an exact patch because .goreleaser.yaml goes out of its way to make builds reproducible -- -trimpath and mod_timestamp exist so that two builds of one commit produce one checksum, and the toolchain version is stamped into the binary, so a compiler free to drift would undo that. The directive is a floor rather than a ceiling: a machine with a newer Go runs that instead. Releases are exact anyway, because setup-go installs the version the directive names and then sets GOTOOLCHAIN=local, which disables switching altogether -- so the guarantee arrives with the bump to setup-go v6 or newer (#67), and until then a release build tracks the newest 1.26 patch. Until now a single `go 1.25.5` served both roles, which is why a gosec release requiring go1.25.8 could redden CI: the workflows install the version go.mod names, so the project's declared minimum was also its build toolchain, and a third party's Go floor could move it. Separating the two ends that coupling. `go install` now requires Go 1.26. Released binaries are unaffected. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01CrknafJSP5hF8u865cbnqX --- go.mod | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index ce0ac35..9fd1be7 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,8 @@ module github.com/korya/http-assert -go 1.25.5 +go 1.26 + +toolchain go1.26.5 require ( github.com/itchyny/gojq v0.12.19 From dced593d34ebe526dced73d0213ab2b7ae7b38a7 Mon Sep 17 00:00:00 2001 From: korya <148461+korya@users.noreply.github.com> Date: Mon, 10 Aug 2026 16:31:05 -0400 Subject: [PATCH 2/3] chore(ci): Report when the pinned Go toolchain trails its patch line Pinning `toolchain` in go.mod keeps builds reproducible, and gives up the automatic patch upgrade that GOTOOLCHAIN=auto used to perform. Every Go patch release carries security fixes, and nothing in this repository bumps the pin, so without a signal it would sit at whatever version last looked current -- which is the failure this pin was introduced to make impossible, in a slower form. The check warns and exits zero. A new Go patch is not a defect here, and a red build every six weeks would teach everyone to skip past it; a warning arrives at the same moment and survives being ignored once. An unreachable go.dev skips the check rather than failing or claiming the pin is current. It lives in the Justfile because CI and a developer's machine should be running one implementation, which is already true of every other check here. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01CrknafJSP5hF8u865cbnqX --- .github/workflows/build.yml | 6 ++++++ Justfile | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 487f3ef..56e6b8e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -27,6 +27,12 @@ jobs: - name: Install just uses: extractions/setup-just@v4 + # The pin in go.mod cannot upgrade itself, and every Go patch release + # carries security fixes. This reports drift; it does not fail the build, + # because a new Go patch is not a defect in this repository. + - name: Check the pinned Go toolchain is current + run: just toolchain-check + - name: Install golangci-lint uses: golangci/golangci-lint-action@v9 with: diff --git a/Justfile b/Justfile index 51615da..db9fb51 100644 --- a/Justfile +++ b/Justfile @@ -46,6 +46,42 @@ lint-config-check: fi done +[doc("Warn if the pinned toolchain has fallen behind its patch line")] +toolchain-check: + #!/usr/bin/env bash + # `toolchain` in go.mod buys reproducible builds -- the Go version is + # stamped into the binary, so a floating compiler changes the checksum that + # -trimpath and mod_timestamp exist to keep stable. What it costs is the + # automatic patch upgrade GOTOOLCHAIN=auto used to perform, and every Go + # patch release carries security fixes. Nothing else bumps the pin, so this + # says when it has fallen behind. + # + # It warns rather than fails. A new Go patch is not a defect in this + # repository, and a red build every six weeks teaches everyone to ignore it. + set -uo pipefail + pinned=$(sed -n 's/^toolchain go//p' go.mod) + if [ -z "$pinned" ]; then + echo "go.mod has no toolchain directive; nothing to check" + exit 0 + fi + minor=${pinned%.*} + latest=$(curl -fsS --max-time 10 "https://go.dev/dl/?mode=json&include=all" \ + | grep -oE "\"go${minor//./\\.}(\.[0-9]+)?\"" | tr -d '"' | sed 's/^go//' \ + | sort -uV | tail -1) + # An unreachable go.dev is not a reason to fail a build that is otherwise + # fine, and not a reason to claim the pin is current either. + if [ -z "$latest" ]; then + echo "could not read the Go release list; skipped the freshness check" >&2 + exit 0 + fi + if [ "$pinned" = "$latest" ]; then + echo "toolchain go${pinned} is the current ${minor} patch" + exit 0 + fi + msg="toolchain go${pinned} trails go${latest}; Go patch releases carry security fixes" + [ -n "${GITHUB_ACTIONS:-}" ] && echo "::warning file=go.mod::${msg}" + echo "$msg" >&2 + [doc("Run go vet")] vet: go vet ./... From 167f45acb6c91392ba2c020e4da34cc4460e69f9 Mon Sep 17 00:00:00 2001 From: korya <148461+korya@users.noreply.github.com> Date: Mon, 10 Aug 2026 16:31:05 -0400 Subject: [PATCH 3/3] docs(readme): State the Go requirement for a source build The README sent readers to `go install` without saying what it needs, which was survivable while the requirement was whatever Go they already had and is not now that the module asks for 1.26. The note also says what the release binaries need, because "requires Go" next to an install command reads as a requirement of the tool rather than of one way to obtain it. The --version sample said go1.25.5, which the toolchain pin has just made untrue of anything built from this commit. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01CrknafJSP5hF8u865cbnqX --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 87ac62b..c3590e5 100644 --- a/README.md +++ b/README.md @@ -116,6 +116,8 @@ http-assert completion zsh --help # per-shell install instructions ### From Source +Requires Go 1.26 or newer. A release binary needs no Go toolchain at all. + ```bash go install github.com/korya/http-assert@latest ``` @@ -411,7 +413,7 @@ tool logs at the warn level. ```console $ http-assert --version -http-assert version v0.1.0 (commit 4ffe282, built 2026-08-07T22:24:59Z, go1.25.5, linux/amd64) +http-assert version v0.1.0 (commit 4ffe282, built 2026-08-07T22:24:59Z, go1.26.5, linux/amd64) ``` A binary built from a checkout rather than a release reports the commit it was