Skip to content

Pin code generation and bring renovate.json to the org baseline - #1733

Open
biglittlebigben wants to merge 1 commit into
mainfrom
renovate/pin-generators-and-baseline
Open

Pin code generation and bring renovate.json to the org baseline#1733
biglittlebigben wants to merge 1 commit into
mainfrom
renovate/pin-generators-and-baseline

Conversation

@biglittlebigben

@biglittlebigben biglittlebigben commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

Why

protoc's plugins were unpinned inputs to code we commit. The generate workflow installed all four with go install ...@latest, ran mage via mage-action with version: latest, and floated protoc within its major.

Worse, every --plugin= flag in the magefile used the short form:

--plugin=go=/path/to/protoc-gen-go              # silently ignored -> plugin taken from PATH
--plugin=protoc-gen-go=/path/to/protoc-gen-go   # honoured

protoc only honours the full-executable-name form. No error, no warning — so generation was really running whatever was in GOPATH/bin, and the @latest installs were the de facto pin. The failure mode is quiet: generated files change whenever an upstream release lands, arriving in an automated generated protobuf commit nobody reads.

Pinning

Each generator is pinned to the version stamped in the committed headers:

input pin
protoc arduino/setup-protoc's version:, exact rather than 35.x
protoc-gen-go, -go-grpc, -psrpc, -twirp tool directives in go.mod, resolved with go tool -n
mage a tool directive too — go tool mage proto
  • The --plugin= flags now use the form protoc honours, so those pinned paths are actually used.
  • protoc is pinned exactly, not floated: it stamps its version into every generated file, so a release bump rewrites the committed output. Moving it should be a deliberate, reviewable edit.
  • release.yaml gets the same pin. It had no version: at all, and it builds the published @livekit/protocol package via pnpm generate:proto — protoc is a release input there, so the published JS package could be generated by a different compiler than the committed Go code.

google.golang.org/protobuf moves 1.36.11 → 1.36.12 because 1.36.12 is what generated the committed files. Pinning to 1.36.11 would land a downgrade of every header disguised as a pin. go get -tool also dragged psrpc 0.7.3 → 0.7.4 along the way; that's put back.

Verification

Regenerated with the pinned protoc (35.1) and plugins: git status on livekit rpc infra is empty — the tree comes back byte-identical, so this is a pin and not a generator upgrade in disguise.

That check is meaningful rather than vacuous here. My GOPATH/bin held older plugins than the pins:

GOPATH/bin: protoc-gen-go v1.36.11   psrpc v0.7.0    go-grpc 1.6.0
pinned:     protoc-gen-go v1.36.12   psrpc v0.7.3    go-grpc 1.6.2

A surviving PATH fallback would have churned every header downward. An empty diff proves the plugin paths are honoured.

CI confirms it independently: the Generate job ran the new path on this branch and added no generated protobuf commit, i.e. a clean runner with an empty GOPATH/bin reproduced the committed tree exactly. renovate-config-validator passes, and go build ./... / go test ./... pass.

mage bootstrap

Kept, as a developer convenience for installing the plugins system-wide, and documented as such. It is not a build step — nothing in .github/, package.json or any mage target references it, and mage proto ignores what it installs, since plugins resolve through the tool directives to explicit paths. If someone did generate with something else, the Generate workflow regenerates and commits on every push to a non-main branch, so what reaches main always comes from the pinned versions.

Removing bootstrap.sh

bootstrap.sh is deleted. It duplicated mage bootstrap — install the four plugins into GOPATH/bin — but at versions that had gone badly stale:

plugin bootstrap.sh actually generated the committed files
protoc-gen-go v1.31.0 v1.36.12
protoc-gen-psrpc v0.5.1 v0.7.3
protoc-gen-go-grpc v1.3 v1.6.2
protoc-gen-twirp v8.1.3 v8.1.3

That mattered because of the --plugin= bug above: while generation resolved plugins from PATH, a contributor who ran ./bootstrap.sh and then mage proto generated the tree with protoc-gen-go v1.31.0 and psrpc v0.5.1 — five minors and two minors behind. The script wasn't a neutral convenience, it was a way to produce wrong output.

The rest of it had also rotted:

  • It gated on GO_TARGET_VERSION=1.17 and had a whole second branch using go get -u for older toolchains. go.mod requires 1.26, so that branch was dead code pinning even older plugins (protoc-gen-go v1.30.0, psrpc v0.3.1).
  • It installed mage by git clone-ing magefile/mage into /tmp and running go run bootstrap.go — an unpinned clone of the default branch. mage is now a tool directive, so go tool mage needs no install at all.
  • Its remaining jobs are covered elsewhere: the protoc presence check is moot once the workflow pins protoc, and go mod download is a workflow step.

Nothing referenced it — no workflow, no package.json script, no docs (the repo has no README). Keeping a second, staler entry point next to mage bootstrap would just reintroduce the hazard this PR removes, so it goes. mage bootstrap remains for anyone who wants the plugins on their PATH.

renovate.json

Off the deprecated config:base and onto the baseline used across the Go repos:

  • Third-party Go modules ungrouped, so a bad bump reverts on its own (they were all in one go deps group).
  • livekit deps grouped and exempt from quarantine — we track pseudo-versions that move constantly.
  • pion deps grouped: 3 direct pion modules, co-released, so one-at-a-time bumps produce PRs that don't build.
  • Vulnerability fast path: 2-day quarantine, no concurrency/hourly/schedule limits, so a CVE fix isn't held two weeks behind the Monday schedule.
  • golang and toolchain deptypes disabled. This module is a library: the go directive is the minimum we ask of consumers, and a toolchain line would raise the floor for everyone.
  • Drops constraints: {go: "1.22"}, four minors behind go.mod.

Follow-ups (not in this PR)

  • stringer in sip/sip.go's go:generate is still unpinned from PATH; CI never runs it.
  • gotestfmt in buildtest.yaml is pinned by commit SHA — fine, but hand-maintained.

🤖 Generated with Claude Code

protoc's plugins were unpinned inputs to committed code: the generate
workflow installed all four with `go install ...@latest`, ran mage from
`mage-action` with `version: latest`, and floated protoc within its
major. Worse, every `--plugin=` flag in the magefile used the short form
(`--plugin=go=`), which protoc silently ignores, so generation actually
ran whatever binary happened to be in GOPATH/bin.

Pin each generator to the version stamped in the committed headers:

  - protoc-gen-go, -go-grpc, -psrpc, -twirp and mage become `tool`
    directives in go.mod, resolved at generation time with `go tool -n`
  - the `--plugin=` flags use the full-executable-name form protoc
    honours, so those pinned paths are actually used
  - protoc is pinned exactly rather than floated within its major; it
    stamps its version into every generated file, so a bump rewrites
    the committed output and should be a reviewable edit
  - release.yaml gets the same protoc pin: it builds the published JS
    package via `pnpm generate:proto`, so protoc is a release input

google.golang.org/protobuf moves 1.36.11 -> 1.36.12 because 1.36.12 is
what generated the committed files; pinning to 1.36.11 would land a
downgrade of every header disguised as a pin. Verified by regenerating
with the pinned protoc: the generated tree comes back byte-identical.
GOPATH/bin here held older plugins (protoc-gen-go v1.36.11, psrpc
v0.7.0), so an empty diff also proves the plugin paths are honoured
rather than falling back to PATH.

`mage bootstrap` stays as a developer convenience for installing the
plugins system-wide, documented as such: it is not a build step, and
generation ignores what it installs. bootstrap.sh is removed - it did
the same job pinned to protoc-gen-go v1.31.0 and psrpc v0.5.1, and
nothing referenced it.

renovate.json moves off the deprecated config:base to the baseline used
across the Go repos: third-party modules ungrouped so a bad bump reverts
alone, livekit deps grouped and exempt from quarantine, pion grouped
because they are co-released, a vulnerability fast path, and both the
go and toolchain directives disabled - this module is a library, so its
go directive is the minimum we ask of consumers. Drops the stale
go 1.22 constraint, four minors behind go.mod.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@changeset-bot

changeset-bot Bot commented Aug 22, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: c8cd27c

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

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.

3 participants