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 ./... 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 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