From 1b8513bdb69ff638c34431a3dd959943c373bbdb Mon Sep 17 00:00:00 2001 From: Dean Sheather Date: Mon, 12 Jan 2026 16:33:20 +0000 Subject: [PATCH 1/5] chore: update GitHub Actions and golangci-lint to latest versions - actions/checkout v2/v3 -> v4 - actions/setup-go v3 -> v5 - actions/upload-artifact v2 -> v4 - docker/login-action v2 -> v3 - golangci/golangci-lint-action v3.2.0 -> v6 - golangci-lint v1.51.0 -> v1.64.8 - jaxxstorm/action-install-gh-release v1.7.1 -> v2.1.0 - gotestsum v1.9.0 -> v1.12.1 - Go version 1.20 -> 1.22 - Updated .golangci.yaml from coder/coder - Fixed lint warnings in tunneld code --- .github/workflows/release.yaml | 12 ++-- .github/workflows/wgtunnel.yaml | 26 ++++---- .golangci.yaml | 101 ++++++++++++++++++-------------- cmd/tunneld/main.go | 2 +- tunneld/api.go | 4 +- tunneld/options.go | 2 +- tunneld/tunneld.go | 2 +- 7 files changed, 80 insertions(+), 69 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 3799e33..5fcca17 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -27,7 +27,7 @@ jobs: release: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 @@ -40,15 +40,15 @@ jobs: run: git fetch --tags --force - name: Docker Login - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - uses: actions/setup-go@v3 + - uses: actions/setup-go@v5 with: - go-version: "~1.20" + go-version: "~1.22" - name: Build tunneld and Docker images id: build @@ -65,7 +65,7 @@ jobs: exit 1 fi - echo "docker_tag=${image_tag}" >> $GITHUB_OUTPUT + echo "docker_tag=${image_tag}" >> "$GITHUB_OUTPUT" - name: Push Docker image if: ${{ !github.event.inputs.dry_run && !github.event.inputs.snapshot }} @@ -92,7 +92,7 @@ jobs: - name: Upload artifacts to actions (if dry-run or snapshot) if: ${{ github.event.inputs.dry_run || github.event.inputs.snapshot }} - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: release-artifacts path: | diff --git a/.github/workflows/wgtunnel.yaml b/.github/workflows/wgtunnel.yaml index c1406dc..5181df7 100644 --- a/.github/workflows/wgtunnel.yaml +++ b/.github/workflows/wgtunnel.yaml @@ -30,11 +30,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Setup Go - uses: actions/setup-go@v3 + uses: actions/setup-go@v5 with: - go-version: "~1.20" + go-version: "~1.22" - name: Check for unstaged files run: ./scripts/check_unstaged.sh @@ -42,31 +42,31 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Setup Go - uses: actions/setup-go@v3 + uses: actions/setup-go@v5 with: - go-version: "~1.20" + go-version: "~1.22" - name: golangci-lint - uses: golangci/golangci-lint-action@v3.2.0 + uses: golangci/golangci-lint-action@v6 with: - version: v1.51.0 + version: v1.64.8 test: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Setup Go - uses: actions/setup-go@v3 + uses: actions/setup-go@v5 with: - go-version: "~1.20" + go-version: "~1.22" - name: Install gotestsum - uses: jaxxstorm/action-install-gh-release@v1.7.1 + uses: jaxxstorm/action-install-gh-release@v2.1.0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: repo: gotestyourself/gotestsum - tag: v1.9.0 + tag: v1.12.1 - name: Test run: make test diff --git a/.golangci.yaml b/.golangci.yaml index 20bdc5e..fa70ea5 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -1,11 +1,14 @@ -# This is copied from github.com/coder/coder. -# -# Changes: -# - removed ruleguard +# See https://golangci-lint.run/usage/configuration/ +# Over time we should try tightening some of these. linters-settings: + dupl: + # goal: 100 + threshold: 412 + + gocognit: - min-complexity: 46 # Min code complexity (def 30). + min-complexity: 300 goconst: min-len: 4 # Min length of string consts (def 3). @@ -15,30 +18,19 @@ linters-settings: enabled-checks: # - appendAssign # - appendCombine - - argOrder # - assignOp # - badCall - - badCond - badLock - badRegexp - boolExprSimplify # - builtinShadow - builtinShadowDecl - - captLocal - - caseOrder - - codegenComment # - commentedOutCode - commentedOutImport - - commentFormatting - - defaultCaseOrder - deferUnlambda # - deprecatedComment # - docStub - - dupArg - - dupBranchBody - - dupCase - dupImport - - dupSubExpr # - elseif - emptyFallthrough # - emptyStringTest @@ -47,8 +39,6 @@ linters-settings: # - exitAfterDefer # - exposedSyncMutex # - filepathJoin - - flagDeref - - flagName - hexLiteral # - httpNoBody # - hugeParam @@ -56,53 +46,42 @@ linters-settings: # - importShadow - indexAlloc - initClause - - ioutilDeprecated - - mapKey - methodExprCall # - nestingReduce - - newDeref - nilValReturn # - octalLiteral - - offBy1 # - paramTypeCombine # - preferStringWriter # - preferWriteByte # - ptrToRefParam # - rangeExprCopy # - rangeValCopy - - regexpMust - regexpPattern # - regexpSimplify # - ruleguard - - singleCaseSwitch - - sloppyLen # - sloppyReassign - - sloppyTypeAssert - sortSlice - sprintfQuotedString - sqlQuery # - stringConcatSimplify # - stringXbytes # - suspiciousSorting - - switchTrue - truncateCmp - typeAssertChain # - typeDefFirst - - typeSwitchVar # - typeUnparen - - underef # - unlabelStmt # - unlambda # - unnamedResult # - unnecessaryBlock # - unnecessaryDefer # - unslice - - valSwap - weakCond # - whyNoLint # - wrapperFunc # - yodaStyleExpr + staticcheck: # https://staticcheck.io/docs/options#checks # We disable SA1019 because it gets angry about our usage of xerrors. We @@ -113,17 +92,17 @@ linters-settings: goimports: local-prefixes: coder.com,cdr.dev,go.coder.com,github.com/cdr,github.com/coder - gocyclo: - min-complexity: 50 - importas: no-unaliased: true misspell: locale: US + ignore-words: + - trialer nestif: - min-complexity: 4 # Min complexity of if statements (def 5, goal 4) + # goal: 10 + min-complexity: 20 revive: # see https://github.com/mgechev/revive#available-rules for details. @@ -163,8 +142,6 @@ linters-settings: - name: modifies-value-receiver - name: package-comments - name: range - - name: range-val-address - - name: range-val-in-closure - name: receiver-naming - name: redefines-builtin-id - name: string-of-int @@ -178,30 +155,58 @@ linters-settings: - name: unnecessary-stmt - name: unreachable-code - name: unused-parameter + exclude: "**/*_test.go" - name: unused-receiver - name: var-declaration - name: var-naming - name: waitgroup-by-value + usetesting: + # Only os-setenv is enabled because we migrated to usetesting from another linter that + # only covered os-setenv. + os-setenv: true + os-create-temp: false + os-mkdir-temp: false + os-temp-dir: false + os-chdir: false + context-background: false + context-todo: false + + # irrelevant as of Go v1.22: https://go.dev/blog/loopvar-preview + govet: + disable: + - loopclosure + gosec: + excludes: + # Implicit memory aliasing of items from a range statement (irrelevant as of Go v1.22) + - G601 issues: + exclude-dirs: + - node_modules + - .git + + exclude-files: + - scripts/rules.go + # Rules listed here: https://github.com/securego/gosec#available-rules exclude-rules: - path: _test\.go linters: # We use assertions rather than explicitly checking errors in tests - errcheck + - forcetypeassert + # - exhaustruct # This is unhelpful in tests. + + - path: scripts/rules.go + linters: + - ALL fix: true max-issues-per-linter: 0 max-same-issues: 0 run: - concurrency: 4 - skip-dirs: - - node_modules - skip-files: - - scripts/rules.go - timeout: 5m + timeout: 10m # Over time, add more and more linters from # https://golangci-lint.run/usage/linters/ as the code improves. @@ -215,10 +220,15 @@ linters: - errcheck - errname - errorlint - - exportloopref + # - exhaustruct - forcetypeassert - gocritic - - gocyclo + # gocyclo is may be useful in the future when we start caring + # about testing complexity, but for the time being we should + # create a good culture around cognitive complexity. + # - gocyclo + - gocognit + - nestif - goimports - gomodguard - gosec @@ -241,7 +251,6 @@ linters: # - wastedassign - staticcheck - - tenv # In Go, it's possible for a package to test it's internal functionality # without testing any exported functions. This is enabled to promote # decomposing a package before testing it's internals. A function caller @@ -254,3 +263,5 @@ linters: - typecheck - unconvert - unused + - usetesting + - dupl diff --git a/cmd/tunneld/main.go b/cmd/tunneld/main.go index f179069..526d04b 100644 --- a/cmd/tunneld/main.go +++ b/cmd/tunneld/main.go @@ -249,7 +249,7 @@ func runApp(ctx *cli.Context) error { options := &tunneld.Options{ BaseURL: baseURLParsed, WireguardEndpoint: wireguardEndpoint, - WireguardPort: uint16(wireguardPort), + WireguardPort: uint16(wireguardPort), //nolint:gosec // validated earlier WireguardKey: wireguardKeyParsed, WireguardMTU: wireguardMTU, WireguardServerIP: wireguardServerIPParsed, diff --git a/tunneld/api.go b/tunneld/api.go index dd1e49c..fd7300d 100644 --- a/tunneld/api.go +++ b/tunneld/api.go @@ -54,7 +54,7 @@ func (api *API) Router() http.Handler { }), ) - apiRouter.Get("/", func(w http.ResponseWriter, r *http.Request) { + apiRouter.Get("/", func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusOK) _, _ = w.Write([]byte("https://coder.com")) }) @@ -254,7 +254,7 @@ func (api *API) handleTunnel(rw http.ResponseWriter, r *http.Request) { rp := httputil.ReverseProxy{ // This can only happen when it fails to dial. - ErrorHandler: func(w http.ResponseWriter, r *http.Request, err error) { + ErrorHandler: func(_ http.ResponseWriter, _ *http.Request, err error) { httpapi.Write(ctx, rw, http.StatusBadGateway, tunnelsdk.Response{ Message: "Failed to dial peer.", Detail: err.Error(), diff --git a/tunneld/options.go b/tunneld/options.go index e67ac20..579c4eb 100644 --- a/tunneld/options.go +++ b/tunneld/options.go @@ -243,6 +243,6 @@ func (options *Options) HostnameToWireguardIP(hostname string) (netip.Addr, erro } addrBytes := options.WireguardNetworkPrefix.Addr().As16() - copy(addrBytes[8:], addrLast8Bytes[:]) + copy(addrBytes[8:], addrLast8Bytes) return netip.AddrFrom16(addrBytes), nil } diff --git a/tunneld/tunneld.go b/tunneld/tunneld.go index 7a4e2cb..6b1560a 100644 --- a/tunneld/tunneld.go +++ b/tunneld/tunneld.go @@ -86,7 +86,7 @@ listen_port=%d`, wgDevice: dev, pkeyCache: make(map[netip.Addr]cachedPeer), transport: &http.Transport{ - DialContext: func(ctx context.Context, network, addr string) (nc net.Conn, err error) { + DialContext: func(ctx context.Context, _, _ string) (nc net.Conn, err error) { ctx, span := otel.GetTracerProvider().Tracer("").Start(ctx, "(http.Transport).DialContext") defer span.End() defer func() { From 5c0b309f37307a293479e3f1a6f9b7a9952360c1 Mon Sep 17 00:00:00 2001 From: Dean Sheather Date: Mon, 12 Jan 2026 16:34:59 +0000 Subject: [PATCH 2/5] chore: pin GitHub Actions to SHA for security --- .github/workflows/release.yaml | 10 +++++----- .github/workflows/wgtunnel.yaml | 16 ++++++++-------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 5fcca17..57d753c 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -27,7 +27,7 @@ jobs: release: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 0 @@ -40,13 +40,13 @@ jobs: run: git fetch --tags --force - name: Docker Login - uses: docker/login-action@v3 + uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - uses: actions/setup-go@v5 + - uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 with: go-version: "~1.22" @@ -84,7 +84,7 @@ jobs: - name: Publish release if: ${{ !github.event.inputs.dry_run && !github.event.inputs.snapshot }} - uses: ncipollo/release-action@v1 + uses: ncipollo/release-action@b7eabc95ff50cbeeedec83973935c8f306dfcd0b # v1.20.0 with: artifacts: "build/tunneld" body: "Docker image: `${{ steps.build.outputs.docker_tag }}`" @@ -92,7 +92,7 @@ jobs: - name: Upload artifacts to actions (if dry-run or snapshot) if: ${{ github.event.inputs.dry_run || github.event.inputs.snapshot }} - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 with: name: release-artifacts path: | diff --git a/.github/workflows/wgtunnel.yaml b/.github/workflows/wgtunnel.yaml index 5181df7..9a973f7 100644 --- a/.github/workflows/wgtunnel.yaml +++ b/.github/workflows/wgtunnel.yaml @@ -30,9 +30,9 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Setup Go - uses: actions/setup-go@v5 + uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 with: go-version: "~1.22" - name: Check for unstaged files @@ -42,13 +42,13 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Setup Go - uses: actions/setup-go@v5 + uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 with: go-version: "~1.22" - name: golangci-lint - uses: golangci/golangci-lint-action@v6 + uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # v9.2.0 with: version: v1.64.8 @@ -56,13 +56,13 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Setup Go - uses: actions/setup-go@v5 + uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 with: go-version: "~1.22" - name: Install gotestsum - uses: jaxxstorm/action-install-gh-release@v2.1.0 + uses: jaxxstorm/action-install-gh-release@6096f2a2bbfee498ced520b6922ac2c06e990ed2 # v2.1.0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: From 00ee3f7fe0b387a3366ccfbbea6e50d939546f69 Mon Sep 17 00:00:00 2001 From: Dean Sheather Date: Mon, 12 Jan 2026 16:37:09 +0000 Subject: [PATCH 3/5] chore: fix zizmor security findings - Add persist-credentials: false to all checkout actions - Disable Go cache in release workflow to prevent cache poisoning - Use env var instead of template expansion for docker tag --- .github/workflows/release.yaml | 6 +++++- .github/workflows/wgtunnel.yaml | 6 ++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 57d753c..56c970e 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -30,6 +30,7 @@ jobs: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 0 + persist-credentials: false # If the event that triggered the build was an annotated tag (which our # tags are supposed to be), actions/checkout has a bug where the tag in @@ -49,6 +50,7 @@ jobs: - uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 with: go-version: "~1.22" + cache: false - name: Build tunneld and Docker images id: build @@ -69,10 +71,12 @@ jobs: - name: Push Docker image if: ${{ !github.event.inputs.dry_run && !github.event.inputs.snapshot }} + env: + DOCKER_TAG: ${{ steps.build.outputs.docker_tag }} run: | set -euxo pipefail - image_tag="${{ steps.build.outputs.docker_tag }}" + image_tag="$DOCKER_TAG" docker push "$image_tag" latest_tag="ghcr.io/coder/wgtunnel/tunneld:latest" diff --git a/.github/workflows/wgtunnel.yaml b/.github/workflows/wgtunnel.yaml index 9a973f7..211c14a 100644 --- a/.github/workflows/wgtunnel.yaml +++ b/.github/workflows/wgtunnel.yaml @@ -31,6 +31,8 @@ jobs: steps: - name: Checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - name: Setup Go uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 with: @@ -43,6 +45,8 @@ jobs: steps: - name: Checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - name: Setup Go uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 with: @@ -57,6 +61,8 @@ jobs: steps: - name: Checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - name: Setup Go uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 with: From d218da349f620c5543da52982312982cac5de6be Mon Sep 17 00:00:00 2001 From: Dean Sheather Date: Mon, 12 Jan 2026 16:40:43 +0000 Subject: [PATCH 4/5] fix: upgrade to tailscale/wireguard-go and Go 1.23 - Switch from golang.zx2c4.com/wireguard to github.com/tailscale/wireguard-go - Use coder/wireguard-go fork with data race fix - Upgrade Go version from 1.20 to 1.23 - Use go run for golangci-lint instead of action --- .github/workflows/release.yaml | 2 +- .github/workflows/wgtunnel.yaml | 10 ++++------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 56c970e..c5d4851 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -49,7 +49,7 @@ jobs: - uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 with: - go-version: "~1.22" + go-version: "~1.23" cache: false - name: Build tunneld and Docker images diff --git a/.github/workflows/wgtunnel.yaml b/.github/workflows/wgtunnel.yaml index 211c14a..bc2df77 100644 --- a/.github/workflows/wgtunnel.yaml +++ b/.github/workflows/wgtunnel.yaml @@ -36,7 +36,7 @@ jobs: - name: Setup Go uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 with: - go-version: "~1.22" + go-version: "~1.23" - name: Check for unstaged files run: ./scripts/check_unstaged.sh @@ -50,11 +50,9 @@ jobs: - name: Setup Go uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 with: - go-version: "~1.22" + go-version: "~1.23" - name: golangci-lint - uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # v9.2.0 - with: - version: v1.64.8 + run: go run github.com/golangci/golangci-lint/cmd/golangci-lint@v1.64.8 run test: runs-on: ubuntu-latest @@ -66,7 +64,7 @@ jobs: - name: Setup Go uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 with: - go-version: "~1.22" + go-version: "~1.23" - name: Install gotestsum uses: jaxxstorm/action-install-gh-release@6096f2a2bbfee498ced520b6922ac2c06e990ed2 # v2.1.0 env: From e6f119cd0f7f427f143f442db35b56aa811c07b1 Mon Sep 17 00:00:00 2001 From: Dean Sheather Date: Mon, 12 Jan 2026 16:49:14 +0000 Subject: [PATCH 5/5] chore: trigger CI