Skip to content

sr/context: implement /contexts/{context}/... prefixed handlers#30189

Open
nguyen-andrew wants to merge 10 commits intoredpanda-data:devfrom
nguyen-andrew:sr/context-prefix-handlers
Open

sr/context: implement /contexts/{context}/... prefixed handlers#30189
nguyen-andrew wants to merge 10 commits intoredpanda-data:devfrom
nguyen-andrew:sr/context-prefix-handlers

Conversation

@nguyen-andrew
Copy link
Copy Markdown
Member

@nguyen-andrew nguyen-andrew commented Apr 16, 2026

Implement /contexts/{context}/... prefixed routes for the Schema Registry,
allowing clients to target a non-default context by prefixing any endpoint URL
with /contexts/{context}. This is a Schema Registry compatibility
feature that lets serde clients point their schema.registry.url at a
context-prefixed base URL (e.g. http://host:8081/contexts/.serde) and
transparently register/lookup schemas in that context.

Each context-prefixed route extracts the {context} path parameter, rewrites
the request (scoping the subject, query param, or injecting a synthetic subject),
and delegates to the existing handler. Four URL-rewriting strategies cover all
endpoint shapes:

  • scope_subject_param — qualifies the {subject} path param with the context
  • scope_subject_query — injects/qualifies the ?subject query param
  • scope_subject_prefix_query — injects/prepends context into ?subjectPrefix
  • inject_context_as_subject — sets subject to context-only form for config/mode

Authorization uses a new context_prefix_subject resource type that qualifies
the subject with the context before the ACL check, so users cannot bypass
context isolation via the URL prefix.

Also fixes a bug where DELETE /contexts/{context} was not normalizing the
context path parameter before the default-context check.

Fixes CORE-15191

Backports Required

  • none - not a bug fix

Release Notes

Features

  • Schema Registry now accepts /contexts/{context}/... prefixed URLs on all
    endpoints, allowing serde clients to target a non-default context by
    configuring their base URL (e.g. schema.registry.url=http://host:8081/contexts/.myctx).

@nguyen-andrew nguyen-andrew requested a review from a team as a code owner April 16, 2026 06:22
Copilot AI review requested due to automatic review settings April 16, 2026 06:22
@nguyen-andrew nguyen-andrew self-assigned this Apr 16, 2026
@nguyen-andrew nguyen-andrew requested a review from pgellert April 16, 2026 06:25
Copy link
Copy Markdown
Contributor

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

This PR adds Confluent-compatible context-prefixed Schema Registry routes (/contexts/{context}/...) so clients can target non-default contexts by setting a context-prefixed base URL. It does this by introducing request-rewriting helpers to scope subjects/query params and by updating authorization to evaluate ACLs against the context-qualified subject derived from the URL prefix.

Changes:

  • Add /contexts/{context}/... route registrations that rewrite requests and delegate to existing handlers.
  • Introduce context parsing/normalization and subject scoping utilities, plus unit/integration tests for routing and ACL isolation.
  • Extend Schema Registry auth resource handling to support authorization against context-qualified subjects for prefixed routes.

Reviewed changes

Copilot reviewed 17 out of 18 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
tests/rptest/tests/schema_registry_test.py Adds end-to-end tests for context-prefixed routing, delete-context normalization, serde client base-URL behavior, and ACL isolation.
tests/go/go-kafka-serde/go.mod Updates Go toolchain/deps for the Go serde test client (used by the new serde acceptance test).
tests/go/go-kafka-serde/go.sum Updates dependency lockfile for the Go serde test client.
src/v/utils/variant.h Adds extend_variant_t helper to extend std::variant types.
src/v/utils/tests/variant_test.cc Compile-only test coverage for extend_variant_t.
src/v/utils/tests/BUILD Registers the new variant_test target.
src/v/pandaproxy/schema_registry/test/context_router.cc Adds unit tests for context normalization and request rewrite helpers.
src/v/pandaproxy/schema_registry/test/BUILD Registers the new context_router_test target.
src/v/pandaproxy/schema_registry/service.cc Registers context-prefixed routes and delegates via rewrite wrappers; updates route resource typing.
src/v/pandaproxy/schema_registry/handlers.cc Normalizes context path parameter when deleting contexts (bug fix).
src/v/pandaproxy/schema_registry/errors.h Adds context_invalid error info helper.
src/v/pandaproxy/schema_registry/error.h Adds context_invalid to the Schema Registry error_code enum.
src/v/pandaproxy/schema_registry/error.cc Maps context_invalid to an HTTP 400 response.
src/v/pandaproxy/schema_registry/context_router.h Implements context normalization and rewrite helpers for subject/path/query scoping.
src/v/pandaproxy/schema_registry/authorization.cc Updates auth resource extraction to support context-prefixed subject authorization.
src/v/pandaproxy/schema_registry/auth.h Introduces context_prefix_subject and route_resource to resolve route-time resources into auth-time resources.
src/v/pandaproxy/schema_registry/BUILD Adds context_router.h and links the variant utility into schema registry.
src/v/pandaproxy/api/api-doc/schema_registry.json Documents the new /contexts/{context}/... endpoints for compatibility.

Comment thread src/v/pandaproxy/schema_registry/service.cc Outdated
@nguyen-andrew nguyen-andrew force-pushed the sr/context-prefix-handlers branch from 5eae7af to 866cdb4 Compare April 16, 2026 06:45
@nguyen-andrew
Copy link
Copy Markdown
Member Author

Force push to address copilot comment

@vbotbuildovich
Copy link
Copy Markdown
Collaborator

vbotbuildovich commented Apr 16, 2026

Retry command for Build#83227

please wait until all jobs are finished before running the slash command

/ci-repeat 1
skip-redpanda-build
skip-units
skip-rebase
tests/rptest/tests/schema_registry_test.py::SchemaRegistryTest.test_serde_client@{"client_type":3,"protocol":2}
tests/rptest/tests/schema_registry_test.py::SchemaRegistryAutoAuthTest.test_serde_client@{"client_type":3,"protocol":2}

@vbotbuildovich
Copy link
Copy Markdown
Collaborator

CI test results

test results on build#83227
test_status test_class test_method test_arguments test_kind job_url passed reason test_history
FAIL SchemaRegistryAutoAuthTest test_serde_client {"client_type": 3, "protocol": 2} integration https://buildkite.com/redpanda/redpanda/builds/83227#019d9515-00a6-452b-bc92-3fbb72c794fb 0/11 Test FAILS after retries.Significant increase in flaky rate(baseline=0.0000, p0=0.0000, reject_threshold=0.0100) https://redpanda.metabaseapp.com/dashboard/87-tests?tab=142-dt-individual-test-history&test_class=SchemaRegistryAutoAuthTest&test_method=test_serde_client
FAIL SchemaRegistryAutoAuthTest test_serde_client {"client_type": 3, "protocol": 2} integration https://buildkite.com/redpanda/redpanda/builds/83227#019d9516-0cc1-4e30-aef3-3d3ea08fbfc1 0/11 Test FAILS after retries.Significant increase in flaky rate(baseline=0.0000, p0=0.0000, reject_threshold=0.0100) https://redpanda.metabaseapp.com/dashboard/87-tests?tab=142-dt-individual-test-history&test_class=SchemaRegistryAutoAuthTest&test_method=test_serde_client
FAIL SchemaRegistryTest test_serde_client {"client_type": 3, "protocol": 2} integration https://buildkite.com/redpanda/redpanda/builds/83227#019d9515-00a7-479f-8a0c-4e7748038bb4 0/11 Test FAILS after retries.Significant increase in flaky rate(baseline=0.0000, p0=0.0000, reject_threshold=0.0100) https://redpanda.metabaseapp.com/dashboard/87-tests?tab=142-dt-individual-test-history&test_class=SchemaRegistryTest&test_method=test_serde_client
FAIL SchemaRegistryTest test_serde_client {"client_type": 3, "protocol": 2} integration https://buildkite.com/redpanda/redpanda/builds/83227#019d9516-0cc2-43eb-a5b2-e16448c14dfe 0/11 Test FAILS after retries.Significant increase in flaky rate(baseline=0.0000, p0=0.0000, reject_threshold=0.0100) https://redpanda.metabaseapp.com/dashboard/87-tests?tab=142-dt-individual-test-history&test_class=SchemaRegistryTest&test_method=test_serde_client

@nguyen-andrew nguyen-andrew force-pushed the sr/context-prefix-handlers branch from 866cdb4 to 1bb9ae6 Compare April 16, 2026 16:44
@nguyen-andrew
Copy link
Copy Markdown
Member Author

Force push to change confluent-kafka-go upgrade to v2.3.0. The only thing we need from the upgrade is the URL path fix (confluent-kafka-go#943, landed in v2.1.0). Jumping to v2.14.0 was overkill and pulled in unnecessary transitive deps (Azure SDK, JWT, oauth2). v2.3.0 is the first stable release past the fix.

@nguyen-andrew nguyen-andrew force-pushed the sr/context-prefix-handlers branch from 1bb9ae6 to f3b2f7a Compare April 16, 2026 17:20
@nguyen-andrew
Copy link
Copy Markdown
Member Author

Force push to fold in a security fix. Snyk flagged 4 transitive vulns in tests/go/go-kafka-serde

Introduces context_router.h with inline helpers that will be used by
context-prefixed route wrappers:

- normalize_context(): canonicalize a URL path context parameter
    by stripping outer ':' delimiters, adding '.' prefix, and
    rejecting embedded colons (400 Bad Request via new
    context_invalid error code)
- starts_with_context(): detect subjects already qualified with
    a context prefix

Aliases like "staging", ":.staging:", and ".staging" all resolve to
the canonical form ".staging".

Includes gtest coverage for both helpers.

Includes gtest coverage for all helpers.
Adds a type-level utility for extending a std::variant with additional
alternative types without repeating the original type list. This enables
composing variant types where a superset variant needs all alternatives
from a base variant plus extras.
Splits the auth resource type into `route_resource` (route registration
time) and `resource` (authorization time). The new
`context_prefix_subject` variant in `route_resource` qualifies the
subject with the {context} path param before the ACL check runs, then
resolves to `context_subject`.

This ensures a user with ACLs on "foo" (default context) cannot access
:.staging:foo via the /contexts/.staging/subjects/foo/... URL.
Registers 15 context-prefixed routes that have a {subject} path
parameter. Each route extracts the context from the URL prefix,
scopes the subject with it via scope_subject_param(), and
delegates to the existing handler.

Covers: subject CRUD, versions, compatibility, config/{subject}, and
mode/{subject} — all via /contexts/{context}/... URLs.

Includes unit tests for scope_subject_param() and ducktape coverage
for all 15 endpoints and ACL isolation.
Registers 4 context-prefixed routes for /schemas/ids/{id} and its
sub-resources (/schema, /versions, /subjects). Adds a
scope_subject_query helper that injects the context as a "subject"
query parameter, scoping schema lookups to the specified context.

Includes unit tests for scope_subject_query and ducktape coverage
for schema lookup and sub-resource queries.
Adds scope_subject_prefix_query(), which injects or prepends the
normalized context into the subjectPrefix query parameter. The
context-prefixed GET /contexts/{context}/subjects route uses this
helper to scope subject listings to the specified context.

Includes unit tests for scope_subject_prefix_query and ducktape
coverage verifying subject isolation across contexts.
Registers context-prefixed routes for context-level config/mode and
schema types:

  - GET/PUT/DELETE /contexts/{context}/config
  - GET/PUT/DELETE /contexts/{context}/mode
  - GET /contexts/{context}/schemas/types (pass-through)

Adds inject_context_as_subject(), which sets the subject path
parameter to a context-only qualified subject (e.g., ":.staging:").
The config and mode wrappers use this to delegate to the existing
config/mode subject handlers. Schema types are global so the context
is accepted for compatibility but ignored.

Includes unit tests for inject_context_as_subject and ducktape
coverage for all operations.
While implementing context-prefixed route handlers, noticed that
DELETE /contexts/{context} was not normalizing the context path
parameter before the default-context check.

Apply normalize_context() to the context path parameter before the
default-context check. This ensures alias forms like "staging",
":.staging:", and ".staging" all resolve to the same canonical context
for deletion.

Includes ducktape coverage cycling through alias forms.
@nguyen-andrew nguyen-andrew force-pushed the sr/context-prefix-handlers branch from f3b2f7a to 179c951 Compare April 16, 2026 17:32
@nguyen-andrew
Copy link
Copy Markdown
Member Author

Force push to rebase on latest dev.

The v2.0.2 Schema Registry client stripped the path component from
URLs (confluent-kafka-go#943), preventing context-prefixed URLs
like /contexts/.serde from working. Fixed in v2.1.0 via PR redpanda-data#950.
A serde client configured with schema.registry.url pointing to
/contexts/.serde performs a full produce/consume round-trip. Verifies
schemas are registered in the target context and isolated from the
default context.

Parametrized across Python, Go, and Java clients to cover all
language ecosystems.
@nguyen-andrew nguyen-andrew force-pushed the sr/context-prefix-handlers branch from 179c951 to a921cd1 Compare April 16, 2026 18:51
@nguyen-andrew
Copy link
Copy Markdown
Member Author

Force push to bump golang/protobuf from v1.5.3 to v1.5.4 to try to fix issues with the CI docker image.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants