Send requests to the destination and credential snyk-broker would - #128
Closed
shawnburke wants to merge 1 commit into
Closed
Send requests to the destination and credential snyk-broker would#128shawnburke wants to merge 1 commit into
shawnburke wants to merge 1 commit into
Conversation
shawnburke
marked this pull request as draft
August 26, 2026 22:01
shawnburke
force-pushed
the
grpc/accept-rules-audit
branch
from
August 27, 2026 00:08
d48277c to
458203f
Compare
shawnburke
force-pushed
the
grpc/accept-rules-audit
branch
from
August 27, 2026 00:20
458203f to
3fb4b44
Compare
shawnburke
marked this pull request as ready for review
August 27, 2026 00:26
shawnburke
force-pushed
the
grpc/accept-rules-audit
branch
from
August 27, 2026 00:32
3fb4b44 to
5464337
Compare
shawnburke
force-pushed
the
grpc/accept-rules-audit
branch
from
August 27, 2026 01:47
5464337 to
d2bc9af
Compare
shawnburke
force-pushed
the
grpc/accept-rules-audit
branch
from
August 27, 2026 06:12
d2bc9af to
339ec8c
Compare
shawnburke
force-pushed
the
grpc/accept-rules-audit
branch
from
August 27, 2026 21:03
339ec8c to
f8b0145
Compare
The last of the parity work: where a matched rule actually sends the
request, and what credential rides along.
Wildcard origins work on the tunnel path. 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", and
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, a registrable domain required;
the target host required for a family and refused outside it; the port
taken from the origin, never the header; duplicates and websocket upgrades
refused; a concrete origin refusing a 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 here rather than
lifted from the reflector, which keeps its own copy — the two suites are
how we know they agree while both exist.
A malformed wildcard origin is the one thing that stops the agent, and it
is 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, and treating a bad family as permissive would authorize hosts nobody
chose. Every other origin problem warns and fails per request, the way it
does on the snyk-broker path.
Auth matches auth-header.ts. "token" emitted Bearer, "raw" emitted the
token with a "raw " prefix instead of bare, and basic with a pre-encoded
token dropped it and sent base64(":") — an empty credential. A scheme is
now supported exactly when authHeaderBuilders has a builder for it, so the
set and the behaviour cannot drift; an unrecognized one warns and sends no
header, which is what the broker does with it.
Pool origins rotate again. Origin() expanded ${VAR} before the pool was
consulted, so a variable that exists only as VAR_POOL became the empty
string and every request failed, while pool_test.go — which exercises
PoolManager directly — stayed green.
auth.go, headers.go and origin.go are new files rather than more of
router.go: auth, header handling and origin policy each pulled out whole.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DFYsRuHoCbCBWEFvuaj9kV
shawnburke
force-pushed
the
grpc/accept-rules-audit
branch
from
August 27, 2026 21:16
f8b0145 to
c0af637
Compare
Collaborator
Author
|
Split into a three-PR stack so the auth fix and the pool fix can be reviewed and merged independently of the wildcard work:
#135's tree is byte-identical to this branch, so nothing is lost in the split. #133 is independent of the other two and can go in first. Branch |
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.
Context
This is a stack of PRs to get the new gRPC tunnel up to spec with
snyk-broker--- with nosnyk-brokerin the picture we have to implement all of the accept file parsing and routing in Go.Specifically I had Claude audit all of the test cases in
snyk-broker, figure out which ones we care about, and make sure that the new tunnel supports them properly. In addition, this folds in the new wildcards support.This PR is the culmination of that and is about 400 lines of code changes and then some things moving around and a lot of tests.
But this is the meat of the change, the earlier PRs were to ensure we parse accept files properly, this one focuses that we then apply and route them.
It adds and validates the following cases in the grpc path and does not touch the existing snyk-broker flows:
httpsonly, registrable domain requiredClaude stuff
Stack 4/4 — the last one. 1/4, 2/4 and 3/4 have all merged, so this now sits directly on
mainas a single commit.The last of the parity work: where a matched rule actually sends the request, and what credential rides along.
Wildcard origins work on the tunnel path
Routepreviously parsedhttps://*.googleapis.com, found a scheme and a host, and returned it verbatim — soaccept.google.jsondialed a literal*.googleapis.com.X-Cortex-Target-Hostwas neither validated nor removed, but forwarded to the upstream.The Router now enforces the policy the reflector does:
httpsonly, registrable domain requiredWritten 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's how we know they agree while both exist.One thing 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. And warn-and-ignore has no safe meaning there: treating a bad family as permissive would authorize hosts nobody chose. Every other origin problem warns and fails per request, as it does on the snyk-broker path.
Credentials match
auth-header.tstokenemittedBearer,rawemittedrawinstead of the bare token, andbasicwith a pre-encoded token dropped it and sentBasic Og==— base64 of":", an empty credential.A scheme is now supported exactly when
authHeaderBuildershas a builder for it, so the set and the behaviour can't drift — they were previously a set in one file and aswitchin another, raw literals in both. An unrecognized scheme warns and sends no header, which is what the broker does with one.Pools rotate again
Origin()expanded${VAR}before the pool was consulted, so a variable that exists only asVAR_POOLbecame the empty string and every request failed — whilepool_test.go, which exercisesPoolManagerdirectly, stayed green.varIsSetacceptsVAR_POOLas satisfying a required variable, so such a file loaded fine and then failed at runtime.Structure
auth.go,headers.goandorigin.goare new files rather than more ofrouter.go— auth, header handling and origin policy each pulled out whole.parseOriginreturns aparsedOrigin{url, wildcard}so the two halves of a destination decision travel together, andresolveTargetHostis a method on it.What the snyk-broker path sees
The only non-test consumers of
acceptfileoutsidegrpctunnelarecommon/integration.go(NewAcceptFile,AcceptFile),reflector.go(ResolverMap,StringValueResolver) andrelay_instance_manager.go(RenderContext,route.Origin()). Nothing inorigin.go,auth.go,headers.go,matcher.goorrouter.gois reachable from there —Path()andMatchRulehave no callers outsideacceptfileandgrpctunnel.That leaves two genuinely shared files, and both preserve behaviour:
ResolvePoolVarsnow delegates toresolveVars(s, true), which is its old body verbatim.Peekis new and only tunnel startup validation calls it.Origin()is the one real shared accessor.TestOriginContract(landed in 2/4) pins it, and it was also checked differentially againstmain's exact body across 17 origin shapes — scheme-less*.googleapis.com,1.2.3.4:8080,//protocol-relative,[::1]:8443,ftp://,%2Fmid-path — identical in all 17, the pre-existing panic on a scheme-lessIP:portincluded.REFLECTOR_TESTS=1 go test ./server/snykbroker/... ./common/...is green.No existing test or fixture is modified: the diff against
mainforagent/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.And one open question, not decided here: a caller-supplied
Authorizationstill passes through when the matched rule declares noauth. Pre-existing behaviour this stack doesn't change.The stack
main— merged🤖 Generated with Claude Code
https://claude.ai/code/session_01DFYsRuHoCbCBWEFvuaj9kV