Skip to content

Commit 0d6b887

Browse files
committed
fix: match HTTPRoute on CR name instead of targetModel for X-Gateway-Model-Name
The HTTPRoute body-routed rules matched X-Gateway-Model-Name against targetModel, but body-field-to-header sets the header to the ExternalModel CR name (what /v1/models returns, what clients send). When CR name differs from targetModel (e.g., company-gpt4 vs gpt-4o), no route matched → 404. Fix: match on modelName (CR name) instead of ref.targetModel. Routing is still correct because x-ipp-selected-provider (also in the match) uniquely identifies the backend. The body model field is still rewritten to targetModel by model-provider-resolver — the provider receives the correct model name. Reverts the header rewrite approach (which would break auth — ipp-pre runs before the wasm/auth plugin, so overwriting X-Gateway-Model-Name to targetModel causes Rego model_access lookup and maas-api subscription validation to fail).
1 parent 726eb4d commit 0d6b887

3 files changed

Lines changed: 5 additions & 6 deletions

File tree

pkg/controller/externalmodel/reconciler.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,7 @@ func buildHTTPRoute(refs []resolvedRef, modelName, namespace string, port int32,
317317
Matches: []gatewayapiv1.HTTPRouteMatch{{
318318
Path: &gatewayapiv1.HTTPPathMatch{Type: &pathType, Value: func() *string { s := "/"; return &s }()},
319319
Headers: []gatewayapiv1.HTTPHeaderMatch{
320-
{Name: "X-Gateway-Model-Name", Type: &headerType, Value: ref.targetModel},
320+
{Name: "X-Gateway-Model-Name", Type: &headerType, Value: modelName},
321321
{Name: selectedProviderHeader, Type: &headerType, Value: ref.providerName},
322322
},
323323
}},
@@ -357,7 +357,7 @@ func buildHTTPRoute(refs []resolvedRef, modelName, namespace string, port int32,
357357
gatewayapiv1.HTTPRouteRule{
358358
Matches: []gatewayapiv1.HTTPRouteMatch{{
359359
Headers: []gatewayapiv1.HTTPHeaderMatch{
360-
{Name: "X-Gateway-Model-Name", Type: &headerType, Value: refs[0].targetModel},
360+
{Name: "X-Gateway-Model-Name", Type: &headerType, Value: modelName},
361361
},
362362
}},
363363
BackendRefs: fallbackBackendRefs,

pkg/controller/externalmodel/reconciler_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -336,9 +336,9 @@ func TestReconcile_TwoModelsOneProvider(t *testing.T) {
336336
assert.Equal(t, "shared-provider", string(hr1.Spec.Rules[0].BackendRefs[0].Name))
337337
assert.Equal(t, "shared-provider", string(hr2.Spec.Rules[0].BackendRefs[0].Name))
338338

339-
// Per-provider header match on rule 1 uses targetModel + x-ipp-selected-provider
340-
assert.Equal(t, "gpt-4o", hr1.Spec.Rules[1].Matches[0].Headers[0].Value)
341-
assert.Equal(t, "gpt-3.5-turbo", hr2.Spec.Rules[1].Matches[0].Headers[0].Value)
339+
// Per-provider header match on rule 1 uses CR name + x-ipp-selected-provider
340+
assert.Equal(t, "gpt4", hr1.Spec.Rules[1].Matches[0].Headers[0].Value)
341+
assert.Equal(t, "gpt35", hr2.Spec.Rules[1].Matches[0].Headers[0].Value)
342342

343343
// Different path prefixes
344344
assert.Equal(t, "/"+ns+"/gpt4", *hr1.Spec.Rules[0].Matches[0].Path.Value)

pkg/plugins/model-provider-resolver/plugin.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,6 @@ func (p *ModelProviderResolverPlugin) ProcessRequest(ctx context.Context, cycleS
183183
// Drive Envoy routing to the selected provider's backend.
184184
request.SetHeader(SelectedProviderHeader, ref.providerName)
185185
request.SetHeader("Host", ref.endpoint)
186-
request.SetHeader("X-Gateway-Model-Name", ref.targetModel)
187186

188187
if model != ref.targetModel {
189188
request.SetBodyField("model", ref.targetModel)

0 commit comments

Comments
 (0)