Skip to content

feat!: migrate protobuf codegen to protoc-gen-go and grpc-gateway v2 - #16796

Draft
Joibel wants to merge 1 commit into
argoproj:mainfrom
Joibel:feat/protoc-gen-go-migration
Draft

feat!: migrate protobuf codegen to protoc-gen-go and grpc-gateway v2#16796
Joibel wants to merge 1 commit into
argoproj:mainfrom
Joibel:feat/protoc-gen-go-migration

Conversation

@Joibel

@Joibel Joibel commented Aug 21, 2026

Copy link
Copy Markdown
Member
  • Ran make pre-commit -B
  • Signed-off commits with Conventional Commit messages
  • PR title is a conventional commit message (it becomes the release notes entry)
  • Unit or e2e tests cover the change
  • For features: an associated issue and a feature description file (make feature-new)
  • Opened as draft; will mark "Ready for review" once builds are green

Fixes #7400

Related: #16595 (Kubernetes 1.36 removes the kubernetes_protomessage_one_more_release build tag this relies on; the vendored-protobuf patch in this PR is the forward path).

Motivation

gogo/protobuf is unmaintained and increasingly incompatible with the protobuf ecosystem — most immediately with Kubernetes 1.35+, which is dropping ProtoMessage() from its generated types. This migrates the pkg/apiclient codegen to the officially maintained protoc-gen-go + protoc-gen-go-grpc, and the HTTP gateway from grpc-gateway v1 (also EOL) to v2, dropping go-grpc-middleware v1 along the way.

Modifications

  • protoc-gen-go generates .pb.go (messages), protoc-gen-go-grpc generates _grpc.pb.go (service stubs), protoc-gen-openapiv2 replaces protoc-gen-swagger; grpc-gateway v2 runtime in the server, grpc.ChainUnaryInterceptor/ChainStreamInterceptor replace go-grpc-middleware.
  • The pkg/apis/workflow/v1alpha1 types remain gogo-generated (they predate protoreflect). A new leaf package util/grpc/gateway bridges them into grpc-gateway v2: gateway.MessageV2Of (injected into generated .pb.gw.go by the Makefile's protoc rule, with guards that fail the build if the injection stops applying) satisfies the v2 proto.Message return type while preserving the encoding/json wire format, and an SSE/?fields-aware stream forwarder (reusing util/fields.Cleaner) replaces argoproj/pkg's grpc-gateway v1 forwarder.
  • Kubernetes 1.35 compatibility is belt-and-braces: the Makefile exports -tags=kubernetes_protomessage_one_more_release for make-driven builds, and hack/vendor-patches.sh (idempotent, anchored, fails loudly) patches vendored google.golang.org/protobuf for tag-less builds — the forward path once k8s 1.36 drops the tag. pkg/apiclient probes at startup so unprotected module consumers get an immediate, actionable error instead of a deep runtime panic.
  • Breaking (see docs/upgrading.md): WatchEvents returns a EventWatchEvent{type, object} envelope (matching the other watch streams; the UI events panel is updated); OpenAPI request-body definitions renamed (WorkflowCreateRequestCreateWorkflowBody, argo-events definitions to io.argoproj.events.v1alpha1.*), renaming generated SDK classes; HTTP error bodies use google.rpc.Status.
  • Scope note: gogo/protobuf is not fully removed — it remains confined to the pkg/apis/workflow/v1alpha1 island. Those types are Go-first Kubernetes CRD types, so they are still generated by go-to-protobuf (which requires protoc-gen-gogo at codegen time) and still link the archived gogo runtime, pinned at v1.3.2. Full removal is gated on upstream Kubernetes shipping protoreflect-compatible types (see Update Kubernetes dependencies to 1.36 #16595) and is deliberately out of scope here.
  • The nix dev env (dev/nix/flake.nix, devenv.nix) is migrated to the new toolchain, and Renovate managers cover the codegen tool pins in both the Makefile and the nix files (nix bumps are never automerged since their hashes need manual updates).

Verification

  • New HTTP round-trip test (server/apiserver/gateway_roundtrip_test.go): real gRPC server on bufconn behind the production gateway mux configuration, pinning unary JSON bodies of gogo types (not {}), unary and in-stream google.rpc.Status error shapes, SSE streaming/flush behaviour, the {"result": ...} envelope, event-type passthrough, and ?fields filtering.
  • New unit tests for the stream forwarder (keepalive emission, stop-on-error and stop-on-cancel, logger-free contexts, mutex/Flush contract with http.ResponseController), run clean under -race.
  • make codegen -B, make lint, features-validate, and the unit test suite all pass; the nix packages for the new toolchain build (nix build ./dev/nix#protoc-gen-go etc.).

Documentation

  • docs/upgrading.md gains an "Upgrading to v4.2" section covering every API-visible change (HTTP, gRPC, and Go consumers).
  • Feature description file .features/pending/protoc-gen-go-migration.md.
  • AGENTS.md documents the make vendor requirement.

AI

Code, tests, documentation, and commit message were written with Claude (Opus 4.6 and Fable 5) under human direction, including two multi-agent review passes whose findings were fixed and re-verified; all changes were human-reviewed.

🤖 Generated with Claude Code

https://claude.ai/code/session_01HDe5nzNL4WzD4CTAWZT5Et

@Joibel
Joibel force-pushed the feat/protoc-gen-go-migration branch 4 times, most recently from cf698bc to 98eef1d Compare August 24, 2026 09:27
Replace gogo/protobuf codegen (protoc-gen-gogofast) with the official
protoc-gen-go + protoc-gen-go-grpc. Migrate grpc-gateway from v1 to v2
and replace protoc-gen-swagger with protoc-gen-openapiv2. Drop
go-grpc-middleware v1 in favor of grpc.ChainUnaryInterceptor.

BREAKING CHANGE: the /api/v1/stream/events/{namespace} stream now wraps
each event as {"type", "object"}; some OpenAPI definitions are renamed
(e.g. WorkflowCreateRequest -> CreateWorkflowBody), renaming generated
SDK classes; HTTP error bodies use google.rpc.Status. See
docs/upgrading.md.

Key changes:
- Bump k8s.io/code-generator and proto deps to v0.35.4, aligned with
  go.mod's k8s.io libraries
- protoc-gen-go generates .pb.go (messages), protoc-gen-go-grpc
  generates _grpc.pb.go (service stubs)
- grpc-gateway v2 runtime in argoserver.go
- New leaf package util/grpc/gateway holds the gateway glue shared by
  the server and the generated pkg/apiclient code: an SSE/fields-aware
  stream forwarder (reusing util/fields.Cleaner) and gateway.MessageV2Of,
  which bridges gogo-generated v1alpha1 types to grpc-gateway v2's
  proto.Message while preserving their encoding/json wire format
- Vendor patch (hack/vendor-patches.sh) for K8s types losing
  ProtoMessage() in k8s 1.36+: changes panic to return nil in
  protoMessageV2Of (anchored to that one function, fails loudly if it
  no longer applies), letting aberrantLoadMessageDesc handle them; the
  kubernetes_protomessage_one_more_release build tag stays exported for
  builds that do not use the vendor tree
- Add `make vendor` target (go mod vendor + vendor patches) wired as
  prerequisite to all proto/build/test targets
- Wrap WatchEvents RPC in EventWatchEvent (matching the *WatchEvent
  naming of the other streams) and update the UI events panel for the
  new shape
- HTTP request contexts carry the server logger; the gateway stream
  forwarder falls back to a default logger rather than panicking from
  its keepalive goroutine when one is missing
- pkg/apiclient probes at startup that Kubernetes types can be
  marshalled, turning the unprotected-module-consumer panic into an
  immediate, actionable error (pkg/apiclient/protocompat.go)
- HTTP round-trip test (bufconn gRPC + gateway mux + httptest, sharing
  the production mux configuration) pinning unary JSON bodies, unary and
  in-stream google.rpc.Status error shapes, SSE streaming/flush, the
  {"result": ...} envelope, and ?fields filtering
- Update swaggify.sh for protoc-gen-openapiv2 naming conventions
- Artifact endpoints in _.primary.swagger.json moved to the
  google.rpc.Status error model used everywhere else
- Migrate the nix dev env (dev/nix/flake.nix, devenv.nix) to the new
  toolchain
- Renovate managers for the codegen tool pins, including the nix copies
  (annotated, never automerged)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Alan Clucas <alan@clucas.org>

Claude-Session: https://claude.ai/code/session_01HDe5nzNL4WzD4CTAWZT5Et
@Joibel
Joibel force-pushed the feat/protoc-gen-go-migration branch from 98eef1d to 751b632 Compare August 24, 2026 09:57
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.

GoGo Protobuf is no longer maintained

1 participant