Skip to content

Add ExperimentalListPackageCustomSchemas gRPC endpoint#1981

Merged
openshift-merge-bot[bot] merged 1 commit into
operator-framework:masterfrom
perdasilva:generic-blob-endpoint-compressed
May 21, 2026
Merged

Add ExperimentalListPackageCustomSchemas gRPC endpoint#1981
openshift-merge-bot[bot] merged 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 streaming gRPC endpoint for querying custom (non-core) FBC schema blobs from catalog caches. This enables clients like catalogd to serve arbitrary user-defined catalog metadata alongside the standard olm.package/olm.channel/olm.bundle schemas.

  • New ExperimentalRegistry gRPC service with ExperimentalListPackageCustomSchemas streaming RPC
  • Gated behind X-Acknowledge-Experimental: true gRPC metadata header — absent header silently returns an empty stream
  • Input validation via allowlist regex (^[a-zA-Z0-9][a-zA-Z0-9._-]*$) to prevent path traversal in cache lookups
  • Both JSON (filesystem) and pogreb (embedded KV) cache backends extended with PutMeta/SendMetas for custom schema blob storage
  • Pogreb uses length-prefixed composite keys for O(1) per-key lookup
  • Protoc setup updated to extract well-known proto types (google/protobuf/struct.proto) for codegen

Test plan

  • Unit tests for metaKey validation (valid keys, empty, path traversal, dot sequences, leading special chars, filesystem-unsafe characters)
  • 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, cancelled context)
  • go test ./pkg/cache/... ./pkg/server/...

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 67.44186% with 84 lines in your changes missing coverage. Please review.
✅ Project coverage is 58.77%. Comparing base (210e5d6) to head (88aefd9).
⚠️ Report is 13 commits behind head on master.

Files with missing lines Patch % Lines
pkg/api/registry.pb.go 72.64% 24 Missing and 5 partials ⚠️
pkg/cache/pogrebv1.go 57.57% 8 Missing and 6 partials ⚠️
pkg/cache/json.go 62.06% 7 Missing and 4 partials ⚠️
pkg/server/server.go 56.00% 9 Missing and 2 partials ⚠️
pkg/api/registry_grpc.pb.go 68.96% 6 Missing and 3 partials ⚠️
pkg/cache/cache.go 61.90% 4 Missing and 4 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    13418      -23     
==========================================
+ Hits         7783     7887     +104     
+ Misses       4470     4322     -148     
- Partials     1188     1209      +21     

☔ 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 Outdated
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 Outdated
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
Comment thread pkg/server/server.go Outdated
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?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

kk - I've updated the closure's signature and refactored. Now it provides a pbf struct as opposed to []bytes

Comment thread README.md Outdated
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 Outdated
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?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I believe so. The docs say that the key is converted to lower-case before searching the headers.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I've tested it out manually and can confirm its not case-sensitive

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I also moved the header to a constant

Copilot AI review requested due to automatic review settings May 20, 2026 08:06
@perdasilva perdasilva force-pushed the generic-blob-endpoint-compressed branch from 9e45498 to 9b06802 Compare May 20, 2026 08:06
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 2 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
Comment thread pkg/cache/meta_key.go
@perdasilva perdasilva force-pushed the generic-blob-endpoint-compressed branch from 9b06802 to ab796de Compare May 20, 2026 08:34
Copilot AI review requested due to automatic review settings May 20, 2026 09:14
@perdasilva perdasilva force-pushed the generic-blob-endpoint-compressed branch from ab796de to 712779c Compare May 20, 2026 09:14
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
Comments suppressed due to low confidence (2)

pkg/cache/pogrebv1.go:188

  • SendMetas returns nil for any error from q.db.Get(...), not just "key not found". This will silently hide real DB failures and make clients think there are simply no results. Consider returning the error unless it is the expected not-found condition.
func (q *pogrebV1Backend) SendMetas(ctx context.Context, key metaKey, sender func([]byte) error) error {
	data, err := q.db.Get(q.metaDBKey(key))
	if err != nil || len(data) == 0 {
		return nil
	}

pkg/cache/pogrebv1.go:206

  • SendMetas ignores trailing bytes if the stored value is corrupted such that fewer than 4 bytes remain after parsing blobs (the loop exits and returns nil). This can silently drop data/corruption signals. Consider validating that the value is fully consumed (len(data)==0) after the loop, and returning an error otherwise.
			return err
		}
		data = data[blobLen:]
	}
	return nil
}

Comment thread pkg/server/server.go
Comment thread pkg/cache/pogrebv1.go
Comment thread pkg/cache/meta_key.go
Comment thread pkg/cache/meta_key.go
@perdasilva perdasilva force-pushed the generic-blob-endpoint-compressed branch from 712779c to 2efb1d3 Compare May 20, 2026 10:01
Copilot AI review requested due to automatic review settings May 20, 2026 10:04
@perdasilva perdasilva force-pushed the generic-blob-endpoint-compressed branch from 2efb1d3 to 2296dab Compare May 20, 2026 10:04
@perdasilva perdasilva force-pushed the generic-blob-endpoint-compressed branch from 2296dab to 3089411 Compare May 20, 2026 10:05
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 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 cmd/opm/serve/serve.go
Comment thread pkg/cache/cache.go Outdated
Comment thread pkg/api/registry.proto
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
Comments suppressed due to low confidence (2)

pkg/cache/pogrebv1.go:191

  • SendMetas returns an error when q.db.Get fails. For lookups where no metas exist for the requested key, this should return an empty result (nil) rather than surfacing a storage-layer not-found as a fatal error to callers. Treat the not-found case as "no metas" and return nil.
	binary.BigEndian.PutUint32(header, uint32(len(blob))) //#nosec G115 -- bounds checked above
	return q.db.Put(dbKey, append(existing, append(header, blob...)...))
}

func (q *pogrebV1Backend) SendMetas(ctx context.Context, key metaKey, sender func([]byte) error) error {
	data, err := q.db.Get(q.metaDBKey(key))
	if err != nil {
		return fmt.Errorf("read meta blobs: %w", err)

scripts/ensure-protoc.sh:16

  • The fetch_cmd uses unquoted ${DEST} in rm/mkdir -p, which can break if the repo root path contains spaces or glob characters. Quote these path expansions consistently (similar to how other parts of the command already quote ${DEST}) to avoid word-splitting issues.
fetch_cmd="(curl -sSfLo '${DEST}/protoc-${ver}.zip' 'https://github.com/protocolbuffers/protobuf/releases/download/v${ver}/protoc-${ver}-${os}-${arch}.zip' && unzip -o -j -d '${DEST}' '${DEST}/protoc-${ver}.zip' bin/protoc && unzip -o -d '${DEST}' '${DEST}/protoc-${ver}.zip' 'include/*' && rm ${DEST}/protoc-${ver}.zip)"

if [[ "${ver}" != "$(eval ${ver_cmd})" ]]; then
  echo "protoc missing or not version '${ver}', downloading..."
  mkdir -p ${DEST}
  eval ${fetch_cmd}

Comment thread pkg/cache/pogrebv1.go
Comment thread pkg/cache/pogrebv1.go
Comment thread pkg/cache/meta_key.go
Comment thread cmd/opm/serve/serve.go
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 1 comment.

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)

scripts/ensure-protoc.sh:16

  • This script builds a command string containing the user-supplied version and executes it via eval. If a caller passes a malicious version string containing shell metacharacters/quotes, it could lead to arbitrary command execution. Consider avoiding eval by invoking curl/unzip directly (or strictly validating/sanitizing the version argument and quoting ${DEST} in the rm/mkdir calls).
os="$(uname -s | sed 's/Darwin/osx/')"
arch="$(uname -m | sed 's/arm64/aarch_64/')"
fetch_cmd="(curl -sSfLo '${DEST}/protoc-${ver}.zip' 'https://github.com/protocolbuffers/protobuf/releases/download/v${ver}/protoc-${ver}-${os}-${arch}.zip' && unzip -o -j -d '${DEST}' '${DEST}/protoc-${ver}.zip' bin/protoc && unzip -o -d '${DEST}' '${DEST}/protoc-${ver}.zip' 'include/*' && rm ${DEST}/protoc-${ver}.zip)"

if [[ "${ver}" != "$(eval ${ver_cmd})" ]]; then
  echo "protoc missing or not version '${ver}', downloading..."
  mkdir -p ${DEST}
  eval ${fetch_cmd}

Comment thread pkg/cache/cache.go Outdated
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 no new comments.

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

Introduce a new ExperimentalRegistry gRPC service with a streaming
endpoint for retrieving custom schema blobs (non-core FBC schemas like
"custom.operator.io") from catalog caches, filtered by schema name and
optionally by package name.

Design:
- Separate ExperimentalRegistry service to isolate experimental API
  surface from the stable Registry service
- Callers must send X-Acknowledge-Experimental: true as gRPC metadata;
  without it the endpoint silently returns an empty stream
- Schema and package name inputs are validated against an allowlist
  regex to prevent path traversal
- Both JSON (filesystem) and pogreb (embedded KV) cache backends
  implement PutMeta/SendMetas for storing and streaming custom schema
  blobs at build and query time
- Pogreb stores multiple blobs per (schema, package) key using
  length-prefixed encoding for O(1) lookup

Also:
- Extract protobuf well-known types (google/protobuf/struct.proto)
  during protoc download so codegen can import them
- Add ListBundles to README API listing

Signed-off-by: Per G. da Silva <pegoncal@redhat.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Per G. da Silva <pegoncal@redhat.com>
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 12 out of 14 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/cache/pogrebv1.go
Comment on lines +174 to +186
func (q *pogrebV1Backend) PutMeta(_ context.Context, key metaKey, blob []byte) error {
if len(blob) > math.MaxUint32 {
return fmt.Errorf("meta blob too large: %d bytes exceeds uint32 max", len(blob))
}
dbKey := q.metaDBKey(key)
existing, err := q.db.Get(dbKey)
if err != nil {
return fmt.Errorf("read existing meta blobs: %w", err)
}
header := make([]byte, 4)
binary.BigEndian.PutUint32(header, uint32(len(blob))) //#nosec G115 -- bounds checked above
return q.db.Put(dbKey, append(existing, append(header, blob...)...))
}
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This is a copilot hiccup - Get returns nil on not found not an error

Comment thread pkg/cache/pogrebv1.go
Comment on lines +188 to +195
func (q *pogrebV1Backend) SendMetas(ctx context.Context, key metaKey, sender func([]byte) error) error {
data, err := q.db.Get(q.metaDBKey(key))
if err != nil {
return fmt.Errorf("read meta blobs: %w", err)
}
if len(data) == 0 {
return nil
}
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This is a copilot hiccup - Get returns nil on not found not an error

Comment thread pkg/cache/pogrebv1.go
Comment on lines +170 to +172
func (q *pogrebV1Backend) metaDBKey(in metaKey) []byte {
return []byte(fmt.Sprintf("%s%s/%s", metaKeyPrefix, in.Schema, in.PackageName))
}
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The length prefix is to do with how the list of documents are stored against the key

Comment thread pkg/server/server.go
Comment on lines +124 to +128
func (s *ExperimentalRegistryServer) ExperimentalListPackageCustomSchemas(req *api.ExperimentalListPackageCustomSchemasRequest, stream api.ExperimentalRegistry_ExperimentalListPackageCustomSchemasServer) error {
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(headerXAcknowledgeExperimental); len(vals) == 0 || vals[0] != "true" {
@perdasilva
Copy link
Copy Markdown
Contributor Author

Re: experimental header gating

Intentionally checking only vals[0] here. The header is a simple opt-in gate where clients set it exactly once with value "true". Checking the first value is the standard pattern for single-value gRPC metadata — the client's original value is always first, with any middleware-appended values after it. Accepting any value matching "true" would weaken the signal (e.g. a client explicitly setting "false" followed by middleware appending "true" shouldn't be treated as opting in).

@fgiudici
Copy link
Copy Markdown
Member

/lgtm

@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented May 21, 2026

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: grokspawn

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

Comment thread pkg/cache/pogrebv1.go
}
header := make([]byte, 4)
binary.BigEndian.PutUint32(header, uint32(len(blob))) //#nosec G115 -- bounds checked above
return q.db.Put(dbKey, append(existing, append(header, blob...)...))
Copy link
Copy Markdown
Member

@joelanford joelanford May 21, 2026

Choose a reason for hiding this comment

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

This is still JSON we're writing to the cache right? I was thinking something like this:

st := &structpb.Struct{}
st.UnmarshalJSON(meta.Blob)
protoBytes := proto.Marshal(st)
header := make([]byte, 4)
binary.BigEndian.PutUint32(header, uint32(len(protoBytes))) //#nosec G115 -- bounds checked above
return q.db.Put(dbKey, append(existing, append(header, protoBytes...)...))

Unmarshaling that at read time will be much more efficient, I think.

Comment thread pkg/cache/pogrebv1.go
return q.db.Put(dbKey, append(existing, append(header, blob...)...))
}

func (q *pogrebV1Backend) SendMetas(ctx context.Context, key metaKey, sender func([]byte) error) error {
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.

Plumb sender func(meta *structpb.Struct) error all the way through to the backend. That way the cached can choose how to represent it.

Suggested change
func (q *pogrebV1Backend) SendMetas(ctx context.Context, key metaKey, sender func([]byte) error) error {
func (q *pogrebV1Backend) SendMetas(ctx context.Context, key metaKey, sender func(meta *structpb.Struct) error) error {

Comment thread pkg/cache/pogrebv1.go
return fmt.Errorf("meta blob too large: %d bytes exceeds uint32 max", len(blob))
}
dbKey := q.metaDBKey(key)
existing, err := q.db.Get(dbKey)
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.

I didn't think about the iterative append process of the cache key/value here. This might be hell on the Go GC if there are every multiple blobs for the same key. In our existing use case, we don't expect that. Maybe if this becomes problematic for a future use case, we make another cache implementation that supports prefix/range scans.

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

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. go-apidiff-override kind/feature Categorizes issue or PR as related to a new feature. lgtm Indicates that a PR is ready to be merged.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants