Skip to content

Upgrade to Go 1.27.2 and build a static image - #523

Merged
sethterashima merged 2 commits into
teslamotors:mainfrom
Thanatos9404:fix/522-go-toolchain-and-base-image
Oct 20, 2026
Merged

sethterashima merged 2 commits into
teslamotors:mainfrom
Thanatos9404:fix/522-go-toolchain-and-base-image

Conversation

@Thanatos9404

Copy link
Copy Markdown

Description

Fixes #522

The release image is built FROM golang:1.23.0. Go 1.23 is end of life and 1.23.0 has none of the 1.23.x security fixes, and the runtime base (distroless/base-debian12) brings in glibc and libssl3. This PR:

  • builds with golang:1.27.2 and uses the same version in CI (setup-go), plus the README "tested with" line, following upgrade to golang v1.23.0 #306;
  • builds the binaries with CGO_ENABLED=0 and runs them on gcr.io/distroless/static-debian12:nonroot, so the image no longer contains glibc or OpenSSL. The entrypoint, the nonroot user, the set of binaries in /usr/local/bin and the Debian release are unchanged;
  • moves golangci-lint from v1.61.0 to v2.14.0 (separate commit), because v1 cannot run on the new toolchain.

Why the lint change is needed

With Go 1.27.2 on the PATH, golangci-lint v1.61.0 stops before linting anything:

can't run linter goanalysis_metalinter: buildir: failed to load package goarch:
could not load export data: internal error in importing "internal/goarch" (unsupported version: 5)

v1 is no longer maintained (the last release is v1.64.8), so the first commit moves to golangci-lint v2.14.0 (the first release with Go 1.27 support was v2.13.0) and golangci-lint-action@v9. I kept the same checks as before:

  • .golangci.yml is converted to the v2 format. gosimple is now part of staticcheck, so staticcheck is limited to S1* and SA*, the checks that ran before (no quickfix or stylecheck). examples stays excluded, as it was by the v1 default, with the path pattern (^|/)examples/ (v2 matches exclusion paths against file paths, so a bare examples$ would not match anything).
  • No exclusion presets are enabled, which is what --exclude-use-default=false did. That flag no longer exists, so it is removed from the Makefile.
  • The ECDH deprecation exclusion is updated for the newer staticcheck message wording ((crypto/elliptic.Curve).ScalarMult has been deprecated since Go 1.21: ...).
  • The newer revive also checks if/else chains directly inside switch cases, and reports four indent-error-flow findings. I fixed them by dropping the else after return in pkg/protocol/key.go (LoadPublicKey) and in charging-schedule-remove / precondition-schedule-remove in cmd/tesla-control/commands.go. Behaviour does not change.

The first commit also passes lint on its own with Go 1.23.0, so the two commits can be reviewed or reverted separately.

Why CGO_ENABLED=0 is safe here

  • Nothing in the repository uses cgo. With GOOS=linux and cgo enabled, the only packages that have cgo files are runtime/cgo, net and os/user from the standard library, and they fall back to their pure Go versions. For DNS this is what already happens on Linux with distroless's hosts: files dns.
  • go-ble on Linux uses raw HCI sockets through x/sys, and the Linux keyring backends (file, keyctl, secret-service, kwallet, pass) are pure Go.
  • It also avoids a glibc mismatch. golang:1.27.2 is now the Debian 13 (trixie) image, so a cgo build would link against a newer glibc than the Debian 12 runtime provides. Pinning golang:1.27.2-bookworm would be the alternative if you want to keep cgo.
  • golang:1.27.2 and distroless/static-debian12:nonroot are both published for linux/amd64, linux/arm64 and linux/arm/v7, the platforms in publish.yml.

What this PR does not change

  • The go directive stays at go 1.23. Raising it to 1.27, as the issue suggests, would force every program that imports this module onto Go 1.27, and it does not affect the image, because the toolchain there is pinned by the Dockerfile. It would also break golangci-lint builds older than the target Go version. If you would rather raise it, or add a toolchain go1.27.2 line so that go install .../cmd/...@latest on an older Go picks up a patched toolchain, I can add that.
  • The golang.org/x/* modules are not bumped. None of the findings in 0.4.1 image built with EOL Go 1.23.0 and outdated libssl3 (2 CRITICAL incl. CVE-2025-68121, 30+ HIGH) #522 come from them. govulncheck reports one module-level advisory, GO-2026-5024 (CVE-2026-39824, rated low): x/sys/windows.NewNTUnicodeString, Windows only and not called by this code. The fix (x/sys v0.44.0) needs go 1.25.0 in go.mod, so I left it for a separate change.
  • I kept Debian 12 (static-debian12) to match the current image. static-debian13 also works if you prefer to move now.

Type of change

Please select all options that apply to this change:

  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Bug fix (non-breaking change which fixes an issue)
  • Documentation update

Checklist:

Confirm you have completed the following steps:

  • My code follows the style of this project.
  • I have performed a self-review of my code.
  • I have made corresponding updates to the documentation.
  • I have added/updated unit tests to cover my changes.

No new tests: nothing about the behaviour changes, and the existing tests are run below on both platforms.

Testing

With Go 1.27.2:

  • go build ./..., go vet ./... and go test ./... pass on Windows. go mod tidy leaves go.mod and go.sum unchanged, and gofmt -l . is clean.
  • CGO_ENABLED=0 go build ./... succeeds for linux/amd64, linux/arm64 and linux/arm (GOARM=7). go vet is clean for linux/amd64 and linux/arm.
  • The test binaries for all 12 packages with tests, built for linux/amd64 with CGO_ENABLED=0, pass on Linux (WSL2, kernel 6.6).
  • golangci-lint v2.14.0 reports 0 issues with the new config, with GOOS=linux as well, and with --max-same-issues=0 --max-issues-per-linter=0. golangci-lint v1.61.0 built with Go 1.23 still reports 0 issues on the old config with the code changes.
  • Smoke test of the static linux/amd64 binaries on Linux, using an empty environment plus the variables from docker-compose.yml. tesla-http-proxy starts, negotiates TLS 1.3 / HTTP/2, and returns the same 403 {"error":"client did not provide an OAuth token"} for an unauthenticated command as a Go 1.23.0 build. tesla-keygen -key-file ... create writes a key, and tesla-control, tesla-jws and tesla-auth-token start.

govulncheck v1.9.0 (DB 2026-10-08), binary mode, linux/amd64:

binary Go 1.23.0 (current) Go 1.27.2 (this PR)
tesla-http-proxy 41 stdlib vulnerabilities none
tesla-control, tesla-keygen, tesla-jws, tesla-auth-token 40 each none

The 41 include GO-2026-4337 / CVE-2025-68121 (crypto/tls, the CRITICAL one in the issue) and the crypto/x509, net/http and net/url advisories. In source mode with Go 1.27.2 the only remaining result is the Windows-only x/sys advisory above, which is not called.

Not tested:

  • I did not build the Docker image (no Docker on this machine), so the multi-platform buildx build and the Trivy scan in the issue still need to run. The binaries were built with the same command and flags as the Dockerfile.
  • No real vehicle or Fleet API traffic, and no BLE hardware.
  • The lint run used golangci-lint v2.14.0 built from source with Go 1.27.2, not the release binary the action downloads.

golangci-lint v1 cannot load packages compiled by newer Go releases
(with Go 1.27 it fails with "could not load export data ...
unsupported version"), so it has to move to v2 before the Go toolchain
can be upgraded.

Migrate .golangci.yml to the v2 format and keep the same checks:

* gosimple is now part of staticcheck, so staticcheck is limited to
  the S1 and SA checks that ran before.
* The ECDH deprecation exclusion is updated for the newer staticcheck
  message wording.
* No exclusion presets are enabled, which matches what
  --exclude-use-default=false did. That flag no longer exists, so it
  is dropped from the Makefile.

The newer revive also checks if/else chains directly inside switch
cases. Drop the else after return in the four places it reports.
The release image is built with Go 1.23.0, which is past end of life
and is missing every 1.23.x security fix. govulncheck reports 41
standard library vulnerabilities in tesla-http-proxy built that way,
including crypto/tls, crypto/x509 and net/http issues. Build with Go
1.27.2 instead and use the same version in CI.

None of the binaries need cgo, so build them with CGO_ENABLED=0 and
run them on distroless/static-debian12. This removes glibc and OpenSSL
(libssl3) from the image. It also avoids a glibc mismatch: the golang
images are now based on Debian 13, while the runtime image is Debian
12.

The go directive in go.mod stays at 1.23, so programs that import this
module are not forced onto a newer Go.

Fixes teslamotors#522
@sethterashima
sethterashima merged commit 83baa07 into teslamotors:main Oct 20, 2026
1 check passed
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.

0.4.1 image built with EOL Go 1.23.0 and outdated libssl3 (2 CRITICAL incl. CVE-2025-68121, 30+ HIGH)

2 participants