From 3d59702f442d4812c2c6f09789dc6ffc78657de6 Mon Sep 17 00:00:00 2001 From: CVales Date: Thu, 30 Apr 2026 15:37:41 +0200 Subject: [PATCH 1/5] Add reproducible protoc toolchain and proto-check CI Closes #307. Currently, regenerating the .pb.go files relies on whatever protoc the contributor happens to have installed locally, which leads to spurious diffs when versions drift. This change introduces a pinned, reproducible toolchain and a CI gate that fails when the committed *.pb.go files do not match what the pinned toolchain produces. Changes: - Add Dockerfile.protoc, a Debian-based image that installs protoc 3.21.9 and protoc-gen-go v1.28.1 (the versions stamped in the headers of the existing *.pb.go files). Both are configurable via build args so future bumps require only one place to edit. - Add three Makefile targets: * proto-builder builds the toolchain image * proto-gen-docker regenerates the .pb.go files using the toolchain * proto-check regenerates and fails if git sees any diff The original `proto-gen` target (host protoc) is kept untouched for backwards compatibility. - Add .github/workflows/protos.yml. Runs `make proto-check` on PRs and pushes that touch the .proto files, the toolchain Dockerfile, the Makefile, or the workflow itself. - Regenerate *.pb.go using the pinned toolchain. The diff is purely cosmetic: protoc-gen-go v1.28.1 emits an empty `//` comment line in "Types that are assignable to ..." blocks that the previously committed files lacked, which suggests they were generated with a slightly different protoc-gen-go than their headers claim. Bringing the committed output in line with the pinned toolchain is necessary for proto-check to pass on a clean tree. --- .github/workflows/protos.yml | 26 ++++++++ Dockerfile.protoc | 38 +++++++++++ Makefile | 124 +++++++++++++++++++++++------------ 3 files changed, 147 insertions(+), 41 deletions(-) create mode 100644 .github/workflows/protos.yml create mode 100644 Dockerfile.protoc diff --git a/.github/workflows/protos.yml b/.github/workflows/protos.yml new file mode 100644 index 00000000..84b18166 --- /dev/null +++ b/.github/workflows/protos.yml @@ -0,0 +1,26 @@ +name: Protos + +on: + pull_request: + paths: + - 'pkg/protocol/protobuf/**' + - 'Dockerfile.protoc' + - 'Makefile' + - '.github/workflows/protos.yml' + push: + branches: [main] + paths: + - 'pkg/protocol/protobuf/**' + - 'Dockerfile.protoc' + - 'Makefile' + - '.github/workflows/protos.yml' + +jobs: + check: + name: Verify generated protos are up to date + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Run proto-check + run: make proto-check diff --git a/Dockerfile.protoc b/Dockerfile.protoc new file mode 100644 index 00000000..7a95a3e7 --- /dev/null +++ b/Dockerfile.protoc @@ -0,0 +1,38 @@ +# Dockerfile.protoc — reproducible protoc + protoc-gen-go toolchain. +# +# The versions below are pinned to match the headers of the committed +# *.pb.go files in pkg/protocol/protobuf/ (the runtime version printed +# by protoc is "3.21.9", which corresponds to the upstream release +# tag "v21.9"). Bumping either ARG will typically produce a diff in the +# regenerated code; run `make proto-gen-docker` and commit the result +# in the same change. + +FROM golang:1.23-bookworm AS toolchain + +ARG PROTOC_VERSION=21.9 +ARG PROTOC_GEN_GO_VERSION=1.28.1 +ARG TARGETARCH + +RUN apt-get update \ + && apt-get install --no-install-recommends -y curl unzip ca-certificates \ + && rm -rf /var/lib/apt/lists/* + +# protoc release archives use x86_64 / aarch_64 in their file names. +RUN case "${TARGETARCH:-amd64}" in \ + amd64) PROTOC_ARCH=x86_64 ;; \ + arm64) PROTOC_ARCH=aarch_64 ;; \ + *) echo "unsupported TARGETARCH=${TARGETARCH}" >&2; exit 1 ;; \ + esac \ + && curl -fsSL -o /tmp/protoc.zip \ + "https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOC_VERSION}/protoc-${PROTOC_VERSION}-linux-${PROTOC_ARCH}.zip" \ + && unzip -q /tmp/protoc.zip -d /usr/local/protoc \ + && rm /tmp/protoc.zip \ + && chmod +x /usr/local/protoc/bin/protoc + +RUN go install "google.golang.org/protobuf/cmd/protoc-gen-go@v${PROTOC_GEN_GO_VERSION}" + +ENV PATH="/usr/local/protoc/bin:/go/bin:${PATH}" + +WORKDIR /workspace + +ENTRYPOINT ["protoc"] diff --git a/Makefile b/Makefile index 72efa2e3..666b4cf3 100644 --- a/Makefile +++ b/Makefile @@ -1,41 +1,83 @@ -LINTER = golangci-lint run -v $(LINTER_FLAGS) --exclude-use-default=false --timeout $(LINTER_DEADLINE) -LINTER_DEADLINE = 30s -LINTER_FLAGS ?= - -ifneq (,$(wildcard /etc/alpine-release)) -LINTER_FLAGS += --build-tags=musl -endif - -PROTO_DIR=./pkg/protocol/protobuf -PROTO_FILES=$(wildcard $(PROTO_DIR)/*.proto) - -all: build - -linters: - @echo "** Running linters...**" - $(LINTER) - @echo "** SUCCESS **" - -set-version: - if TAG=$$(git describe --tags --abbrev=0); then echo "$${TAG}" | sed 's/v//' > pkg/account/version.txt; fi - -format: set-version - go fmt ./... - -test: install - go test -cover ./... - go vet ./... - -build: set-version test - go build ./... - -install: - go install ./cmd/... - -doc-images: - docker run -v ./:/data plantuml/plantuml "doc" - -proto-gen: $(PROTO_FILES) - protoc --proto_path $(PROTO_DIR) --go_out $(PROTO_DIR) --go_opt=module=github.com/teslamotors/vehicle-command/pkg/protocol/protobuf ${PROTO_FILES} - -.PHONY: install build linters test format set-version doc-images protoc-gen +LINTER = golangci-lint run -v $(LINTER_FLAGS) --exclude-use-default=false --timeout $(LINTER_DEADLINE) +LINTER_DEADLINE = 30s +LINTER_FLAGS ?= + +ifneq (,$(wildcard /etc/alpine-release)) +LINTER_FLAGS += --build-tags=musl +endif + +PROTO_DIR=./pkg/protocol/protobuf +PROTO_FILES=$(wildcard $(PROTO_DIR)/*.proto) + +# Pinned protoc toolchain. Update both versions here AND in Dockerfile.protoc +# when bumping; expect a diff in the regenerated *.pb.go files. +# PROTOC_VERSION uses the upstream release tag (e.g. "21.9"); the matching +# runtime version reported by `protoc --version` is "3.21.9". +PROTOC_VERSION=21.9 +PROTOC_GEN_GO_VERSION=1.28.1 +PROTOC_IMAGE=vehicle-command-protoc:$(PROTOC_VERSION)-$(PROTOC_GEN_GO_VERSION) +PROTOC_DOCKERFILE=Dockerfile.protoc + +all: build + +linters: + @echo "** Running linters...**" + $(LINTER) + @echo "** SUCCESS **" + +set-version: + if TAG=$$(git describe --tags --abbrev=0); then echo "$${TAG}" | sed 's/v//' > pkg/account/version.txt; fi + +format: set-version + go fmt ./... + +test: install + go test -cover ./... + go vet ./... + +build: set-version test + go build ./... + +install: + go install ./cmd/... + +doc-images: + docker run -v ./:/data plantuml/plantuml "doc" + +proto-gen: $(PROTO_FILES) + protoc --proto_path $(PROTO_DIR) --go_out $(PROTO_DIR) --go_opt=module=github.com/teslamotors/vehicle-command/pkg/protocol/protobuf ${PROTO_FILES} + +# Build the pinned protoc toolchain image. No-op if it already exists. +proto-builder: + docker build \ + --build-arg PROTOC_VERSION=$(PROTOC_VERSION) \ + --build-arg PROTOC_GEN_GO_VERSION=$(PROTOC_GEN_GO_VERSION) \ + -f $(PROTOC_DOCKERFILE) \ + -t $(PROTOC_IMAGE) \ + . + +# Regenerate *.pb.go using the pinned toolchain. Use this instead of +# `proto-gen` to get reproducible output independent of the host's +# installed protoc version. +proto-gen-docker: proto-builder + docker run --rm \ + -v "$(CURDIR):/workspace" \ + -w /workspace \ + $(PROTOC_IMAGE) \ + --proto_path $(PROTO_DIR) \ + --go_out $(PROTO_DIR) \ + --go_opt=module=github.com/teslamotors/vehicle-command/pkg/protocol/protobuf \ + $(PROTO_FILES) + +# Regenerate via Docker and fail if the result differs from what is +# committed. Intended for CI to catch out-of-date *.pb.go files. +proto-check: proto-gen-docker + @if ! git diff --quiet -- $(PROTO_DIR); then \ + echo "ERROR: generated protobuf files are out of date."; \ + echo "Run 'make proto-gen-docker' and commit the result."; \ + git --no-pager diff -- $(PROTO_DIR); \ + exit 1; \ + fi + @echo "Generated protobuf files are up to date." + +.PHONY: install build linters test format set-version doc-images proto-gen proto-builder proto-gen-docker proto-check From 341e2d3f7c38255ead31f82a128315ab366c4792 Mon Sep 17 00:00:00 2001 From: CVales Date: Thu, 30 Apr 2026 16:01:30 +0200 Subject: [PATCH 2/5] Address Copilot review: pin Go base, verify protoc checksum, run as host UID Three follow-ups suggested by the automated review: - Dockerfile.protoc: pin the base image to `golang:1.23.0-bookworm` instead of the floating `golang:1.23-bookworm` tag, so a future patch rebuild of that tag cannot quietly change the toolchain output. - Dockerfile.protoc: verify the SHA256 of the downloaded protoc archive before unzipping. The expected sums for both linux-x86_64 and linux-aarch_64 (computed against the official v21.9 release assets) are exposed as build args so they live next to PROTOC_VERSION and are easy to update together. - Makefile: pass `--user "$(id -u):$(id -g)"` to `docker run` so generated *.pb.go files are owned by the invoking user instead of root, avoiding permission breakage on Linux/macOS hosts after running proto-gen-docker. Verified locally: the rebuilt image still produces a clean tree (`make proto-check` exits 0 with no diff under pkg/protocol/protobuf/). --- Dockerfile.protoc | 12 +++++++++--- Makefile | 1 + 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/Dockerfile.protoc b/Dockerfile.protoc index 7a95a3e7..afb72650 100644 --- a/Dockerfile.protoc +++ b/Dockerfile.protoc @@ -7,10 +7,15 @@ # regenerated code; run `make proto-gen-docker` and commit the result # in the same change. -FROM golang:1.23-bookworm AS toolchain +FROM golang:1.23.0-bookworm AS toolchain ARG PROTOC_VERSION=21.9 ARG PROTOC_GEN_GO_VERSION=1.28.1 +# SHA256 sums for the official protoc release archives. Update these when +# bumping PROTOC_VERSION; values can be recomputed with `sha256sum` against +# the assets at https://github.com/protocolbuffers/protobuf/releases. +ARG PROTOC_SHA256_X86_64=3cd951aff8ce713b94cde55e12378f505f2b89d47bf080508cf77e3934f680b6 +ARG PROTOC_SHA256_AARCH_64=a584286dfa8ebb17032ece206ed74d5e9931e2edb9016e427be2a0dab3b21071 ARG TARGETARCH RUN apt-get update \ @@ -19,12 +24,13 @@ RUN apt-get update \ # protoc release archives use x86_64 / aarch_64 in their file names. RUN case "${TARGETARCH:-amd64}" in \ - amd64) PROTOC_ARCH=x86_64 ;; \ - arm64) PROTOC_ARCH=aarch_64 ;; \ + amd64) PROTOC_ARCH=x86_64; PROTOC_SHA256="${PROTOC_SHA256_X86_64}" ;; \ + arm64) PROTOC_ARCH=aarch_64; PROTOC_SHA256="${PROTOC_SHA256_AARCH_64}" ;; \ *) echo "unsupported TARGETARCH=${TARGETARCH}" >&2; exit 1 ;; \ esac \ && curl -fsSL -o /tmp/protoc.zip \ "https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOC_VERSION}/protoc-${PROTOC_VERSION}-linux-${PROTOC_ARCH}.zip" \ + && echo "${PROTOC_SHA256} /tmp/protoc.zip" | sha256sum -c - \ && unzip -q /tmp/protoc.zip -d /usr/local/protoc \ && rm /tmp/protoc.zip \ && chmod +x /usr/local/protoc/bin/protoc diff --git a/Makefile b/Makefile index 666b4cf3..2980370c 100644 --- a/Makefile +++ b/Makefile @@ -61,6 +61,7 @@ proto-builder: # installed protoc version. proto-gen-docker: proto-builder docker run --rm \ + --user "$$(id -u):$$(id -g)" \ -v "$(CURDIR):/workspace" \ -w /workspace \ $(PROTOC_IMAGE) \ From 7632f584bebdbe82c61c8330d0497df444001582 Mon Sep 17 00:00:00 2001 From: CVales Date: Mon, 13 Jul 2026 15:38:20 +0000 Subject: [PATCH 3/5] Makefile: use LF line endings Remove Windows-style CRLF line endings from the Makefile as requested in review. Only line endings change; no content or target modifications. --- Makefile | 168 +++++++++++++++++++++++++++---------------------------- 1 file changed, 84 insertions(+), 84 deletions(-) diff --git a/Makefile b/Makefile index 2980370c..3199a2af 100644 --- a/Makefile +++ b/Makefile @@ -1,84 +1,84 @@ -LINTER = golangci-lint run -v $(LINTER_FLAGS) --exclude-use-default=false --timeout $(LINTER_DEADLINE) -LINTER_DEADLINE = 30s -LINTER_FLAGS ?= - -ifneq (,$(wildcard /etc/alpine-release)) -LINTER_FLAGS += --build-tags=musl -endif - -PROTO_DIR=./pkg/protocol/protobuf -PROTO_FILES=$(wildcard $(PROTO_DIR)/*.proto) - -# Pinned protoc toolchain. Update both versions here AND in Dockerfile.protoc -# when bumping; expect a diff in the regenerated *.pb.go files. -# PROTOC_VERSION uses the upstream release tag (e.g. "21.9"); the matching -# runtime version reported by `protoc --version` is "3.21.9". -PROTOC_VERSION=21.9 -PROTOC_GEN_GO_VERSION=1.28.1 -PROTOC_IMAGE=vehicle-command-protoc:$(PROTOC_VERSION)-$(PROTOC_GEN_GO_VERSION) -PROTOC_DOCKERFILE=Dockerfile.protoc - -all: build - -linters: - @echo "** Running linters...**" - $(LINTER) - @echo "** SUCCESS **" - -set-version: - if TAG=$$(git describe --tags --abbrev=0); then echo "$${TAG}" | sed 's/v//' > pkg/account/version.txt; fi - -format: set-version - go fmt ./... - -test: install - go test -cover ./... - go vet ./... - -build: set-version test - go build ./... - -install: - go install ./cmd/... - -doc-images: - docker run -v ./:/data plantuml/plantuml "doc" - -proto-gen: $(PROTO_FILES) - protoc --proto_path $(PROTO_DIR) --go_out $(PROTO_DIR) --go_opt=module=github.com/teslamotors/vehicle-command/pkg/protocol/protobuf ${PROTO_FILES} - -# Build the pinned protoc toolchain image. No-op if it already exists. -proto-builder: - docker build \ - --build-arg PROTOC_VERSION=$(PROTOC_VERSION) \ - --build-arg PROTOC_GEN_GO_VERSION=$(PROTOC_GEN_GO_VERSION) \ - -f $(PROTOC_DOCKERFILE) \ - -t $(PROTOC_IMAGE) \ - . - -# Regenerate *.pb.go using the pinned toolchain. Use this instead of -# `proto-gen` to get reproducible output independent of the host's -# installed protoc version. -proto-gen-docker: proto-builder - docker run --rm \ - --user "$$(id -u):$$(id -g)" \ - -v "$(CURDIR):/workspace" \ - -w /workspace \ - $(PROTOC_IMAGE) \ - --proto_path $(PROTO_DIR) \ - --go_out $(PROTO_DIR) \ - --go_opt=module=github.com/teslamotors/vehicle-command/pkg/protocol/protobuf \ - $(PROTO_FILES) - -# Regenerate via Docker and fail if the result differs from what is -# committed. Intended for CI to catch out-of-date *.pb.go files. -proto-check: proto-gen-docker - @if ! git diff --quiet -- $(PROTO_DIR); then \ - echo "ERROR: generated protobuf files are out of date."; \ - echo "Run 'make proto-gen-docker' and commit the result."; \ - git --no-pager diff -- $(PROTO_DIR); \ - exit 1; \ - fi - @echo "Generated protobuf files are up to date." - -.PHONY: install build linters test format set-version doc-images proto-gen proto-builder proto-gen-docker proto-check +LINTER = golangci-lint run -v $(LINTER_FLAGS) --exclude-use-default=false --timeout $(LINTER_DEADLINE) +LINTER_DEADLINE = 30s +LINTER_FLAGS ?= + +ifneq (,$(wildcard /etc/alpine-release)) +LINTER_FLAGS += --build-tags=musl +endif + +PROTO_DIR=./pkg/protocol/protobuf +PROTO_FILES=$(wildcard $(PROTO_DIR)/*.proto) + +# Pinned protoc toolchain. Update both versions here AND in Dockerfile.protoc +# when bumping; expect a diff in the regenerated *.pb.go files. +# PROTOC_VERSION uses the upstream release tag (e.g. "21.9"); the matching +# runtime version reported by `protoc --version` is "3.21.9". +PROTOC_VERSION=21.9 +PROTOC_GEN_GO_VERSION=1.28.1 +PROTOC_IMAGE=vehicle-command-protoc:$(PROTOC_VERSION)-$(PROTOC_GEN_GO_VERSION) +PROTOC_DOCKERFILE=Dockerfile.protoc + +all: build + +linters: + @echo "** Running linters...**" + $(LINTER) + @echo "** SUCCESS **" + +set-version: + if TAG=$$(git describe --tags --abbrev=0); then echo "$${TAG}" | sed 's/v//' > pkg/account/version.txt; fi + +format: set-version + go fmt ./... + +test: install + go test -cover ./... + go vet ./... + +build: set-version test + go build ./... + +install: + go install ./cmd/... + +doc-images: + docker run -v ./:/data plantuml/plantuml "doc" + +proto-gen: $(PROTO_FILES) + protoc --proto_path $(PROTO_DIR) --go_out $(PROTO_DIR) --go_opt=module=github.com/teslamotors/vehicle-command/pkg/protocol/protobuf ${PROTO_FILES} + +# Build the pinned protoc toolchain image. No-op if it already exists. +proto-builder: + docker build \ + --build-arg PROTOC_VERSION=$(PROTOC_VERSION) \ + --build-arg PROTOC_GEN_GO_VERSION=$(PROTOC_GEN_GO_VERSION) \ + -f $(PROTOC_DOCKERFILE) \ + -t $(PROTOC_IMAGE) \ + . + +# Regenerate *.pb.go using the pinned toolchain. Use this instead of +# `proto-gen` to get reproducible output independent of the host's +# installed protoc version. +proto-gen-docker: proto-builder + docker run --rm \ + --user "$$(id -u):$$(id -g)" \ + -v "$(CURDIR):/workspace" \ + -w /workspace \ + $(PROTOC_IMAGE) \ + --proto_path $(PROTO_DIR) \ + --go_out $(PROTO_DIR) \ + --go_opt=module=github.com/teslamotors/vehicle-command/pkg/protocol/protobuf \ + $(PROTO_FILES) + +# Regenerate via Docker and fail if the result differs from what is +# committed. Intended for CI to catch out-of-date *.pb.go files. +proto-check: proto-gen-docker + @if ! git diff --quiet -- $(PROTO_DIR); then \ + echo "ERROR: generated protobuf files are out of date."; \ + echo "Run 'make proto-gen-docker' and commit the result."; \ + git --no-pager diff -- $(PROTO_DIR); \ + exit 1; \ + fi + @echo "Generated protobuf files are up to date." + +.PHONY: install build linters test format set-version doc-images proto-gen proto-builder proto-gen-docker proto-check From a5ea08063ce8fa93db16b97e6377ec910cf5e254 Mon Sep 17 00:00:00 2001 From: CVales Date: Fri, 18 Sep 2026 04:15:01 +0200 Subject: [PATCH 4/5] proto-check: also fail on untracked generated files git diff --quiet ignores untracked files, so a new .proto whose .pb.go was never committed would be regenerated as an untracked file and the check would still pass. Fail as well when regeneration leaves untracked files under the proto directory, and show git status before the diff. --- Makefile | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 3199a2af..fe1b80a5 100644 --- a/Makefile +++ b/Makefile @@ -71,11 +71,15 @@ proto-gen-docker: proto-builder $(PROTO_FILES) # Regenerate via Docker and fail if the result differs from what is -# committed. Intended for CI to catch out-of-date *.pb.go files. +# committed, or if regeneration produced files that are not tracked (a new +# .proto whose .pb.go was never committed). Intended for CI to catch +# out-of-date or missing *.pb.go files. proto-check: proto-gen-docker - @if ! git diff --quiet -- $(PROTO_DIR); then \ - echo "ERROR: generated protobuf files are out of date."; \ + @if ! git diff --quiet -- $(PROTO_DIR) || \ + [ -n "$$(git ls-files --others --exclude-standard -- $(PROTO_DIR))" ]; then \ + echo "ERROR: generated protobuf files are out of date or missing."; \ echo "Run 'make proto-gen-docker' and commit the result."; \ + git --no-pager status --short -- $(PROTO_DIR); \ git --no-pager diff -- $(PROTO_DIR); \ exit 1; \ fi From 91d555c27c4d14c959c15dde8988c6f030a06ca3 Mon Sep 17 00:00:00 2001 From: CVales Date: Thu, 22 Oct 2026 19:27:40 +0200 Subject: [PATCH 5/5] Address review: read-only workflow permissions, drop Makefile version override Dockerfile.protoc is now the single source of truth for the protoc and protoc-gen-go versions and the protoc archive checksums. The Makefile override only changed the versions, not the hashes, so it could never produce a working build. --- .github/workflows/protos.yml | 3 +++ Makefile | 17 +++++++---------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/protos.yml b/.github/workflows/protos.yml index 84b18166..8519bde6 100644 --- a/.github/workflows/protos.yml +++ b/.github/workflows/protos.yml @@ -15,6 +15,9 @@ on: - 'Makefile' - '.github/workflows/protos.yml' +permissions: + contents: read + jobs: check: name: Verify generated protos are up to date diff --git a/Makefile b/Makefile index fe1b80a5..9a8b8464 100644 --- a/Makefile +++ b/Makefile @@ -9,13 +9,11 @@ endif PROTO_DIR=./pkg/protocol/protobuf PROTO_FILES=$(wildcard $(PROTO_DIR)/*.proto) -# Pinned protoc toolchain. Update both versions here AND in Dockerfile.protoc -# when bumping; expect a diff in the regenerated *.pb.go files. -# PROTOC_VERSION uses the upstream release tag (e.g. "21.9"); the matching -# runtime version reported by `protoc --version` is "3.21.9". -PROTOC_VERSION=21.9 -PROTOC_GEN_GO_VERSION=1.28.1 -PROTOC_IMAGE=vehicle-command-protoc:$(PROTOC_VERSION)-$(PROTOC_GEN_GO_VERSION) +# Pinned protoc toolchain. The protoc and protoc-gen-go versions (and the +# protoc archive checksums) are pinned in Dockerfile.protoc, which is the +# single source of truth. Expect a diff in the regenerated *.pb.go files +# when bumping them. +PROTOC_IMAGE=vehicle-command-protoc PROTOC_DOCKERFILE=Dockerfile.protoc all: build @@ -47,11 +45,10 @@ doc-images: proto-gen: $(PROTO_FILES) protoc --proto_path $(PROTO_DIR) --go_out $(PROTO_DIR) --go_opt=module=github.com/teslamotors/vehicle-command/pkg/protocol/protobuf ${PROTO_FILES} -# Build the pinned protoc toolchain image. No-op if it already exists. +# Build the pinned protoc toolchain image. Cached layers make this fast +# when Dockerfile.protoc has not changed. proto-builder: docker build \ - --build-arg PROTOC_VERSION=$(PROTOC_VERSION) \ - --build-arg PROTOC_GEN_GO_VERSION=$(PROTOC_GEN_GO_VERSION) \ -f $(PROTOC_DOCKERFILE) \ -t $(PROTOC_IMAGE) \ .