Skip to content

Add ExperimentalListPackageCustomSchemas gRPC endpoint#1981

Open
perdasilva wants to merge 1 commit into
operator-framework:masterfrom
perdasilva:generic-blob-endpoint-compressed
Open

Add ExperimentalListPackageCustomSchemas gRPC endpoint#1981
perdasilva wants to merge 1 commit into
operator-framework:masterfrom
perdasilva:generic-blob-endpoint-compressed

Conversation

@perdasilva
Copy link
Copy Markdown
Contributor

@perdasilva perdasilva commented May 12, 2026

Summary

Adds a new ExperimentalListPackageCustomSchemas streaming gRPC endpoint that returns custom schema blobs (arbitrary JSON documents) stored in FBC catalogs, filtered by schema name and optionally by package name.

Key design decisions

  • Separate ExperimentalRegistry gRPC service — the endpoint lives outside the stable Registry API to signal its experimental status and allow independent evolution
  • Experimental header gate — callers must pass X-Acknowledge-Experimental: true gRPC metadata; without it the endpoint silently returns an empty stream
  • Allowlist-validated metaKey — schema and package name components are validated against ^[a-zA-Z0-9][a-zA-Z0-9._-]*$ to prevent path traversal and filesystem tricks
  • Dual cache backend support — both JSON (filesystem) and pogreb (embedded KV) backends implement PutMeta/SendMetas

Known limitations

  • pogreb SendMetas performs a full table scan — pogreb does not support prefix/range scans, so queries iterate all entries in the database. This scales linearly with total catalog size and may be slow for very large catalogs.

Test plan

  • Unit tests for metaKey validation (valid keys, empty, path traversal, dot sequences, leading special chars)
  • Cache-level integration tests for both JSON and pogreb backends (multiple blobs, packageless blobs, no custom schemas)
  • Server-level gRPC round-trip tests (results, empty results, packageless, invalid argument, missing experimental header)
  • Context cancellation checks in both SendMetas implementations
  • go test ./pkg/cache/... ./pkg/server/... passes

🤖 Generated with Claude Code

Copilot AI review requested due to automatic review settings May 12, 2026 12:13
@codecov
Copy link
Copy Markdown

codecov Bot commented May 12, 2026

Codecov Report

❌ Patch coverage is 68.54839% with 78 lines in your changes missing coverage. Please review.
✅ Project coverage is 58.77%. Comparing base (210e5d6) to head (9e45498).
⚠️ Report is 8 commits behind head on master.

Files with missing lines Patch % Lines
pkg/api/registry.pb.go 72.64% 24 Missing and 5 partials ⚠️
pkg/server/server.go 58.06% 9 Missing and 4 partials ⚠️
pkg/api/registry_grpc.pb.go 62.06% 7 Missing and 4 partials ⚠️
pkg/cache/json.go 62.06% 7 Missing and 4 partials ⚠️
pkg/cache/cache.go 57.14% 3 Missing and 3 partials ⚠️
pkg/cache/pogrebv1.go 75.00% 4 Missing and 2 partials ⚠️
pkg/cache/meta_key.go 86.66% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1981      +/-   ##
==========================================
+ Coverage   57.90%   58.77%   +0.87%     
==========================================
  Files         140      141       +1     
  Lines       13441    13405      -36     
==========================================
+ Hits         7783     7879      +96     
+ Misses       4470     4319     -151     
- Partials     1188     1207      +19     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds support for streaming per-package “custom schema” FBC blobs over gRPC, backed by new cache storage primitives in both pogreb and JSON cache backends. This extends the opm serve gRPC surface to expose non-standard schema content without introducing new typed protobuf messages.

Changes:

  • Adds ListPackageCustomSchemas(schema, packageName) server-streaming gRPC RPC returning google.protobuf.Struct.
  • Extends cache backends with meta blob storage/retrieval keyed by (schema, packageName) and updates cache build to persist non-standard schemas.
  • Updates protoc/tooling wiring to include protobuf well-known types (struct.proto) during codegen.

Reviewed changes

Copilot reviewed 13 out of 15 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
scripts/ensure-protoc.sh Downloads protoc include files so well-known protos (e.g., struct.proto) can be imported during codegen.
README.md Documents the new gRPC method in the public list of endpoints.
pkg/server/server.go Implements the new gRPC streaming handler and converts stored JSON blobs into structpb.Struct.
pkg/server/server_test.go Adds integration-style gRPC tests for streaming results, empty results, and invalid-argument behavior.
pkg/client/client_test.go Updates the client stub interface to include the new RPC.
pkg/cache/pogrebv1.go Adds meta blob Put/Send support in the pogreb backend.
pkg/cache/meta_key.go Introduces meta key validation helpers for schema/packageName components.
pkg/cache/json.go Adds meta blob directory layout and Put/Send support in the JSON backend.
pkg/cache/cache.go Extends cache interface + build pipeline to store non-standard schema blobs and expose query method.
pkg/cache/cache_test.go Adds unit tests covering custom schema storage/retrieval and packageless blob skipping.
pkg/api/registry.proto Adds the new RPC and request message; imports google/protobuf/struct.proto.
pkg/api/registry.pb.go Regenerated protobuf Go types (incl. new request type).
pkg/api/registry_grpc.pb.go Regenerated gRPC service stubs (incl. new streaming method).
Makefile Updates protoc include paths used by make codegen.
AGENTS.md Documents the new gRPC method in internal agent docs.
Files not reviewed (2)
  • pkg/api/registry.pb.go: Language not supported
  • pkg/api/registry_grpc.pb.go: Language not supported

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

Comment thread pkg/cache/cache.go Outdated
Comment thread pkg/cache/cache.go Outdated
Comment thread pkg/cache/json.go Outdated
Comment thread pkg/cache/json.go
Comment thread pkg/server/server.go
Comment thread pkg/server/server_test.go Outdated
Comment thread Makefile
@perdasilva perdasilva force-pushed the generic-blob-endpoint-compressed branch 2 times, most recently from 9e6cfcf to 8f19197 Compare May 12, 2026 12:40
Copilot AI review requested due to automatic review settings May 12, 2026 12:40
@perdasilva perdasilva force-pushed the generic-blob-endpoint-compressed branch from 8f19197 to 029eaa4 Compare May 12, 2026 12:41
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 13 out of 15 changed files in this pull request and generated 4 comments.

Files not reviewed (2)
  • pkg/api/registry.pb.go: Language not supported
  • pkg/api/registry_grpc.pb.go: Language not supported

Comment thread pkg/server/server.go Outdated
Comment thread pkg/cache/json.go
Comment thread pkg/cache/pogrebv1.go
Comment thread pkg/cache/pogrebv1.go Outdated
@perdasilva perdasilva force-pushed the generic-blob-endpoint-compressed branch 3 times, most recently from 318e335 to 4226e11 Compare May 12, 2026 15:23
Copilot AI review requested due to automatic review settings May 12, 2026 15:23
@perdasilva perdasilva force-pushed the generic-blob-endpoint-compressed branch from 4226e11 to f45c501 Compare May 12, 2026 15:44
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 14 out of 16 changed files in this pull request and generated 2 comments.

Files not reviewed (2)
  • pkg/api/registry.pb.go: Language not supported
  • pkg/api/registry_grpc.pb.go: Language not supported
Comments suppressed due to low confidence (1)

pkg/cache/cache.go:323

  • In Build’s WalkMetasFS callback, custom-schema metas with an empty packageName are still appended to byPackageReaders[""] and later written into the package index via pkgs[pkgName] = pkgIndex[pkgName]. This will cause ListPackages to include an empty package name when packageless custom schema blobs exist. Consider short-circuiting after storing the meta (PutMeta) for non-standard schemas when packageName == "" so they don’t participate in package index construction (and don’t create a pkgs[""] entry).
		switch meta.Schema {
		case declcfg.SchemaPackage, declcfg.SchemaChannel, declcfg.SchemaBundle, declcfg.SchemaDeprecation:
		default:
			mk, err := newValidatedMetaKey(meta.Schema, packageName)
			if err != nil {
				return fmt.Errorf("invalid custom schema meta: %v", err)
			}
			if err := c.backend.PutMeta(ctx, mk, meta.Blob); err != nil {
				return fmt.Errorf("store custom schema meta %v: %v", mk, err)
			}
		}
		if _, err := tmpFile.Write(meta.Blob); err != nil {
			return err
		}
		sr := io.NewSectionReader(tmpFile, offset, int64(len(meta.Blob)))
		byPackageReaders[packageName] = append(byPackageReaders[packageName], sr)
		offset += int64(len(meta.Blob))

Comment thread AGENTS.md Outdated
Comment thread README.md
@perdasilva perdasilva force-pushed the generic-blob-endpoint-compressed branch from f45c501 to ba1392c Compare May 13, 2026 07:15
Copilot AI review requested due to automatic review settings May 13, 2026 07:27
@perdasilva perdasilva force-pushed the generic-blob-endpoint-compressed branch from ba1392c to fbe2335 Compare May 13, 2026 07:27
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

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

Files not reviewed (2)
  • pkg/api/registry.pb.go: Language not supported
  • pkg/api/registry_grpc.pb.go: Language not supported

Comment thread pkg/cache/meta_key.go
Comment thread pkg/cache/meta_key_test.go
Comment thread pkg/server/server.go Outdated
@perdasilva perdasilva force-pushed the generic-blob-endpoint-compressed branch 3 times, most recently from 26f2d3a to 3176657 Compare May 13, 2026 13:37
@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented May 19, 2026

@fgiudici: Overrode contexts on behalf of fgiudici: go-apidiff

Details

In response to this:

/override go-apidiff

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@perdasilva perdasilva changed the title Add ListPackageCustomSchemas gRPC endpoint to opm serve Add ExperimentalListPackageCustomSchemas gRPC endpoint May 19, 2026
@openshift-ci openshift-ci Bot removed the lgtm Indicates that a PR is ready to be merged. label May 19, 2026
@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented May 19, 2026

New changes are detected. LGTM label has been removed.

@perdasilva perdasilva force-pushed the generic-blob-endpoint-compressed branch 2 times, most recently from 2cc69cb to 07e8015 Compare May 19, 2026 15:30
Copilot AI review requested due to automatic review settings May 19, 2026 15:30
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 17 out of 19 changed files in this pull request and generated 7 comments.

Files not reviewed (2)
  • pkg/api/registry.pb.go: Language not supported
  • pkg/api/registry_grpc.pb.go: Language not supported

Comment thread pkg/cache/cache.go Outdated
Comment thread pkg/server/server_test.go Outdated
Comment thread pkg/server/server.go Outdated
Comment thread pkg/cache/pogrebv1.go
Comment thread pkg/server/server_test.go
Comment thread pkg/cache/meta_key.go
Comment thread pkg/cache/json.go Outdated
Copilot AI review requested due to automatic review settings May 19, 2026 15:47
@perdasilva perdasilva force-pushed the generic-blob-endpoint-compressed branch from c5b9a80 to ef719ce Compare May 19, 2026 15:54
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 17 out of 19 changed files in this pull request and generated 6 comments.

Files not reviewed (2)
  • pkg/api/registry.pb.go: Language not supported
  • pkg/api/registry_grpc.pb.go: Language not supported

Comment thread pkg/cache/cache.go
Comment thread pkg/cache/cache.go Outdated
Comment thread pkg/server/server.go Outdated
Comment thread pkg/server/server_test.go
Comment thread pkg/cache/pogrebv1.go
Comment thread cmd/opm/serve/serve.go Outdated
@perdasilva perdasilva force-pushed the generic-blob-endpoint-compressed branch from ef719ce to bb3283d Compare May 19, 2026 15:58
Copilot AI review requested due to automatic review settings May 19, 2026 16:01
@perdasilva perdasilva force-pushed the generic-blob-endpoint-compressed branch 3 times, most recently from 7bcc452 to 97a8931 Compare May 19, 2026 16:08
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 17 out of 19 changed files in this pull request and generated 8 comments.

Files not reviewed (2)
  • pkg/api/registry.pb.go: Language not supported
  • pkg/api/registry_grpc.pb.go: Language not supported

Comment thread cmd/registry-server/main.go Outdated
Comment thread cmd/opm/registry/serve.go Outdated
Comment thread cmd/configmap-server/main.go Outdated
Comment thread pkg/server/server.go
Comment thread pkg/cache/pogrebv1.go
Comment thread pkg/cache/cache.go
Comment thread pkg/server/server_test.go
Comment thread pkg/server/server.go
Add a new ExperimentalRegistry gRPC service with a streaming
ExperimentalListPackageCustomSchemas endpoint that returns custom
schema blobs stored in FBC catalogs, filtered by schema name and
optionally by package name.

The endpoint returns an empty stream unless the caller passes the
X-Acknowledge-Experimental gRPC metadata header with value "true".

- Extend cache backends (pogreb, JSON) with meta blob storage keyed
  by (schema, packageName)
- Add validated metaKey type to enforce schema/package constraints
- Register ExperimentalRegistry service in all server entry points
- Update README and AGENTS.md with usage documentation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Comment thread cmd/opm/registry/serve.go
}

api.RegisterRegistryServer(s, server.NewRegistryServer(store))
api.RegisterExperimentalRegistryServer(s, server.NewExperimentalRegistryServer(store))
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Drop this? opm registry serve is deprecated/legacy and only serves sqlite DBs directly.

s := grpc.NewServer()

api.RegisterRegistryServer(s, server.NewRegistryServer(store))
api.RegisterExperimentalRegistryServer(s, server.NewExperimentalRegistryServer(store))
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Drop this? I think this is only used for catalog sources with type: ConfigMap

I don't remember how those work, but iirc they predate and don't directly support FBC catalogs.

s := grpc.NewServer()

api.RegisterRegistryServer(s, server.NewRegistryServer(store))
api.RegisterExperimentalRegistryServer(s, server.NewExperimentalRegistryServer(store))
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Drop this? registry-server (iirc) is a separate binary with just the sqlite serving bits extracted.

Comment thread pkg/cache/pogrebv1.go
Comment on lines +184 to +185
// NOTE: pogreb does not support prefix/range scans, so this performs a full table scan. This scales
// linearly with the total number of entries (bundles + metas + index) and may be slow for large catalogs.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

What if we stored a single blob for each package + schema? Then SendMetas could lookup a specific key and send everything under that key.

I suppose the tradeoff would be that if there are a large number of blobs for a single schema + package, we'd end up loading all of that into memory, as opposed to the current situation of a single blob in memory at a time.

Comment thread pkg/server/server.go
Comment on lines +143 to +145
if err := json.Unmarshal(blob, &m); err != nil {
return status.Errorf(codes.Internal, "unmarshal custom schema blob: %v", err)
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This seems like it could be expensive if we're able to use a non-JSON blob in the cache? iirc the pogreb cache stores the other blobs directly with proto serialization. Could we have the closure directly provide structpb.NewStruct(m), and let the implementation decide how to get the blob into that format?

Comment thread README.md
Comment on lines +179 to +192
The server also exposes an experimental `ExperimentalRegistry` service:

```sh
$ grpcurl -plaintext localhost:50051 list api.ExperimentalRegistry
ExperimentalListPackageCustomSchemas
```

Experimental endpoints require the `X-Acknowledge-Experimental: true` gRPC metadata header. Without it, the endpoint returns an empty response.

```sh
grpcurl -plaintext -H 'X-Acknowledge-Experimental: true' \
-d '{"schema":"custom.operator.io","packageName":"mypkg"}' \
localhost:50051 api.ExperimentalRegistry/ExperimentalListPackageCustomSchemas
```
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

WDYT about leaving all of this undocumented?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Same with AGENTS.md?

Someone developing a client may point their agent at this repo. To be fair, the agent can probably figure this out anyway if they see our repo, but maybe we don't make it easy?

Comment thread pkg/server/server.go
md, _ := metadata.FromIncomingContext(stream.Context())
// Silently return an empty stream when the experimental header is absent
// so that unaware clients see no disruption.
if vals := md.Get("x-acknowledge-experimental"); len(vals) == 0 || vals[0] != "true" {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is this case-sensitive?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

go-apidiff-override kind/feature Categorizes issue or PR as related to a new feature.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants