Files
coder/coderd/aibridged/provider_test.go
T
Cian Johnston 042421694f fix: surface duplicate AI provider hostname as warning, not error (#28208)
Two live `ai_providers` rows can share the same `base_url` hostname.
This is an intended configuration (AIGOV-97): the direct routing path
(`/api/v2/ai-gateway/{name}/...`) routes by provider name and fully
supports it. Only the MITM proxy path (`aibridgeproxyd`) cannot
disambiguate, because its `nameByHost` map is 1:1.

`classifyProviderRow` marked the second provider as
`ProviderStatusError`, which surfaced as a misleading log warning and a
`status=error` Prometheus label. The provider is not actually broken; it
is fully routable via the direct path. The error was only visible in
server logs and Prometheus, not in the API or UI.

This change:

- Extracts `BaseURLHostname` into `coderd/aibridged` and eliminates
three duplicate implementations (proxy classifier, chatprovider, and the
API layer now uses it for status checks).
- Downgrades the proxy classifier from `ProviderStatusError` to a new
`ProviderStatusProxyExcluded` status. The provider is not broken; it is
just not reachable via the MITM proxy path.
- Adds `Status *AIProviderStatus` to `codersdk.AIProvider` with
`Warnings []string`, matching the `WorkspaceProxy` precedent.
- Populates warnings on create, update, GET, and list when a provider's
hostname collides with another enabled provider.
- Adds an integration test proving that a duplicate provider is routable
via the direct path but not via the proxy path.

Refs AIGOV-596

Generated by Coder Agents



https://github.com/user-attachments/assets/bf323837-5121-4d1b-ab19-593f1d32374e
2026-08-24 13:27:22 +01:00

34 lines
924 B
Go

package aibridged_test
import (
"testing"
"github.com/stretchr/testify/require"
"github.com/coder/coder/v2/coderd/aibridged"
)
func TestBaseURLHostname(t *testing.T) {
t.Parallel()
tests := []struct {
name string
baseURL string
want string
}{
{name: "URL", baseURL: "https://openrouter.ai/api/v1", want: "openrouter.ai"},
{name: "BareHost", baseURL: "openrouter.ai", want: "openrouter.ai"},
{name: "HostWithPort", baseURL: "https://openrouter.ai:443/api/v1", want: "openrouter.ai"},
{name: "UppercaseHost", baseURL: "https://API.OpenRouter.AI/v1", want: "api.openrouter.ai"},
{name: "IPv6", baseURL: "https://[::1]:8080/v1", want: "::1"},
{name: "Empty", baseURL: "", want: ""},
{name: "Invalid", baseURL: "://", want: ""},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
require.Equal(t, tt.want, aibridged.BaseURLHostname(tt.baseURL))
})
}
}