Skip to content

feat: support gateway token passthrough for embedded controllers - #3263

Open
codyhartsook wants to merge 5 commits into
mainfrom
codyhartsook/tokenPassthroughGateway
Open

codyhartsook wants to merge 5 commits into
mainfrom
codyhartsook/tokenPassthroughGateway

Conversation

@codyhartsook

@codyhartsook codyhartsook commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Lets an embedding controller deliver tokenPassthrough credentials at the egress gateway, through app.Options.EgressPolicyCompilers. Builds on #3177 and #3257.

  • Revisions record each passthrough client as a target {origin, header, prefix} on egress Access.
  • token_passthrough_targets replaces token_passthrough_origins in the unreleased baseline migration.
  • Compilers run in order after the built-in EgressPolicy compiler and may change the policy. Kagent then validates it.
  • With any compiler registered, every target must be bound.
  • If a compiler or the validation fails, the actor gets no egress until a retry succeeds.
  • The embedder's UpstreamAuth must swap the caller token for the kagent-credential-injected placeholder, which the ADK forwards.
  • Covers Go ADK MCP and models, and Python OpenAI/Anthropic models. Claude, Codex, Python MCP, Ollama and Bedrock are follow-ups.

Behavior change with no compiler registered:

  • A passthrough origin can't be shared with MCP or model clients that don't opt in, or with an explicit header matching a target.

The Migration Immutability check fails because this edits 000001_initial.sql, as that file's header allows until the 1.0 release.

Testing: the affected race suites and the migration and PostgreSQL round-trip tests pass locally, and CI lint passes.

@github-actions github-actions Bot added enhancement New feature or request and removed enhancement New feature or request labels Oct 19, 2026
QuentinBisson added a commit to giantswarm/kagent-upstream that referenced this pull request Oct 19, 2026
@codyhartsook
codyhartsook force-pushed the codyhartsook/tokenPassthroughGateway branch from 919ddbf to 447b070 Compare October 19, 2026 15:13
@EItanya

EItanya commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

🤖 AI-generated review.

I think this is putting the extension behavior too high in the stack. The use case is that we want different behavior on the compiled Substrate EgressPolicy for specific tokenPassthrough origins. However, this threads a provider name through app, the controller, the generic translator, and every harness compiler, then hardcodes the provider URI format in credential compilation.

Could we make EgressPolicy compilation extensible instead? I'm thinking of a simple ordered compiler chain:

type EgressPolicyCompiler interface {
    Compile(context.Context, EgressPolicyInput, *ateapipb.EgressPolicy) error
}

The OSS compiler would always run first and build the normal allowlist and credential effects. Embedded controllers could register additional compilers that run afterward and add their behavior for the relevant origins. The chain would validate the final policy and reject conflicting effects rather than using last-writer-wins.

That would let the generic compilation path keep tokenPassthrough as semantic, origin-scoped information, while the vendor compiler decides how that becomes an EgressPolicy effect. It also gives us a reusable backend extension point without making Claude, Codex, ADK, models, or MCP compilation know about a particular provider or URI protocol.

With that boundary, I don't think we need TokenPassthroughProvider or most of the provider-specific translator and harness changes in this PR.

Signed-off-by: Cody Hartsook <cody.hartsook@solo.io>
@codyhartsook
codyhartsook force-pushed the codyhartsook/tokenPassthroughGateway branch from 447b070 to c73cf6a Compare October 19, 2026 19:27
@github-actions github-actions Bot added enhancement New feature or request and removed enhancement New feature or request labels Oct 19, 2026
@codyhartsook
codyhartsook marked this pull request as ready for review October 19, 2026 19:46
@codyhartsook
codyhartsook requested review from a team and supreme-gg-gg as code owners October 19, 2026 19:46
return egress.Access{}, nil, err
}
return egress.EffectiveAccess(base, grants, row.TokenPassthroughOrigins)
return access, targets, nil

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

should passthrough targets be a part of access?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yeah, makes sense. I kept them separate because targets are pinned to the revision, but they can live on Access

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why are targets pinned to the revision?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

so the gateway policy matches the actor’s compiled config, even after the Agent or ModelConfig change

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

updated so they are on Access

// host set the request goes to that host, so api.ollama.com never
// needs to be reachable.
hasCredential := modelConfig.Spec.APIKeySecret != "" || modelConfig.Spec.TokenPassthrough
hasCredential := modelConfig.Spec.APIKeySecret != ""

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Ollama doesn’t read the caller token today, so added a validation error for passthrough and removed because its now unreachable. Could split that into a separate fix

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I know there's the ability to use ollama cloud, but you're the Ollama client doesn't support passthrough?

@codyhartsook codyhartsook Oct 19, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

🤖 AI assisted response.

Ollama Cloud works with a Secret key, but our Ollama clients never read the caller token. The Go ADK takes the key only from OLLAMA_API_KEY, and the Python ADK ignores api_key_passthrough. So tokenPassthrough on an Ollama model has no effect today. With no key, a cloud model even routes to the local daemon. Supporting it means having the Ollama client use the passthrough token, which I'd do as a follow-up

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

reverted, I'll address this in a follow up instead

}
// Populate shared transport settings.
populateTLSFields(ollama, model.Spec.TLS)
ollama.ApiKeyPassthrough = model.Spec.TokenPassthrough

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

same reason as above, the ollama runtime never reads this flag. I’ll keep these changes together in a separate fix

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

reverted


// Populate shared transport settings.
populateTLSFields(bedrock, model.Spec.TLS)
bedrock.ApiKeyPassthrough = model.Spec.TokenPassthrough

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

same issue with Bedrock, the runtime doesn’t use this flag to forward the caller token

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

reverted


// validCredentialURI accepts ate-secret://<provider>/<path>. Provider names are
// lowercase DNS names without ports. k8s.io paths name one Secret key.
func validCredentialURI(raw string) error {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Did this functionality move or did it just get added?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

a bit of both. I pulled the existing validation into a helper for clarity and expanded it to allow other credential providers. The k8s.io checks stay intact. Func was getting a bit hard to read

teemow pushed a commit to giantswarm/kagent-upstream that referenced this pull request Oct 19, 2026
teemow pushed a commit to giantswarm/kagent-upstream that referenced this pull request Oct 19, 2026
Signed-off-by: Cody Hartsook <cody.hartsook@solo.io>
…low-up

Signed-off-by: Cody Hartsook <cody.hartsook@solo.io>
Signed-off-by: Cody Hartsook <cody.hartsook@solo.io>
@codyhartsook
codyhartsook requested a review from EItanya October 20, 2026 01:01
Signed-off-by: Cody Hartsook <cody.hartsook@solo.io>
@github-actions github-actions Bot added enhancement New feature or request and removed enhancement New feature or request labels Oct 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants