fix: config validation hardening and integration polish

- providers.go: validate provider names against ^[a-zA-Z0-9._-]+$ and
  reject reserved names (v1, mcp, a2a) that would shadow gateway routes;
  reject nil ProviderConfig map values at construction instead of
  panicking.
- mcp_a2a.go: apply the same name-pattern and reserved-name validation to
  mcpServers/agents keys, and reject nil TargetConfig/AgentConfig map
  values at construction.
- auth.go: reject nil GroupConfig map values at construction.
- provider_openai_test.go, mcp_a2a_test.go, auth_test.go: table-driven
  constructor-error coverage for the above.
- integration/integration_test.go: point the package doc at
  `make integration-up`/`integration-keep` instead of a bare
  `docker compose up -d --build`, which skips the dynamic.yml.tmpl
  render step and can run against a stale or absent dynamic.yml; add
  max_tokens to the gemini chat request so translate_gemini.go's
  hasMaxTokens=true branch is actually exercised under real Yaegi.
- translate_gemini.go: soften the max_tokens comment's verification claim
  to match what the integration suite actually now exercises.
This commit is contained in:
2026-08-20 13:57:56 +01:00
parent 730583d98e
commit ae4d6bab96
8 changed files with 202 additions and 23 deletions
+16 -6
View File
@@ -5,10 +5,16 @@
// upstreams, and a real shared Redis, all orchestrated by
// integration/docker-compose.yml. It assumes the compose stack is already
// up and healthy — the `integration` Makefile target starts it, waits for
// traefik1 to answer, runs this package, then tears the stack down; run it
// directly with `go test -tags integration ./...` from this directory
// after `docker compose up -d --build` if you want to keep the stack alive
// between runs (see the `integration-keep` Makefile target).
// traefik1 to answer, runs this package, then tears the stack down. To keep
// the stack alive between runs for debugging, use `make integration-keep`
// (or `make integration-up` followed directly by
// `go test -tags integration ./...` from this directory), not a bare
// `docker compose up -d --build`: integration-up first renders
// integration/traefik/dynamic.yml from dynamic.yml.tmpl (substituting
// INTEGRATION_REAL_BASEURL), and that generated dynamic.yml is
// git-ignored — running docker compose directly reuses whatever stale or
// absent dynamic.yml happens to be on disk instead of a freshly rendered
// one.
package integration
import (
@@ -213,8 +219,12 @@ func TestUnifiedChatAllProviders(t *testing.T) {
}
geminiReq := map[string]any{
"model": "gemini/gemini-mock",
"messages": []map[string]any{{"role": "user", "content": "hi"}},
"model": "gemini/gemini-mock",
// max_tokens exercises translate_gemini.go's hasMaxTokens=true
// branch (see its comment on the yaegi multi-value-assignment
// workaround) under real Traefik + Yaegi, not just go test.
"max_tokens": 64,
"messages": []map[string]any{{"role": "user", "content": "hi"}},
}
resp3, body3 := doJSON(t, http.MethodPost, traefik1URL+"/v1/chat/completions", aliceKey, geminiReq)
if resp3.StatusCode != http.StatusOK {