Skip to content

Add reproducible protoc toolchain and proto-check CI (#307) - #445

Open
carlosvales wants to merge 3 commits into
teslamotors:mainfrom
carlosvales:feat/protoc-docker-toolchain
Open

Add reproducible protoc toolchain and proto-check CI (#307)#445
carlosvales wants to merge 3 commits into
teslamotors:mainfrom
carlosvales:feat/protoc-docker-toolchain

Conversation

@carlosvales

Copy link
Copy Markdown

Description

Closes #307.

Currently, regenerating the .pb.go files relies on whatever protoc the contributor happens to have installed locally. This leads to spurious diffs whenever versions drift. This PR 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

Dockerfile.protoc

A Debian-based image (golang:1.23-bookworm) that installs:

  • protoc 3.21.9 (upstream tag v21.9)
  • protoc-gen-go v1.28.1

These match the versions stamped in the headers of the existing *.pb.go files. Both are configurable via build args so future bumps only need to edit two lines (Dockerfile + Makefile).

Makefile targets

Target What it does
proto-builder Builds the toolchain image (vehicle-command-protoc:21.9-1.28.1).
proto-gen-docker Regenerates the .pb.go files using the pinned toolchain.
proto-check Regenerates via Docker and fails if git diff is non-empty under pkg/protocol/protobuf/.

The original proto-gen target (host protoc) is kept untouched for backwards compatibility — contributors who want to keep using their local toolchain can still do so.

.github/workflows/protos.yml

Runs make proto-check on PRs and pushes to main that touch the .proto files, the toolchain Dockerfile, the Makefile, or the workflow itself.

Regenerated *.pb.go

Six files are touched (+257 / -0). The diff is purely cosmetic: protoc-gen-go v1.28.1 emits an empty // comment line at the top of each "Types that are assignable to ..." block that the previously committed files lacked. This suggests the committed files 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.

A representative hunk:

 // Types that are assignable to ActionMsg:
+//
 //	*Action_VehicleAction
 ActionMsg isAction_ActionMsg \`protobuf_oneof:\"action_msg\"\`

No type signatures, field tags, or runtime behavior change.

Type of 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:

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

(Documentation/unit tests not applicable: tooling-only PR, the new CI workflow is the test.)

Copilot AI review requested due to automatic review settings April 30, 2026 13:38

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a pinned, Docker-based protoc + protoc-gen-go toolchain and a CI workflow to ensure committed *.pb.go outputs stay in sync with the pinned generator versions, preventing version-drift diffs.

Changes:

  • Add Dockerfile.protoc to build a reproducible protoc toolchain image (pinned protoc + protoc-gen-go via build args).
  • Extend Makefile with proto-builder, proto-gen-docker, and proto-check targets to regenerate and verify protobuf outputs via Docker.
  • Add .github/workflows/protos.yml to run make proto-check on relevant changes; regenerate *.pb.go files to match the pinned generator output.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
Dockerfile.protoc Introduces Dockerized protoc/protoc-gen-go toolchain used for deterministic generation.
Makefile Adds Docker-based proto generation + a proto-check gate intended for CI.
.github/workflows/protos.yml Runs make proto-check on PRs/pushes when proto/tooling files change.
pkg/protocol/protobuf/vcsec/vcsec.pb.go Regenerated output (cosmetic comment lines) to match pinned toolchain.
pkg/protocol/protobuf/universalmessage/universal_message.pb.go Regenerated output (cosmetic comment lines) to match pinned toolchain.
pkg/protocol/protobuf/signatures/signatures.pb.go Regenerated output (cosmetic comment lines) to match pinned toolchain.
pkg/protocol/protobuf/carserver/vehicle.pb.go Regenerated output (cosmetic comment lines) to match pinned toolchain.
pkg/protocol/protobuf/carserver/common.pb.go Regenerated output (cosmetic comment lines) to match pinned toolchain.
pkg/protocol/protobuf/carserver/car_server.pb.go Regenerated output (cosmetic comment lines) to match pinned toolchain.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread Dockerfile.protoc
Comment on lines +26 to +30
&& 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

Copilot AI Apr 30, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Dockerfile downloads the protoc zip from GitHub but doesn't verify its checksum/signature. Since this image is intended to gate CI and provide reproducible output, it would be safer and more deterministic to validate the downloaded archive (e.g., check SHA256 from the release assets) before unzipping/using it.

Copilot uses AI. Check for mistakes.
Comment thread Makefile Outdated
Comment on lines +63 to +70
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)

Copilot AI Apr 30, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

proto-gen-docker runs the container as root and writes generated *.pb.go files back into the working tree. On many hosts this will leave root-owned files in pkg/protocol/protobuf/**, which is painful to clean up and can break subsequent local tooling. Consider running the container with the current UID/GID (e.g., docker run --user ...) so generated files keep normal ownership.

Copilot uses AI. Check for mistakes.
Comment thread Dockerfile.protoc Outdated
# regenerated code; run `make proto-gen-docker` and commit the result
# in the same change.

FROM golang:1.23-bookworm AS toolchain

Copilot AI Apr 30, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For a reproducible toolchain image, FROM golang:1.23-bookworm is a floating tag and can change over time (new patch versions / rebuilds), which can introduce drift unrelated to protoc/protoc-gen-go. Pinning to a specific patch tag (e.g., golang:1.23.0-bookworm) or an image digest would better match the goal of this PR.

Suggested change
FROM golang:1.23-bookworm AS toolchain
FROM golang:1.23.0-bookworm AS toolchain

Copilot uses AI. Check for mistakes.
@sethterashima

Copy link
Copy Markdown
Collaborator

Thanks for putting up this PR and apologies that it hasn't gotten review sooner.

It looks good, with one minor issue: Please remove the Windows-style line endings (\n\r) from the Makefile.

@carlosvales

Copy link
Copy Markdown
Author

Thanks @sethterashima! Done — I've removed the Windows-style CRLF line endings from the Makefile (it's LF now). The new commit only touches line endings, no content or target changes. Let me know if there's anything else before merge.

sethterashima pushed a commit that referenced this pull request Jul 16, 2026
Regenerate existing protobuf files using a consistent compiler version
in preperation for merging
#445.
@sethterashima

Copy link
Copy Markdown
Collaborator

Workflow is failing, likely because ed0cacc introduced the very protobuf version mismatch error this will prevent. I updated the protobuf versions in 4c2143a, but it looks like the workflow is picking up the stale versions. Could you rebase on main and force-push to see if this resolves the issue?

Closes teslamotors#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.
…ost 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/).
Remove Windows-style CRLF line endings from the Makefile as requested in review.
Only line endings change; no content or target modifications.
@carlosvales
carlosvales force-pushed the feat/protoc-docker-toolchain branch from 8cb40c7 to 7632f58 Compare August 5, 2026 18:52
@carlosvales

Copy link
Copy Markdown
Author

Rebased on main and force-pushed, as requested.

Now that 4c2143a (Normalize protobuf file versions) is in main, the regenerated protos on this branch match it exactly — the diff against main is down to just the three files this PR is about: Makefile, Dockerfile.protoc and .github/workflows/protos.yml.

Ready for another CI run whenever you can approve the workflow. Thanks!

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.

create a docker file for generating protos

3 participants