Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
88f4e13
Add Redis client utility and corresponding tests
Thenujan-Nagaratnam Aug 7, 2026
d419ca0
Enhance Redis client to support distinct protocols and improve connec…
Thenujan-Nagaratnam Aug 7, 2026
961f77a
Improve test for Redis client connection handling during ping to ensu…
Thenujan-Nagaratnam Aug 7, 2026
7f08d9b
Update license header
Thenujan-Nagaratnam Aug 7, 2026
e29f6ac
Implement shared Redis client initialization and configuration handling
Thenujan-Nagaratnam Aug 11, 2026
d469b1c
Enhance Redis client timeout handling and validation in configuration…
Thenujan-Nagaratnam Aug 12, 2026
375102c
asasa
Thenujan-Nagaratnam Aug 12, 2026
60c5724
docs: design spec for generic upstream-attempt retry/credential-refre…
Thenujan-Nagaratnam Aug 12, 2026
59c6f10
docs: implementation plan for generic upstream-attempt retry/credenti…
Thenujan-Nagaratnam Aug 12, 2026
b9dbe5e
feat(sdk): add generic UpstreamAttemptPolicy interface for per-retry-…
Thenujan-Nagaratnam Aug 12, 2026
3b5859e
refactor(policy-engine): extract extractRouteKey body into a shared f…
Thenujan-Nagaratnam Aug 12, 2026
38f9a20
feat(policy-engine): add minimal upstream ext_proc server dispatching…
Thenujan-Nagaratnam Aug 12, 2026
c765596
feat(policy-engine): wire the upstream ext_proc server into startup/s…
Thenujan-Nagaratnam Aug 12, 2026
1947cfb
feat(gateway-controller): add resilience.retry to the OpenAPI schema
Thenujan-Nagaratnam Aug 12, 2026
f092b92
docs: fix plan Task 5 to define Retry as a named top-level OpenAPI sc…
Thenujan-Nagaratnam Aug 12, 2026
e99d4a8
fix(gateway-controller): make Retry a named schema (not inline) for r…
Thenujan-Nagaratnam Aug 12, 2026
ac66997
feat(gateway-controller): validate resilience.retry for both REST and…
Thenujan-Nagaratnam Aug 12, 2026
00ae72f
test(gateway-controller): add retry validation tests for LLMProxy res…
Thenujan-Nagaratnam Aug 12, 2026
a1b464f
feat(gateway-controller): emit native RouteAction.RetryPolicy from re…
Thenujan-Nagaratnam Aug 12, 2026
c3b9109
feat(gateway-controller): attach upstream ext_proc filter to clusters…
Thenujan-Nagaratnam Aug 12, 2026
09844ea
feat(oauth2-generator): implement UpstreamAttemptPolicy for retry-tim…
Thenujan-Nagaratnam Aug 12, 2026
712e8f6
fix: stop tracking gitignored dev-policies/oauth2-generator (was forc…
Thenujan-Nagaratnam Aug 12, 2026
ed36f7e
fix(gateway-controller): set VirtualHost.IncludeRequestAttemptCount w…
Thenujan-Nagaratnam Aug 12, 2026
340387e
fix(gateway-controller): scope IncludeRequestAttemptCount per-vhost, …
Thenujan-Nagaratnam Aug 12, 2026
5133312
asa
Thenujan-Nagaratnam Aug 12, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 35 additions & 11 deletions cli/src/cmd/aiworkspace/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -570,7 +570,14 @@ func buildLLMProviderPayload(name string, metadata aiWorkspaceMetadata, runtime
if up := runtime.Spec.Upstream; up != nil {
target := llmUpstreamTarget{URL: strings.TrimSpace(up.URL)}
if up.Auth != nil {
target.Auth = &llmUpstreamAuth{Type: up.Auth.Type, Header: up.Auth.Header, Value: up.Auth.Value}
target.Auth = &llmUpstreamAuth{
Type: up.Auth.Type,
Header: up.Auth.Header,
Value: up.Auth.Value,
PolicyName: up.Auth.PolicyName,
PolicyVersion: up.Auth.PolicyVersion,
PolicyParams: up.Auth.PolicyParams,
}
}
payload.Upstream = &llmUpstream{Main: target}
}
Expand Down Expand Up @@ -643,7 +650,14 @@ func buildMCPProxyPayload(name string, metadata aiWorkspaceMetadata, runtime aiW
if up := runtime.Spec.Upstream; up != nil {
target := llmUpstreamTarget{URL: strings.TrimSpace(up.URL)}
if up.Auth != nil {
target.Auth = &llmUpstreamAuth{Type: up.Auth.Type, Header: up.Auth.Header, Value: up.Auth.Value}
target.Auth = &llmUpstreamAuth{
Type: up.Auth.Type,
Header: up.Auth.Header,
Value: up.Auth.Value,
PolicyName: up.Auth.PolicyName,
PolicyVersion: up.Auth.PolicyVersion,
PolicyParams: up.Auth.PolicyParams,
}
}
payload.Upstream = &llmUpstream{Main: target}
}
Expand Down Expand Up @@ -991,11 +1005,15 @@ func buildLLMProxyPayload(proxyName string, metadata aiWorkspaceMetadata, runtim
}

// The proxy references its provider by id; the provider owns the credential
// value, so only the auth type/header are carried here (never the secret).
// value, so only non-secret fields are carried here - type/header/policyName/
// policyVersion, never value or policyParams (which for oauth2 holds the
// client secret/token endpoint credentials).
if auth := runtime.Spec.Provider.Auth; auth != nil {
payload.Provider.Auth = &llmUpstreamAuth{
Type: auth.Type,
Header: auth.Header,
Type: auth.Type,
Header: auth.Header,
PolicyName: auth.PolicyName,
PolicyVersion: auth.PolicyVersion,
}
}

Expand Down Expand Up @@ -1105,9 +1123,12 @@ type runtimeProvider struct {
}

type runtimeProviderAuth struct {
Type string `yaml:"type"`
Header string `yaml:"header"`
Value string `yaml:"value"`
Type string `yaml:"type"`
Header string `yaml:"header"`
Value string `yaml:"value"`
PolicyName string `yaml:"policyName"`
PolicyVersion string `yaml:"policyVersion"`
PolicyParams map[string]interface{} `yaml:"policyParams"`
}

type runtimeUpstream struct {
Expand Down Expand Up @@ -1172,9 +1193,12 @@ type llmProxyProvider struct {
}

type llmUpstreamAuth struct {
Type string `json:"type,omitempty"`
Header string `json:"header,omitempty"`
Value string `json:"value,omitempty"`
Type string `json:"type,omitempty"`
Header string `json:"header,omitempty"`
Value string `json:"value,omitempty"`
PolicyName string `json:"policyName,omitempty"`
PolicyVersion string `json:"policyVersion,omitempty"`
PolicyParams map[string]interface{} `json:"policyParams,omitempty"`
}

type llmPolicy struct {
Expand Down
56 changes: 56 additions & 0 deletions cli/src/cmd/aiworkspace/build_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,31 @@ func TestBuildLLMProxyPayload_UsesRuntimeDescriptionWhenSet(t *testing.T) {
}
}

func TestBuildLLMProxyPayload_ProviderAuthOmitsSecretFields(t *testing.T) {
rt := newProxyRuntime()
rt.Spec.Provider.Auth = &runtimeProviderAuth{
Type: "oauth2",
PolicyName: "oauth2-generator",
PolicyVersion: "v1",
Value: "should-never-be-copied",
PolicyParams: map[string]interface{}{
"clientSecret": "should-never-be-copied",
},
}

payload := buildLLMProxyPayload("claude-proxy2", newProxyMetadata(), rt, "")
auth := payload.Provider.Auth
if auth == nil {
t.Fatalf("expected provider auth to be set")
}
if auth.Type != "oauth2" || auth.PolicyName != "oauth2-generator" || auth.PolicyVersion != "v1" {
t.Fatalf("expected non-secret fields to pass through, got %+v", auth)
}
if auth.Value != "" || auth.PolicyParams != nil {
t.Fatalf("expected secret-bearing fields (value/policyParams) to be omitted, got %+v", auth)
}
}

func TestBuildLLMProxyPayload_OmitsPoliciesWhenNone(t *testing.T) {
var md aiWorkspaceMetadata
md.Spec.DisplayName = "p"
Expand Down Expand Up @@ -189,6 +214,37 @@ func TestBuildLLMProviderPayload_OmitsModelProvidersForUnknownTemplate(t *testin
}
}

func TestBuildLLMProviderPayload_UpstreamOAuth2CarriesPolicyParams(t *testing.T) {
var metadata aiWorkspaceMetadata
metadata.Spec.Version = "v1.0"

var runtime aiWorkspaceRuntime
runtime.Spec.Upstream = &runtimeUpstream{
URL: "https://upstream.example.com",
Auth: &runtimeProviderAuth{
Type: "oauth2",
PolicyVersion: "v1",
PolicyParams: map[string]interface{}{
"tokenEndpoint": "https://idp.example.com/token",
"clientId": "abc",
"clientSecret": "{{ secret \"upstream-oauth2\" }}",
},
},
}

payload := buildLLMProviderPayload("p", metadata, runtime, "")
if payload.Upstream == nil || payload.Upstream.Main.Auth == nil {
t.Fatalf("expected upstream auth to be set, got %+v", payload.Upstream)
}
auth := payload.Upstream.Main.Auth
if auth.Type != "oauth2" || auth.PolicyVersion != "v1" {
t.Fatalf("unexpected auth type/policyVersion: %+v", auth)
}
if auth.PolicyParams["tokenEndpoint"] != "https://idp.example.com/token" || auth.PolicyParams["clientId"] != "abc" {
t.Fatalf("expected policyParams to pass through verbatim, got %+v", auth.PolicyParams)
}
}

func writeTestEnvFile(t *testing.T, dir, name, content string) string {
t.Helper()
path := filepath.Join(dir, name)
Expand Down
Loading
Loading