mirror of
https://github.com/netbirdio/netbird.git
synced 2026-09-07 15:31:30 +02:00
[management,proxy] Serve guardrail allowlists of declared model ids (#7389)
After #7221, guardrail allowlists built from a path-style provider's declared model ids (Bedrock, Vertex) stopped working: the raw region/version form was compared against the parser's canonical id, so the agent config advertised an empty model list and requests for the allowlisted model were refused. Make every allowlist compare provider-aware, keyed on the destination provider's catalog id: the agent config, the policy gate, and the synthesized proxy allowlists match an entry on both its verbatim and canonical form — Bedrock's strip only under bedrock_api, Vertex's only under vertex_ai_api, verbatim everywhere else, so a plain provider's suffixed entries never widen. The router's claim compare learns the Vertex @version strip. New e2e, realstore, and unit tests reproduce both regressions and pin the fix.
This commit is contained in:
@@ -115,3 +115,20 @@ func TestRouter_BedrockNamespacedInferenceProfilesStripsPrefix(t *testing.T) {
|
||||
assert.Equal(t, "/bedrock", out.Mutations.RewriteUpstream.StripPathPrefix,
|
||||
"the namespace prefix must not reach the real Bedrock endpoint")
|
||||
}
|
||||
|
||||
// TestRouteClaimsModel_VertexNormalizesCandidate is the Vertex counterpart of
|
||||
// the Bedrock case above: the parser strips the "@version" suffix from the
|
||||
// path model, so a provider registered with the versioned form must still
|
||||
// match the normalized request model.
|
||||
func TestRouteClaimsModel_VertexNormalizesCandidate(t *testing.T) {
|
||||
route := ProviderRoute{Vertex: true, Models: []string{"claude-sonnet-4-5@20250929"}}
|
||||
assert.True(t, routeClaimsModel(route, "claude-sonnet-4-5"),
|
||||
"raw @version Vertex model must match the normalized request model")
|
||||
assert.False(t, routeClaimsModel(route, "claude-opus-4-8"),
|
||||
"a model outside the provider's list must not match")
|
||||
|
||||
// Non-Vertex routes keep exact matching (no @version stripping).
|
||||
openai := ProviderRoute{Models: []string{"gpt-4o@2024"}}
|
||||
assert.False(t, routeClaimsModel(openai, "gpt-4o"),
|
||||
"non-Vertex routes must not strip an @version suffix")
|
||||
}
|
||||
|
||||
@@ -331,6 +331,11 @@ func discoverableModels(route ProviderRoute, userGroups []string) ([]string, boo
|
||||
intersection[m] = struct{}{}
|
||||
}
|
||||
}
|
||||
if route.Vertex {
|
||||
if _, ok := permitted[llm.NormalizeVertexModel(m)]; ok {
|
||||
intersection[m] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
return sortedModels(intersection), true
|
||||
}
|
||||
@@ -869,6 +874,11 @@ func routeClaimsModel(route ProviderRoute, model string) bool {
|
||||
if route.Bedrock && llm.NormalizeBedrockModel(candidate) == model {
|
||||
return true
|
||||
}
|
||||
// Vertex likewise: the parser strips the "@version" suffix from the
|
||||
// path model, while the operator may register the versioned form.
|
||||
if route.Vertex && llm.NormalizeVertexModel(candidate) == model {
|
||||
return true
|
||||
}
|
||||
// A client may pin a dated Anthropic id ("claude-sonnet-4-5-20250929")
|
||||
// where the operator registered the undated one. Only an undated
|
||||
// registration absorbs a dated request: normalising both sides would
|
||||
|
||||
Reference in New Issue
Block a user