Grpc-tunnel: implement wildcard origins w/ tests - #135
Merged
Conversation
aszarama
approved these changes
Aug 28, 2026
shawnburke
force-pushed
the
grpc/wildcard-origins
branch
from
August 28, 2026 06:33
4782b93 to
146303c
Compare
`Route` previously parsed `https://*.googleapis.com`, found a scheme and a host, and returned it verbatim — so `accept.google.json` dialed a literal `*.googleapis.com`. `X-Cortex-Target-Host` was neither validated nor removed, but forwarded to the upstream. The Router now enforces the policy the reflector does: - one wildcard, leftmost label only, https only, registrable domain required - a family requires a target host; absent, duplicated or outside-policy is refused - the port comes from the origin, never the header - a websocket upgrade on a family is refused - a concrete origin refuses a target host that disagrees with it - the header comes off the request before rules are consulted, so it can neither reach the upstream nor select a rule Written fresh in `acceptfile` rather than lifted from the reflector, which keeps its own copy. `origin_test.go` mirrors the reflector's wildcard suite case for case — that is how we know they agree while both exist. One thing stops the agent: a malformed wildcard origin. The snyk-broker path refuses it too, so no working deployment carries one, and treating a bad family as permissive would authorize hosts nobody chose. Every other origin problem warns and fails per request. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
shawnburke
force-pushed
the
grpc/wildcard-origins
branch
from
August 28, 2026 10:42
146303c to
c624a75
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stack 3/3 — base #134. This is the top commit only; the tree is byte-identical to the original #128.
Replaces #128, split into three so the auth fix and the pool fix can be reviewed and merged on their own.
The bug
Routeparsedhttps://*.googleapis.com, found a scheme and a host, and returned it verbatim — soaccept.google.jsondialed a literal*.googleapis.com. AndX-Cortex-Target-Hostwas neither validated nor removed, but forwarded to the upstream.The policy
The Router now enforces what the reflector enforces:
httpsonly, registrable domain requiredRejections map to 403 and name the policy, never the value that failed it.
Written fresh in
acceptfilerather than lifted from the reflector, which keeps its own copy.origin_test.gomirrors the reflector's wildcard suite case for case — that is how we know the two agree while both exist.The one thing that stops the agent
A malformed wildcard origin. Not a migration risk: the snyk-broker path refuses it too — at render, or by panicking when the reflector is off — so no working deployment carries one. Warn-and-ignore has no safe meaning here, since treating a bad family as permissive would authorize hosts nobody chose. Every other origin problem warns and fails per request, as on the snyk-broker path.
This is why
NewRouternow returns an error, which is the ripple through the fivegrpctunnelfiles.What the snyk-broker path sees
Nothing in
origin.go,headers.go,matcher.goorrouter.gois reachable from the reflector —Path()andMatchRulehave no callers outsideacceptfileandgrpctunnel. The genuinely shared surface isOrigin(), pinned byTestOriginContract, andResolvePoolVars, which now delegates toresolveVars(s, true)— its old body verbatim.Peekis new and only startup validation calls it, so validating a pool does not shift which member the first request lands on.No existing test or fixture is modified: the diff for
agent/common/,agent/test/relay/,agent/test/load/,reflector.goandrelay_instance_manager.gois empty.Known remaining divergences
Both are more permissive than snyk-broker, so a request the broker routed still routes:
validheader values compare case-insensitively; the broker is case-sensitive.valuesarray means "the header must be present"; the broker rejects everything.One open question, not decided here: a caller-supplied
Authorizationstill passes through when the matched rule declares noauth. Pre-existing; this stack does not change it.Test plan
origin_test.go— wildcard policy in isolation, mirroring the reflector's suite.router_wildcard_test.go— the policy as applied during routing, including header stripping and the websocket refusal.test/conformance/wildcard_origins.json— transport-agnostic fixtures;absentHeadersasserts the target-host header never reaches the upstream.go test ./server/snykbroker/... ./common/...green.🤖 Generated with Claude Code