Skip to content

fix(sr-normalize): reference inlined deps by their local name#175

Open
birdayz wants to merge 1 commit into
mainfrom
jb/fix-sr-normalize-cross-package
Open

fix(sr-normalize): reference inlined deps by their local name#175
birdayz wants to merge 1 commit into
mainfrom
jb/fix-sr-normalize-cross-package

Conversation

@birdayz

@birdayz birdayz commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

What

Fix cross-package dependency references in protoc-gen-go-sr-normalize. A message whose field type lives in a different proto package produced a schema with a dangling type reference that Schema Registry rejects. Same-package schemas are byte-identical to before.

Why

The plugin builds a single self-contained schema by inlining every non-WKT transitive dependency as a top-level type in the target's package. The reference-naming logic stripped only the package prefix that the referred type shared with the referring message. That is fine while everything sits in one package, but wrong across packages.

Concrete case that motivated this: redpanda.api.adp.v1alpha1.LLMProviderType referenced from a message in redpanda.adp.v1alpha1. The shared prefix is just redpanda., so the reference came out as api.adp.v1alpha1.LLMProviderType while the enum was inlined top-level as LLMProviderType. Dangling reference, schema rejected. The workaround so far was to duplicate the enum into the referring package, which is exactly what this makes unnecessary.

Implementation details

Reference each type by its path within its own file: strip the type's own package prefix, not the prefix it happens to share with the referrer. A top-level type resolves to its bare name; a nested type to Parent.Nested, matching how the generator renders inlined types (flattened into one package, nesting preserved). Well-known google/protobuf/* types are kept as imports, so they retain their full name.

The change is contained to the naming path: relativeName (shared-prefix stripping) is replaced by localTypeName (own-package stripping) behind schemaTypeName, which also handles the well-known case.

New example proves the cross-package path end to end: example.other.v1.ProviderType (a separate package) referenced by an annotated example.v1.Event. TestSchemaRegistry_EventRoundTrip registers the generated schema against a real Schema Registry and round-trips a message. A unit test pins the naming logic directly.

The order.pb.go / product.pb.go diffs are a regeneration, not a functional change. Their checked-in go_package had been renamed textually from protoc-gen-go-sr to protoc-gen-go-sr-normalize without regenerating, which left the descriptor's varint length prefix stale (87 vs the actual 97 bytes) and panics at package init. Regenerating corrects the descriptor; the .sr.pb.go outputs are unchanged.

References

Discovered while moving proto packages around, where the cross-package enum reference forced a duplicate enum definition.

The plugin inlines every non-WKT transitive dependency as a top-level
type in the target's package, then references it by name. The naming
logic stripped only the package prefix the referred type shared with the
referring message. That works when everything lives in one package, and
breaks the moment a dependency comes from another package: the emitted
reference keeps the non-shared package segments while the type was
inlined under its bare name, so the reference dangles and Schema Registry
rejects the schema.

Reference each type by its path within its own file instead: strip the
type's own package, not the prefix it happens to share with the referrer.
Top-level types resolve to their bare name, nested types to Parent.Nested.
Well-known google/protobuf types stay imports and keep their full name.
Same-package output is byte-identical, so existing schemas are unchanged.

Add a cross-package example (example.other.v1.ProviderType referenced by
example.v1.Event) with an SR round-trip test that registers the schema
against a real Schema Registry, plus a unit test for the naming logic.

The order/product .pb.go changes are a regeneration: their checked-in
go_package string had been renamed textually from protoc-gen-go-sr to
protoc-gen-go-sr-normalize without regenerating, leaving a stale descriptor
length prefix that panics at package init.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@secpanda

secpanda commented Jul 8, 2026

Copy link
Copy Markdown

Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues
Licenses 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

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.

2 participants