Skip to content

Grpc-tunnel: implement wildcard origins w/ tests - #135

Merged
shawnburke merged 1 commit into
mainfrom
grpc/wildcard-origins
Aug 28, 2026
Merged

Grpc-tunnel: implement wildcard origins w/ tests#135
shawnburke merged 1 commit into
mainfrom
grpc/wildcard-origins

Conversation

@shawnburke

Copy link
Copy Markdown
Collaborator

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

Route parsed https://*.googleapis.com, found a scheme and a host, and returned it verbatim — so accept.google.json dialed a literal *.googleapis.com. And X-Cortex-Target-Host was neither validated nor removed, but forwarded to the upstream.

The policy

The Router now enforces what the reflector enforces:

  • 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 tunnel call carries no per-request routing once upgraded, so a family has no authority to upgrade against
  • 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

Rejections map to 403 and name the policy, never the value that failed it.

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 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 NewRouter now returns an error, which is the ripple through the five grpctunnel files.

What the snyk-broker path sees

Nothing in origin.go, headers.go, matcher.go or router.go is reachable from the reflector — Path() and MatchRule have no callers outside acceptfile and grpctunnel. The genuinely shared surface is Origin(), pinned by TestOriginContract, and ResolvePoolVars, which now delegates to resolveVars(s, true) — its old body verbatim. Peek is 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.go and relay_instance_manager.go is empty.

Known remaining divergences

Both are more permissive than snyk-broker, so a request the broker routed still routes:

  • valid header values compare case-insensitively; the broker is case-sensitive.
  • An empty values array means "the header must be present"; the broker rejects everything.

One open question, not decided here: a caller-supplied Authorization still passes through when the matched rule declares no auth. 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; absentHeaders asserts the target-host header never reaches the upstream.
  • go test ./server/snykbroker/... ./common/... green.

🤖 Generated with Claude Code

@shawnburke shawnburke changed the title Send requests only to a destination the accept file authorizes Grpc-tunnel: implement wildcard origins w/ tests Aug 28, 2026
@shawnburke
shawnburke force-pushed the grpc/wildcard-origins branch from 4782b93 to 146303c Compare August 28, 2026 06:33
Base automatically changed from grpc/pool-rotation to main August 28, 2026 10:42
`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
shawnburke force-pushed the grpc/wildcard-origins branch from 146303c to c624a75 Compare August 28, 2026 10:42
@shawnburke
shawnburke merged commit 0503bb8 into main Aug 28, 2026
16 checks passed
@shawnburke
shawnburke deleted the grpc/wildcard-origins branch August 28, 2026 10:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants