Skip to content

UPSTREAM: <carry>: Add GetCustomSchema OPM serve gRPC endpoint#1296

Draft
perdasilva wants to merge 1 commit into
openshift:mainfrom
perdasilva:opm-endpoint
Draft

UPSTREAM: <carry>: Add GetCustomSchema OPM serve gRPC endpoint#1296
perdasilva wants to merge 1 commit into
openshift:mainfrom
perdasilva:opm-endpoint

Conversation

@perdasilva
Copy link
Copy Markdown
Contributor

@perdasilva perdasilva commented May 11, 2026

Summary by CodeRabbit

  • New Features

    • Added GetCustomSchemas gRPC streaming endpoint to query custom schema metadata from the registry.
    • Extended registry cache to persist and serve non-standard schema blobs alongside standard OLM schemas.
  • Documentation

    • Updated API documentation and examples to reflect the new custom schema query capability.

Signed-off-by: Per G. da Silva <pegoncal@redhat.com>
@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented May 11, 2026

Skipping CI for Draft Pull Request.
If you want CI signal for your change, please convert it to an actual PR.
You can still manually trigger a test run with /test all

@openshift-ci openshift-ci Bot added the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label May 11, 2026
@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented May 11, 2026

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: perdasilva

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

@openshift-ci openshift-ci Bot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label May 11, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 11, 2026

Walkthrough

A new GetCustomSchemas gRPC streaming endpoint is added to the operator registry to query and stream custom schema metadata blobs. This requires proto definitions, cache backend storage/retrieval, a server handler, build system updates, and comprehensive test coverage across cache, client, and server layers.

Changes

Custom Schema Streaming

Layer / File(s) Summary
Proto Definitions
staging/operator-registry/pkg/api/registry.proto
New GetCustomSchemasRequest message and Registry.GetCustomSchemas RPC returning stream google.protobuf.Struct; imports google/protobuf/struct.proto.
Meta Key Validation
staging/operator-registry/pkg/cache/meta_key.go
New internal metaKey struct with path-traversal and separator validation; mutex-protected metaKeys type wrapping a B-tree to store and walk validated keys.
Cache Interface
staging/operator-registry/pkg/cache/cache.go
Adds Cache.SendCustomSchemas() method; extends Build() to parse, validate, and store custom schema meta blobs (non-standard schemas) via backend PutMeta; ensures uniqueness via seenMetaKeys tracking.
JSON Backend
staging/operator-registry/pkg/cache/json.go
Implements GetMeta, PutMeta, SendMetas for JSON file-based storage in cache/metas/.../*.json hierarchy; loadMetaKeys() scans on-disk meta structure during initialization.
Pogreb Backend
staging/operator-registry/pkg/cache/pogrebv1.go
Implements GetMeta, PutMeta, SendMetas for embedded pogreb DB with metas/<schema>/<package>/<name> key format; loads meta keys from DB during GetPackageIndex().
Server Handler
staging/operator-registry/pkg/server/server.go
New GetCustomSchemas RPC handler checks for customSchemaQuerier support; unmarshals JSON blobs to protobuf Struct and streams results to client; returns Unimplemented if unsupported.
Build Configuration
staging/operator-registry/Makefile, staging/operator-registry/scripts/ensure-protoc.sh
codegen target adds -I ./tools/bin/include to protoc; ensure-protoc.sh unpacks include/* headers alongside binary.
Tests & Client Stub
staging/operator-registry/pkg/cache/cache_test.go, staging/operator-registry/pkg/client/client_test.go, staging/operator-registry/pkg/server/server_test.go
New cache tests (customSchemaFS, namelessCustomSchemaFS fixtures) validate filtering, exclusion of standard OLM schemas, and unnamed blob handling; server test provisions custom-schema cache and verifies GetCustomSchemas streaming; client stub adds GetCustomSchemas method.
Documentation
staging/operator-registry/AGENTS.md, staging/operator-registry/README.md
Update gRPC method listings to include GetCustomSchemas.

Sequence Diagram

sequenceDiagram
    participant Client
    participant Server as gRPC Server
    participant CacheIface as Cache Interface
    participant Backend as Cache Backend
    
    Client->>Server: GetCustomSchemas(schema, packageName, name)
    Server->>Server: Check if store supports<br/>customSchemaQuerier
    alt unsupported
        Server-->>Client: Unimplemented error
    else supported
        Server->>CacheIface: SendCustomSchemas(ctx, filters...,<br/>sender callback)
        CacheIface->>Backend: SendMetas(ctx, sender)
        activate Backend
        loop for each stored meta key
            Backend->>Backend: Read blob from storage
            Backend->>CacheIface: sender(schema, pkg, name, blob)
        end
        deactivate Backend
        CacheIface->>Server: return error (if any)
        Server->>Server: Unmarshal JSON blob<br/>to map[string]interface{}
        Server->>Server: Convert map to<br/>protobuf Struct
        Server-->>Client: Stream Struct
    end
    Client->>Client: Receive stream of<br/>custom schema Structs
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 11 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (11 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: adding a GetCustomSchema gRPC endpoint to OPM serve, which aligns with the comprehensive changeset that implements this feature across proto definitions, cache, server, and tests.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Stable And Deterministic Test Names ✅ Passed The custom check requires Ginkgo test names to be stable and deterministic. This PR contains no Ginkgo tests—all tests use Go's standard testing package. All test names are static and deterministic.
Test Structure And Quality ✅ Passed Custom check targets Ginkgo BDD tests. PR adds standard Go tests (testing.T, testify), not Ginkgo. Not applicable.
Microshift Test Compatibility ✅ Passed No Ginkgo e2e tests are added in this PR. All test functions are standard Go unit tests using testing.T. The check is not applicable.
Single Node Openshift (Sno) Test Compatibility ✅ Passed PR does not add Ginkgo e2e tests. Changes are standard Go unit/integration tests using testing.T in pkg/cache and pkg/server, not Ginkgo syntax. No e2e test files modified.
Topology-Aware Scheduling Compatibility ✅ Passed PR makes no changes to deployment manifests or scheduling constraints. Only modifies Go source code, Protocol Buffer definitions, and documentation for a gRPC service in the operator-registry library.
Ote Binary Stdout Contract ✅ Passed Only library code in staging/operator-registry/pkg/ is modified. No main(), init(), or process-level functions write to stdout. TestMain uses logrus which writes to stderr. No stdout violations found.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed PR does not add any Ginkgo e2e tests. Changes are limited to unit tests in pkg/cache, pkg/server, and pkg/client using standard Go testing. The custom check is not applicable to this PR.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (1)
staging/operator-registry/pkg/server/server_test.go (1)

812-815: ⚡ Quick win

Cover the unfiltered RPC path against the populated custom-schema cache.

Right now the empty-request case only runs against cacheAddress, so it would still pass if the handler accidentally treated an empty Schema as “return nothing.” Adding an empty-schema case against customSchemaCacheAddress and asserting the two distinct resource names would make this new RPC coverage much harder to fool.

Also applies to: 827-841, 850-862

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@staging/operator-registry/pkg/server/server_test.go` around lines 812 - 815,
Add an empty-request test run that targets the populated custom-schema cache: in
TestGetCustomSchemas call testGetCustomSchemasEmpty(customSchemaCacheAddress)
(in addition to the existing cacheAddress case) and assert the response returns
the two distinct resource names expected; likewise update the related test runs
referenced (the blocks around lines 827–841 and 850–862) to invoke the
empty-schema path against customSchemaCacheAddress as well so the unfiltered RPC
path is exercised and the two resource names are asserted.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@staging/operator-registry/pkg/cache/json.go`:
- Around line 198-205: SendMetas currently discards the context parameter;
update jsonBackend.SendMetas to honor the provided ctx by checking ctx.Err() (or
ctx.Done()) inside the metas.Walk callback (before reading the file and before
calling sender) and return early with the context error when cancelled; locate
the jsonBackend.SendMetas function and its anonymous callback passed to
q.metas.Walk, add a context cancellation check at the top of that callback and
propagate ctx.Err() (or wrap it) instead of continuing to use q.metaFile,
os.ReadFile, or sender when cancelled.

In `@staging/operator-registry/pkg/cache/pogrebv1.go`:
- Around line 214-221: The SendMetas function currently ignores its context (it
uses _ context.Context) so pogreb scanning continues after cancellation; change
the signature to use the provided ctx and in the q.metas.Walk callback check
ctx.Err() before doing work (e.g., at the top of the Walk func) and return
ctx.Err() to stop the walk when canceled; ensure this check happens before
q.db.Get(q.metaDBKey(key)) and before calling sender(key.Schema,
key.PackageName, key.Name, data) so DB reads and sends stop promptly.

In `@staging/operator-registry/pkg/server/server.go`:
- Around line 117-129: The fmt.Errorf calls inside the lambda passed to
mq.SendCustomSchemas are not wrapping errors with %w; update the error returns
in the anonymous function (the json.Unmarshal error and the structpb.NewStruct
error) to use fmt.Errorf with %w so callers can inspect the underlying error
(i.e., change the two fmt.Errorf("%v", err) uses to use a descriptive message
and %w, keeping the same surrounding text in the function passed to
mq.SendCustomSchemas that ultimately calls stream.Send).

---

Nitpick comments:
In `@staging/operator-registry/pkg/server/server_test.go`:
- Around line 812-815: Add an empty-request test run that targets the populated
custom-schema cache: in TestGetCustomSchemas call
testGetCustomSchemasEmpty(customSchemaCacheAddress) (in addition to the existing
cacheAddress case) and assert the response returns the two distinct resource
names expected; likewise update the related test runs referenced (the blocks
around lines 827–841 and 850–862) to invoke the empty-schema path against
customSchemaCacheAddress as well so the unfiltered RPC path is exercised and the
two resource names are asserted.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: openshift/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: b75bca00-e245-487b-a36c-36f55ccac912

📥 Commits

Reviewing files that changed from the base of the PR and between 12c6652 and a764562.

⛔ Files ignored due to path filters (10)
  • staging/operator-registry/pkg/api/registry.pb.go is excluded by !**/*.pb.go
  • staging/operator-registry/pkg/api/registry_grpc.pb.go is excluded by !**/*.pb.go
  • vendor/github.com/operator-framework/operator-registry/pkg/api/registry.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/github.com/operator-framework/operator-registry/pkg/api/registry.proto is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/operator-framework/operator-registry/pkg/api/registry_grpc.pb.go is excluded by !**/*.pb.go, !**/vendor/**, !vendor/**
  • vendor/github.com/operator-framework/operator-registry/pkg/cache/cache.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/operator-framework/operator-registry/pkg/cache/json.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/operator-framework/operator-registry/pkg/cache/meta_key.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/operator-framework/operator-registry/pkg/cache/pogrebv1.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/operator-framework/operator-registry/pkg/server/server.go is excluded by !**/vendor/**, !vendor/**
📒 Files selected for processing (13)
  • staging/operator-registry/AGENTS.md
  • staging/operator-registry/Makefile
  • staging/operator-registry/README.md
  • staging/operator-registry/pkg/api/registry.proto
  • staging/operator-registry/pkg/cache/cache.go
  • staging/operator-registry/pkg/cache/cache_test.go
  • staging/operator-registry/pkg/cache/json.go
  • staging/operator-registry/pkg/cache/meta_key.go
  • staging/operator-registry/pkg/cache/pogrebv1.go
  • staging/operator-registry/pkg/client/client_test.go
  • staging/operator-registry/pkg/server/server.go
  • staging/operator-registry/pkg/server/server_test.go
  • staging/operator-registry/scripts/ensure-protoc.sh

Comment on lines +246 to +249
// defaultMetaName is used as the metaKey name for custom schema blobs that
// lack a "name" field. Since each (schema, packageName) pair must be unique,
// a collision on this sentinel indicates duplicate data in the FBC source.
const defaultMetaName = "noname"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

defaultMetaName can alias a real custom-schema entry.

A nameless blob and a blob explicitly named "noname" in the same (schema, package) collapse to the same metaKey, so this can raise a false duplicate custom schema meta error or make lookup ambiguous. Please encode “unnamed” separately or reserve/reject the sentinel for user-provided names.

Also applies to: 321-337

Comment on lines +198 to +205
func (q *jsonBackend) SendMetas(_ context.Context, sender func(schema, pkg, name string, blob []byte) error) error {
return q.metas.Walk(func(key metaKey) error {
data, err := os.ReadFile(q.metaFile(key))
if err != nil {
return fmt.Errorf("get meta %v: %w", key, err)
}
return sender(key.Schema, key.PackageName, key.Name, data)
})
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

# First, let's examine the actual code at the specified lines
head -n 210 staging/operator-registry/pkg/cache/json.go | tail -n 20

Repository: openshift/operator-framework-olm

Length of output: 689


🏁 Script executed:

# Let's get more context around the function
sed -n '195,210p' staging/operator-registry/pkg/cache/json.go

Repository: openshift/operator-framework-olm

Length of output: 575


🏁 Script executed:

# Let's find the Walk function definition to understand if it already supports context
rg "func.*Walk" staging/operator-registry/pkg/cache/json.go -A 3

Repository: openshift/operator-framework-olm

Length of output: 58


🏁 Script executed:

# Check the type of metas field and its Walk method
rg "metas\s*:" staging/operator-registry/pkg/cache/json.go -B 5 -A 2

Repository: openshift/operator-framework-olm

Length of output: 229


🏁 Script executed:

# Look for the entire jsonBackend struct
ast-grep --pattern 'type jsonBackend struct { $$$ }'

Repository: openshift/operator-framework-olm

Length of output: 855


🏁 Script executed:

# Find metaKeys type definition
rg "type metaKeys" staging/operator-registry/pkg/cache/json.go -A 5

Repository: openshift/operator-framework-olm

Length of output: 58


🏁 Script executed:

# Search for Walk method definition on metaKeys
rg "func.*metaKeys.*Walk" staging/operator-registry/pkg/cache/json.go -A 8

Repository: openshift/operator-framework-olm

Length of output: 58


🏁 Script executed:

# More general search for Walk method
rg "func.*\(.*metaKeys\).*Walk" staging/operator-registry/pkg/cache/json.go -A 8

Repository: openshift/operator-framework-olm

Length of output: 58


🏁 Script executed:

# Search for any Walk method in the file
rg "func.*Walk" staging/operator-registry/pkg/cache/ -A 5

Repository: openshift/operator-framework-olm

Length of output: 996


🏁 Script executed:

# Get full implementation of metaKeys.Walk
sed -n '/^func (m \*metaKeys) Walk/,/^func /p' staging/operator-registry/pkg/cache/meta_key.go | head -n 20

Repository: openshift/operator-framework-olm

Length of output: 364


🏁 Script executed:

# Get full implementation of bundleKeys.Walk
sed -n '/^func (b bundleKeys) Walk/,/^func /p' staging/operator-registry/pkg/cache/bundle_key.go | head -n 20

Repository: openshift/operator-framework-olm

Length of output: 245


🏁 Script executed:

# Check if there are similar Send* functions in other backends (file.go, sql.go, etc)
fd "\\.go$" staging/operator-registry/pkg/cache/ --exec grep -l "Send" {} \;

Repository: openshift/operator-framework-olm

Length of output: 263


🏁 Script executed:

# Look for other Send* functions that accept context
rg "func.*Send.*context.Context" staging/operator-registry/pkg/cache/ -A 3

Repository: openshift/operator-framework-olm

Length of output: 2542


🏁 Script executed:

# Find the interface that defines SendMetas
rg "SendMetas" staging/operator-registry/pkg/cache/ -B 3 | grep -E "(interface|type.*struct)" -A 10

Repository: openshift/operator-framework-olm

Length of output: 58


🏁 Script executed:

# Search for Backend interface definition
rg "type.*Backend" staging/operator-registry/pkg/cache/ | head -20

Repository: openshift/operator-framework-olm

Length of output: 224


🏁 Script executed:

# Look at cache.go to see the Backend interface
sed -n '1,100p' staging/operator-registry/pkg/cache/cache.go | grep -A 30 "interface"

Repository: openshift/operator-framework-olm

Length of output: 1281


🏁 Script executed:

# Search for Backend interface in cache.go more thoroughly
rg "interface" staging/operator-registry/pkg/cache/cache.go -A 20

Repository: openshift/operator-framework-olm

Length of output: 1091


🏁 Script executed:

# Check SendBundles implementation in json.go
sed -n '/func (q \*jsonBackend) SendBundles/,/^func /p' staging/operator-registry/pkg/cache/json.go | head -30

Repository: openshift/operator-framework-olm

Length of output: 1070


🏁 Script executed:

# Check SendBundles implementation in pogrebv1.go
sed -n '/func (q \*pogrebV1Backend) SendBundles/,/^func /p' staging/operator-registry/pkg/cache/pogrebv1.go | head -30

Repository: openshift/operator-framework-olm

Length of output: 670


Use the context parameter to cancel iteration on context cancellation.

The SendMetas method accepts context.Context per the interface contract but explicitly discards it with _. Since this function iterates over potentially many metadata blobs and reads each from disk, it should respect context cancellation—particularly when backing streamed RPCs. Add context error checks in the loop to abort early if the caller cancels.

Suggested change
-func (q *jsonBackend) SendMetas(_ context.Context, sender func(schema, pkg, name string, blob []byte) error) error {
+func (q *jsonBackend) SendMetas(ctx context.Context, sender func(schema, pkg, name string, blob []byte) error) error {
 	return q.metas.Walk(func(key metaKey) error {
+		if err := ctx.Err(); err != nil {
+			return err
+		}
 		data, err := os.ReadFile(q.metaFile(key))
 		if err != nil {
 			return fmt.Errorf("get meta %v: %w", key, err)
 		}
+		if err := ctx.Err(); err != nil {
+			return err
+		}
 		return sender(key.Schema, key.PackageName, key.Name, data)
 	})
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@staging/operator-registry/pkg/cache/json.go` around lines 198 - 205,
SendMetas currently discards the context parameter; update jsonBackend.SendMetas
to honor the provided ctx by checking ctx.Err() (or ctx.Done()) inside the
metas.Walk callback (before reading the file and before calling sender) and
return early with the context error when cancelled; locate the
jsonBackend.SendMetas function and its anonymous callback passed to
q.metas.Walk, add a context cancellation check at the top of that callback and
propagate ctx.Err() (or wrap it) instead of continuing to use q.metaFile,
os.ReadFile, or sender when cancelled.

Comment on lines +214 to +221
func (q *pogrebV1Backend) SendMetas(_ context.Context, sender func(schema, pkg, name string, blob []byte) error) error {
return q.metas.Walk(func(key metaKey) error {
data, err := q.db.Get(q.metaDBKey(key))
if err != nil {
return fmt.Errorf("get meta %v: %w", key, err)
}
return sender(key.Schema, key.PackageName, key.Name, data)
})
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

cat -n staging/operator-registry/pkg/cache/pogrebv1.go | head -250 | tail -50

Repository: openshift/operator-framework-olm

Length of output: 1733


🏁 Script executed:

wc -l staging/operator-registry/pkg/cache/pogrebv1.go

Repository: openshift/operator-framework-olm

Length of output: 128


🏁 Script executed:

cat -n staging/operator-registry/pkg/cache/pogrebv1.go | sed -n '200,230p'

Repository: openshift/operator-framework-olm

Length of output: 1226


🏁 Script executed:

rg -A 10 "func.*Walk" staging/operator-registry/pkg/cache/pogrebv1.go

Repository: openshift/operator-framework-olm

Length of output: 58


🏁 Script executed:

rg "func.*Backend.*Send" staging/operator-registry/pkg/cache/pogrebv1.go

Repository: openshift/operator-framework-olm

Length of output: 287


🏁 Script executed:

fd "*.go" staging/operator-registry/pkg/cache/ | head -10

Repository: openshift/operator-framework-olm

Length of output: 360


🏁 Script executed:

rg -A 8 "func.*SendMetas" staging/operator-registry/pkg/cache/

Repository: openshift/operator-framework-olm

Length of output: 1603


🏁 Script executed:

rg -B 5 -A 15 "func (q \*pogrebV1Backend) SendMetas" staging/operator-registry/pkg/cache/pogrebv1.go

Repository: openshift/operator-framework-olm

Length of output: 58


🏁 Script executed:

rg "\.Walk\(" staging/operator-registry/pkg/cache/pogrebv1.go

Repository: openshift/operator-framework-olm

Length of output: 290


🏁 Script executed:

rg -B 2 -A 10 "metas\.Walk" staging/operator-registry/pkg/cache/pogrebv1.go

Repository: openshift/operator-framework-olm

Length of output: 567


🏁 Script executed:

cat -n staging/operator-registry/pkg/cache/pogrebv1.go | sed -n '1,50p'

Repository: openshift/operator-framework-olm

Length of output: 1404


🏁 Script executed:

cat -n staging/operator-registry/pkg/cache/pogrebv1.go | sed -n '100,150p'

Repository: openshift/operator-framework-olm

Length of output: 1661


🏁 Script executed:

rg "metas" staging/operator-registry/pkg/cache/pogrebv1.go | head -20

Repository: openshift/operator-framework-olm

Length of output: 321


🏁 Script executed:

rg -B 5 -A 10 "type metaKeys" staging/operator-registry/pkg/cache/

Repository: openshift/operator-framework-olm

Length of output: 1128


🏁 Script executed:

rg -B 2 -A 15 "func.*metaKeys.*Walk" staging/operator-registry/pkg/cache/

Repository: openshift/operator-framework-olm

Length of output: 1231


🏁 Script executed:

rg -B 2 -A 15 "func.*SendBundles" staging/operator-registry/pkg/cache/pogrebv1.go

Repository: openshift/operator-framework-olm

Length of output: 673


🏁 Script executed:

rg -B 2 -A 15 "func.*SendBundles" staging/operator-registry/pkg/cache/json.go

Repository: openshift/operator-framework-olm

Length of output: 697


🏁 Script executed:

rg "ctx\.Err\(\)" staging/operator-registry/pkg/cache/

Repository: openshift/operator-framework-olm

Length of output: 58


🏁 Script executed:

rg "func.*Send" staging/operator-registry/pkg/cache/ | grep -v "BundleSender\|MetaSender"

Repository: openshift/operator-framework-olm

Length of output: 932


🏁 Script executed:

rg "func.*Send.*_ context.Context" staging/operator-registry/pkg/cache/

Repository: openshift/operator-framework-olm

Length of output: 674


🏁 Script executed:

rg -B 5 "SendMetas\|SendBundles" staging/operator-registry/pkg/cache/backend.go

Repository: openshift/operator-framework-olm

Length of output: 163


🏁 Script executed:

rg -B 3 -A 10 "type backend interface" staging/operator-registry/pkg/cache/

Repository: openshift/operator-framework-olm

Length of output: 1066


🏁 Script executed:

rg -B 3 -A 3 "select.*ctx\.Done\|if.*ctx\.Err" staging/operator-registry/pkg/ | head -40

Repository: openshift/operator-framework-olm

Length of output: 58


🏁 Script executed:

fd registry.go staging/operator-registry/pkg/ | head -3

Repository: openshift/operator-framework-olm

Length of output: 280


🏁 Script executed:

rg "SendMetas\|SendBundles" staging/operator-registry/pkg/registry/ | head -20

Repository: openshift/operator-framework-olm

Length of output: 58


🏁 Script executed:

rg -A 30 "type backend interface" staging/operator-registry/pkg/cache/cache.go

Repository: openshift/operator-framework-olm

Length of output: 948


🏁 Script executed:

rg -B 5 -A 8 "SendMetas" staging/operator-registry/pkg/registry/ | head -50

Repository: openshift/operator-framework-olm

Length of output: 58


🏁 Script executed:

rg "\.SendMetas\|\.SendBundles" staging/operator-registry/ --type go | head -30

Repository: openshift/operator-framework-olm

Length of output: 58


🏁 Script executed:

rg "SendMetas\|SendBundles" staging/operator-registry/ --type go | grep -E "test\.go|example|handler" | head -20

Repository: openshift/operator-framework-olm

Length of output: 58


🏁 Script executed:

fd "service.pb.go\|service.go" staging/operator-registry/pkg/api/ | head -5

Repository: openshift/operator-framework-olm

Length of output: 58


🏁 Script executed:

rg "Metas\|Bundles" staging/operator-registry/pkg/api/ | grep "func\|Sender" | head -20

Repository: openshift/operator-framework-olm

Length of output: 58


🏁 Script executed:

rg "ListBundles\|GetBundles" staging/operator-registry/pkg/ --type go | head -10

Repository: openshift/operator-framework-olm

Length of output: 58


🏁 Script executed:

fd "\.proto" staging/operator-registry/

Repository: openshift/operator-framework-olm

Length of output: 125


🏁 Script executed:

rg "rpc.*Meta\|rpc.*Bundle" staging/operator-registry/ | head -20

Repository: openshift/operator-framework-olm

Length of output: 58


🏁 Script executed:

rg -B 5 -A 10 "SendMetas\|SendBundles" staging/operator-registry/pkg/cache/cache.go

Repository: openshift/operator-framework-olm

Length of output: 58


🏁 Script executed:

rg "backend\|\.SendMetas\|\.SendBundles" staging/operator-registry/pkg/cache/cache.go | head -40

Repository: openshift/operator-framework-olm

Length of output: 58


🏁 Script executed:

cat -n staging/operator-registry/pkg/cache/cache.go | head -100

Repository: openshift/operator-framework-olm

Length of output: 3390


🏁 Script executed:

rg "func.*cache.*Send" staging/operator-registry/pkg/cache/cache.go

Repository: openshift/operator-framework-olm

Length of output: 318


🏁 Script executed:

cat -n staging/operator-registry/pkg/cache/json.go | sed -n '140,180p'

Repository: openshift/operator-framework-olm

Length of output: 1459


🏁 Script executed:

cat -n staging/operator-registry/pkg/cache/pogrebv1.go | sed -n '260,290p'

Repository: openshift/operator-framework-olm

Length of output: 1187


🏁 Script executed:

rg -B 5 -A 10 "c\.backend\.SendMetas\|backend\.SendMetas" staging/operator-registry/pkg/cache/cache.go

Repository: openshift/operator-framework-olm

Length of output: 58


🏁 Script executed:

cat -n staging/operator-registry/pkg/cache/cache.go | sed -n '200,300p'

Repository: openshift/operator-framework-olm

Length of output: 4497


🏁 Script executed:

rg "func.*cache.*" staging/operator-registry/pkg/cache/cache.go | head -20

Repository: openshift/operator-framework-olm

Length of output: 1677


🏁 Script executed:

cat -n staging/operator-registry/pkg/cache/cache.go | sed -n '251,264p'

Repository: openshift/operator-framework-olm

Length of output: 606


Honor cancellation while scanning Pogreb meta entries.

SendMetas keeps reading from Pogreb even after the request context is canceled. For a streamed gRPC path, that means unnecessary DB work after the client is already gone.

Suggested change
-func (q *pogrebV1Backend) SendMetas(_ context.Context, sender func(schema, pkg, name string, blob []byte) error) error {
+func (q *pogrebV1Backend) SendMetas(ctx context.Context, sender func(schema, pkg, name string, blob []byte) error) error {
 	return q.metas.Walk(func(key metaKey) error {
+		if err := ctx.Err(); err != nil {
+			return err
+		}
 		data, err := q.db.Get(q.metaDBKey(key))
 		if err != nil {
 			return fmt.Errorf("get meta %v: %w", key, err)
 		}
+		if err := ctx.Err(); err != nil {
+			return err
+		}
 		return sender(key.Schema, key.PackageName, key.Name, data)
 	})
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
func (q *pogrebV1Backend) SendMetas(_ context.Context, sender func(schema, pkg, name string, blob []byte) error) error {
return q.metas.Walk(func(key metaKey) error {
data, err := q.db.Get(q.metaDBKey(key))
if err != nil {
return fmt.Errorf("get meta %v: %w", key, err)
}
return sender(key.Schema, key.PackageName, key.Name, data)
})
func (q *pogrebV1Backend) SendMetas(ctx context.Context, sender func(schema, pkg, name string, blob []byte) error) error {
return q.metas.Walk(func(key metaKey) error {
if err := ctx.Err(); err != nil {
return err
}
data, err := q.db.Get(q.metaDBKey(key))
if err != nil {
return fmt.Errorf("get meta %v: %w", key, err)
}
if err := ctx.Err(); err != nil {
return err
}
return sender(key.Schema, key.PackageName, key.Name, data)
})
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@staging/operator-registry/pkg/cache/pogrebv1.go` around lines 214 - 221, The
SendMetas function currently ignores its context (it uses _ context.Context) so
pogreb scanning continues after cancellation; change the signature to use the
provided ctx and in the q.metas.Walk callback check ctx.Err() before doing work
(e.g., at the top of the Walk func) and return ctx.Err() to stop the walk when
canceled; ensure this check happens before q.db.Get(q.metaDBKey(key)) and before
calling sender(key.Schema, key.PackageName, key.Name, data) so DB reads and
sends stop promptly.

Comment on lines +117 to +129
return mq.SendCustomSchemas(stream.Context(), req.GetSchema(), req.GetPackageName(), req.GetName(),
func(_, _, _ string, blob []byte) error {
var m map[string]interface{}
if err := json.Unmarshal(blob, &m); err != nil {
return fmt.Errorf("unmarshal custom schema blob: %v", err)
}
s, err := structpb.NewStruct(m)
if err != nil {
return fmt.Errorf("convert custom schema blob to struct: %v", err)
}
return stream.Send(s)
})
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Wrap errors with %w for proper error chain propagation.

Lines 121 and 125 use fmt.Errorf with %v instead of %w. This breaks the error chain and prevents callers from using errors.Is or errors.As to inspect the underlying error.

🔧 Proposed fix
 			var m map[string]interface{}
 			if err := json.Unmarshal(blob, &m); err != nil {
-				return fmt.Errorf("unmarshal custom schema blob: %v", err)
+				return fmt.Errorf("unmarshal custom schema blob: %w", err)
 			}
 			s, err := structpb.NewStruct(m)
 			if err != nil {
-				return fmt.Errorf("convert custom schema blob to struct: %v", err)
+				return fmt.Errorf("convert custom schema blob to struct: %w", err)
 			}

As per coding guidelines: "Wrap errors with context using fmt.Errorf() with the %w verb in Go code" for files matching staging/operator-registry/**/*.go.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
return mq.SendCustomSchemas(stream.Context(), req.GetSchema(), req.GetPackageName(), req.GetName(),
func(_, _, _ string, blob []byte) error {
var m map[string]interface{}
if err := json.Unmarshal(blob, &m); err != nil {
return fmt.Errorf("unmarshal custom schema blob: %v", err)
}
s, err := structpb.NewStruct(m)
if err != nil {
return fmt.Errorf("convert custom schema blob to struct: %v", err)
}
return stream.Send(s)
})
}
return mq.SendCustomSchemas(stream.Context(), req.GetSchema(), req.GetPackageName(), req.GetName(),
func(_, _, _ string, blob []byte) error {
var m map[string]interface{}
if err := json.Unmarshal(blob, &m); err != nil {
return fmt.Errorf("unmarshal custom schema blob: %w", err)
}
s, err := structpb.NewStruct(m)
if err != nil {
return fmt.Errorf("convert custom schema blob to struct: %w", err)
}
return stream.Send(s)
})
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@staging/operator-registry/pkg/server/server.go` around lines 117 - 129, The
fmt.Errorf calls inside the lambda passed to mq.SendCustomSchemas are not
wrapping errors with %w; update the error returns in the anonymous function (the
json.Unmarshal error and the structpb.NewStruct error) to use fmt.Errorf with %w
so callers can inspect the underlying error (i.e., change the two
fmt.Errorf("%v", err) uses to use a descriptive message and %w, keeping the same
surrounding text in the function passed to mq.SendCustomSchemas that ultimately
calls stream.Send).

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. do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant