fix: reject dot-only config names

configNamePattern (^[a-zA-Z0-9._-]+$) permits "." and ".." as valid
provider/mcpServers/agents names, since a bare dot is in the allowed
character class. Both names read as directory-traversal segments once
embedded as a path segment in the gateway's own routes
(passthroughRoute's "/{provider}/*", targetRoute's "/mcp/{name}/*" and
"/a2a/{name}/*"). Nothing in this package's current path handling
mis-resolves them, but disallowing them at construction is cheap and
removes any future dependence on that staying true.

- providers.go: add dotOnlyConfigNames ({".", ".."}), checked in
  validateConfigName between the character-class check and the
  reserved-name check.
- provider_openai_test.go: extend TestValidateConfigName with "." and
  ".." cases (rejected) across provider/mcpServers/agents kinds, plus
  "..." (accepted — the rule is an exact match on "." and "..", not "any
  dots-only string").

Gates: go test ./... -count=1, go test ./... -race -count=1, gofmt -l .,
go vet ./..., make yaegi-check, golangci-lint run ./..., golangci-lint
run --enable=gosec ./..., fieldalignment ./... — all clean.
This commit is contained in:
2026-08-20 14:29:55 +01:00
parent 08dca6ad98
commit 3f49cda42c
2 changed files with 29 additions and 8 deletions
+12 -5
View File
@@ -666,11 +666,13 @@ func TestBuildAdapters(t *testing.T) {
})
}
// TestValidateConfigName covers validateConfigName's character-set and
// reserved-name rules, shared by buildAdapters (provider names) and
// validateTargetURLs (mcpServers/agents names, mcp_a2a_test.go) — a
// provider, MCP server, or agent named "v1", "mcp", or "a2a" would shadow
// one of the gateway's own fixed top-level routes.
// TestValidateConfigName covers validateConfigName's character-set,
// dot-only-name, and reserved-name rules, shared by buildAdapters
// (provider names) and validateTargetURLs (mcpServers/agents names,
// mcp_a2a_test.go) — a provider, MCP server, or agent named "v1", "mcp",
// or "a2a" would shadow one of the gateway's own fixed top-level routes,
// and one named "." or ".." reads as a directory-traversal segment once
// embedded as a path segment in the gateway's own routes.
func TestValidateConfigName(t *testing.T) {
tests := []struct {
kind string
@@ -687,6 +689,11 @@ func TestValidateConfigName(t *testing.T) {
{"provider", "a2a", true}, // reserved: A2A target-proxy prefix
{"mcpServers", "v1", true}, // same reserved set applies to every kind
{"agents", "a2a", true},
{"provider", ".", true}, // dot-only: matches configNamePattern's character class but rejected anyway
{"provider", "..", true}, // dot-only: same
{"mcpServers", ".", true}, // dot-only rule applies to every kind
{"agents", "..", true}, // dot-only rule applies to every kind
{"provider", "...", false}, // three dots is NOT one of dotOnlyConfigNames — the rule is exact-match on "." and "..", not "any dots-only string"
}
for _, tt := range tests {
t.Run(tt.kind+"/"+tt.name, func(t *testing.T) {