chore: tolerate empty providers at startup and log env seeds (#25605)

Since AI Gateway is now enabled by default, and if the AI Gateway Proxy is enabled too it's possible the server can start without any configured providers. This would previously block startup, which is unacceptable.

In an upstack PR we will handle reloading the providers at runtime, so the server needs to be able to start up even if it can't handle any proxy requests to AI Gateway.

This change was necessitated because if there are providers configured in the environment they need to be seeded _before_ the proxy starts.
This commit is contained in:
Danny Kopping
2026-05-22 12:45:14 +02:00
committed by GitHub
parent c8b1fa3196
commit ef6ee2af68
5 changed files with 91 additions and 103 deletions
+9 -7
View File
@@ -258,24 +258,26 @@ func New(ctx context.Context, logger slog.Logger, opts Options) (*Server, error)
allowedPorts = []string{"80", "443"}
}
if len(opts.DomainAllowlist) == 0 {
return nil, xerrors.New("domain allow list is required")
}
// An empty allowlist is permitted so the server can boot before any
// ai_providers row exists; every intercept attempt is then rejected
// until providers are configured.
// TODO: refresh the allowlist when ai_providers changes so a restart
// is not required after the first provider is configured.
mitmHosts, err := convertDomainsToHosts(opts.DomainAllowlist, allowedPorts)
if err != nil {
return nil, xerrors.Errorf("invalid domain allowlist: %w", err)
}
if len(mitmHosts) == 0 {
return nil, xerrors.New("domain allowlist is empty, at least one domain is required")
}
if opts.AIBridgeProviderFromHost == nil {
return nil, xerrors.New("AIBridgeProviderFromHost is required")
}
aibridgeProviderFromHost := opts.AIBridgeProviderFromHost
// Validate that all allowlisted domains have correct aibridge provider mappings.
for _, domain := range opts.DomainAllowlist {
domain = strings.TrimSpace(strings.ToLower(domain))
if domain == "" {
continue
}
if aibridgeProviderFromHost(domain) == "" {
return nil, xerrors.Errorf("domain %q is in allowlist but has no provider mapping", domain)
}
@@ -678,14 +678,15 @@ func TestNew(t *testing.T) {
mitmCertFile, mitmKeyFile := getSharedTestMITMCert(t)
logger := slogtest.Make(t, nil)
_, err := aibridgeproxyd.New(t.Context(), logger, aibridgeproxyd.Options{
ListenAddr: ":0",
CoderAccessURL: "http://localhost:3000",
MITMCertFile: mitmCertFile,
MITMKeyFile: mitmKeyFile,
srv, err := aibridgeproxyd.New(t.Context(), logger, aibridgeproxyd.Options{
ListenAddr: ":0",
CoderAccessURL: "http://localhost:3000",
MITMCertFile: mitmCertFile,
MITMKeyFile: mitmKeyFile,
AIBridgeProviderFromHost: testProviderFromHost,
})
require.Error(t, err)
require.Contains(t, err.Error(), "domain allow list is required")
require.NoError(t, err)
t.Cleanup(func() { _ = srv.Close() })
})
t.Run("EmptyDomainAllowlist", func(t *testing.T) {
@@ -694,15 +695,16 @@ func TestNew(t *testing.T) {
mitmCertFile, mitmKeyFile := getSharedTestMITMCert(t)
logger := slogtest.Make(t, nil)
_, err := aibridgeproxyd.New(t.Context(), logger, aibridgeproxyd.Options{
ListenAddr: ":0",
CoderAccessURL: "http://localhost:3000",
MITMCertFile: mitmCertFile,
MITMKeyFile: mitmKeyFile,
DomainAllowlist: []string{""},
srv, err := aibridgeproxyd.New(t.Context(), logger, aibridgeproxyd.Options{
ListenAddr: ":0",
CoderAccessURL: "http://localhost:3000",
MITMCertFile: mitmCertFile,
MITMKeyFile: mitmKeyFile,
DomainAllowlist: []string{""},
AIBridgeProviderFromHost: testProviderFromHost,
})
require.Error(t, err)
require.Contains(t, err.Error(), "domain allowlist is empty, at least one domain is required")
require.NoError(t, err)
t.Cleanup(func() { _ = srv.Close() })
})
t.Run("InvalidDomainAllowlist", func(t *testing.T) {