From 9bbce65a95de29731a99da186aab73fee994e20d Mon Sep 17 00:00:00 2001 From: scttbnsn <80784472+scttbnsn@users.noreply.github.com> Date: Tue, 16 Jun 2026 15:46:53 -0400 Subject: [PATCH] =?UTF-8?q?=F0=9F=94=A7=20chore(security):=20pin=20Go=20to?= =?UTF-8?q?olchain=20to=201.26.4=20as=20CI's=20single=20source=20of=20trut?= =?UTF-8?q?h?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit go.mod declared only `go 1.26.0` (no toolchain directive), so builds and scans floated to whatever 1.26.x a runner installed, and a clean-machine build on 1.26.0 would ship reachable crypto/x509 + net/url CVEs (GO-2026-4599/4600/4601, fixed in 1.26.1). - 🔧 go.mod: add `toolchain go1.26.4` — a floor for every build via GOTOOLCHAIN=auto. - 🔄 all 9 workflows: setup-go `go-version: "1.26"` -> `go-version-file: go.mod` (14 steps), so the pinned toolchain governs build, govulncheck, Grype, and release in lockstep. setup-go honors the toolchain directive over the go line. - 📝 CHANGELOG: document the pin and the one-source-of-truth switch. Verified: go build ./... and govulncheck ./... clean on 1.26.4; actionlint + zizmor clean across all workflows. --- .github/workflows/ci.yml | 12 ++++++------ .github/workflows/quality-bench-monthly.yml | 2 +- .github/workflows/quality-fuzz-monthly.yml | 2 +- .github/workflows/quality-fuzz-nightly.yml | 2 +- .github/workflows/quality-integration.yml | 2 +- .github/workflows/quality-mutation-monthly.yml | 2 +- .github/workflows/quality-soak-weekly.yml | 2 +- .github/workflows/release.yml | 2 +- .github/workflows/security-grype.yml | 9 ++++----- CHANGELOG.md | 1 + go.mod | 2 ++ 11 files changed, 20 insertions(+), 18 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d60f6ea..7bac920 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -40,7 +40,7 @@ jobs: - name: Setup Go uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 with: - go-version: "1.26" + go-version-file: go.mod - name: Verify dependencies run: go mod verify @@ -82,7 +82,7 @@ jobs: - name: Setup Go uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 with: - go-version: "1.26" + go-version-file: go.mod - name: golangci-lint uses: golangci/golangci-lint-action@82606bf257cbaff209d206a39f5134f0cfbfd2ee # v9.2.1 @@ -105,7 +105,7 @@ jobs: - name: Setup Go uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 with: - go-version: "1.26" + go-version-file: go.mod - name: Install govulncheck run: go install golang.org/x/vuln/cmd/govulncheck@v1.2.0 @@ -195,7 +195,7 @@ jobs: - name: Setup Go uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 with: - go-version: "1.26" + go-version-file: go.mod - name: Run GoReleaser check uses: goreleaser/goreleaser-action@5daf1e915a5f0af01ddbcd89a43b8061ff4f1a89 # v7.2.2 @@ -239,7 +239,7 @@ jobs: - name: Setup Go uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 with: - go-version: "1.26" + go-version-file: go.mod - name: Build Go run: go build ./... @@ -305,7 +305,7 @@ jobs: - name: Setup Go uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 with: - go-version: "1.26" + go-version-file: go.mod - name: Fuzz ${{ matrix.fuzzer.name }} env: diff --git a/.github/workflows/quality-bench-monthly.yml b/.github/workflows/quality-bench-monthly.yml index ccdba06..035f3a8 100644 --- a/.github/workflows/quality-bench-monthly.yml +++ b/.github/workflows/quality-bench-monthly.yml @@ -47,7 +47,7 @@ jobs: - name: Setup Go uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 with: - go-version: "1.26" + go-version-file: go.mod - name: Run benchmarks run: | diff --git a/.github/workflows/quality-fuzz-monthly.yml b/.github/workflows/quality-fuzz-monthly.yml index 5b7d979..6c2d189 100644 --- a/.github/workflows/quality-fuzz-monthly.yml +++ b/.github/workflows/quality-fuzz-monthly.yml @@ -67,7 +67,7 @@ jobs: - name: Setup Go uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 with: - go-version: "1.26" + go-version-file: go.mod - name: Resolve fuzz budget id: budget diff --git a/.github/workflows/quality-fuzz-nightly.yml b/.github/workflows/quality-fuzz-nightly.yml index f98fa3a..3b884c8 100644 --- a/.github/workflows/quality-fuzz-nightly.yml +++ b/.github/workflows/quality-fuzz-nightly.yml @@ -57,7 +57,7 @@ jobs: - name: Setup Go uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 with: - go-version: "1.26" + go-version-file: go.mod - name: Resolve fuzz budget id: budget diff --git a/.github/workflows/quality-integration.yml b/.github/workflows/quality-integration.yml index 4fb283a..2920912 100644 --- a/.github/workflows/quality-integration.yml +++ b/.github/workflows/quality-integration.yml @@ -53,7 +53,7 @@ jobs: - name: Setup Go uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 with: - go-version: "1.26" + go-version-file: go.mod - name: Verify Docker daemon is reachable run: | diff --git a/.github/workflows/quality-mutation-monthly.yml b/.github/workflows/quality-mutation-monthly.yml index 8b2c237..85f5fcf 100644 --- a/.github/workflows/quality-mutation-monthly.yml +++ b/.github/workflows/quality-mutation-monthly.yml @@ -59,7 +59,7 @@ jobs: - name: Setup Go uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 with: - go-version: "1.26" + go-version-file: go.mod - name: Install Gremlins run: go install github.com/go-gremlins/gremlins/cmd/gremlins@"${GREMLINS_VERSION}" diff --git a/.github/workflows/quality-soak-weekly.yml b/.github/workflows/quality-soak-weekly.yml index ec90bf6..27ce0e8 100644 --- a/.github/workflows/quality-soak-weekly.yml +++ b/.github/workflows/quality-soak-weekly.yml @@ -65,7 +65,7 @@ jobs: - name: Setup Go uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 with: - go-version: "1.26" + go-version-file: go.mod - name: Resolve soak parameters id: params diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 98f3fa2..aef8454 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -38,7 +38,7 @@ jobs: - name: Setup Go uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 with: - go-version: "1.26" + go-version-file: go.mod - name: Install cosign uses: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6 # v4.1.2 diff --git a/.github/workflows/security-grype.yml b/.github/workflows/security-grype.yml index bc8175c..0110bf5 100644 --- a/.github/workflows/security-grype.yml +++ b/.github/workflows/security-grype.yml @@ -54,11 +54,10 @@ jobs: - name: Setup Go uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 with: - # go.mod declares only the language version (`go 1.26.0`) with no - # `toolchain` directive, so go-version-file would pin govulncheck to - # 1.26.0 and report stdlib advisories already fixed in 1.26.1+. Track - # the latest 1.26.x like the build and the gating ci.yml scan do. - go-version: "1.26" + # Reads the `toolchain go1.26.4` directive from go.mod (setup-go honors + # toolchain over the `go` line), so the scan runs on the same pinned, + # patched toolchain the binary is built with — one source of truth. + go-version-file: go.mod - name: Install govulncheck run: go install "golang.org/x/vuln/cmd/govulncheck@${GOVULNCHECK_VERSION}" diff --git a/CHANGELOG.md b/CHANGELOG.md index a91d1cd..5dad4af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - **Standardized dependency/CVE scanning on Grype + govulncheck; Snyk stays off Portwing.** Snyk's GitHub SCM integration scans the full Go *module requirement graph* (`go mod graph`) instead of the compiled build graph, so it flags advisories in modules that transitive deps merely *require* but the binary never links in (nothing in `go list -deps ./...`, nothing reachable per govulncheck, clean under Grype). That's a methodology gap, not staleness, so it's being decommissioned org-wide. Portwing never wired Snyk into the repo (no `.snyk` policy, no workflow step, no README badge), so there was nothing to strip out on the repo side. govulncheck (Go call-graph reachability) and Grype (the built image's binary build-info, plus `go.mod`/`go.sum` and the npm lockfiles) already cover dependencies accurately. The existing weekly scan is consolidated into `security-grype.yml`, which now also runs on pull requests (path-filtered to source/deps/Dockerfile/the workflow itself), keeps the weekly cron and manual dispatch, guards the heavy container build off PRs (govulncheck plus the dependency scan give fast PR coverage), gives each scanner a distinct code-scanning `category` so the Grype image and dependency SARIF no longer clobber each other in the Security tab, and runs gosec in report-only mode (`-no-fail`) so its heuristic findings still feed the Security tab without gating the build (CodeQL, Grype, and govulncheck handle the gating). +- **Pinned the Go toolchain to `go1.26.4` and made it the single source of truth for CI.** `go.mod` now carries a `toolchain go1.26.4` directive (it previously declared only `go 1.26.0`), so every build — local, CI, and release — runs on a stdlib past the reachable `crypto/x509` / `net/url` advisories (GO-2026-4599/4600/4601, fixed in 1.26.1) instead of whatever 1.26.x a runner happened to install. Every workflow's `setup-go` step switched from the floating `go-version: "1.26"` to `go-version-file: go.mod`, so the pin now governs the build, the govulncheck/Grype scans, and the release in lockstep — bump the toolchain in one place to move them all. `govulncheck ./...` is clean on 1.26.4. ## [0.3.0] - 2026-06-15 diff --git a/go.mod b/go.mod index e2e06f8..a14bda1 100644 --- a/go.mod +++ b/go.mod @@ -2,6 +2,8 @@ module github.com/codeswhat/portwing go 1.26.0 +toolchain go1.26.4 + require ( github.com/google/uuid v1.6.0 github.com/gorilla/websocket v1.5.3