fix: block global-credential providers already managed via env

Bedrock, Vertex AI, and Ollama credentials live in fixed env vars with
no apiKeyEnv redirection, so a panel instance of one of these would
silently override the credentials that env-configured models rely on.
The API now rejects saving such a provider when the env config already
uses that type, and the Add Provider dropdown disables it with a
'managed via env' note.
This commit is contained in:
dayuan.jiang
2026-06-11 18:08:02 +09:00
parent 8ca628a872
commit b0a96c23a3
5 changed files with 103 additions and 22 deletions

View File

@@ -3,7 +3,11 @@ import {
ProviderNameSchema,
type ServerModelsConfig,
} from "@/lib/server-model-config"
import { PROVIDER_INFO, type ProviderName } from "@/lib/types/model-config"
import {
FIXED_CRED_PROVIDERS,
PROVIDER_INFO,
type ProviderName,
} from "@/lib/types/model-config"
import { type MaskedSecret, maskSecret } from "./auth"
import { loadSettings } from "./settings"
@@ -65,11 +69,6 @@ const SECRET_FIELDS = [
"vertexApiKey",
] as const
// Providers whose credentials the runtime reads from fixed env vars
// (no apiKeyEnv support), so the panel writes those vars directly and
// only one instance of each is allowed. edgeone needs no credentials.
const FIXED_CRED_PROVIDERS: ProviderName[] = ["bedrock", "vertexai", "ollama"]
// ADMIN_-prefixed env var names for instance `index` (0-based) of a provider
function credEnvNames(
provider: ProviderName,
@@ -151,18 +150,27 @@ function displayName(p: StoredAdminProvider): string {
export function validateAdminProviders(
list: StoredAdminProvider[],
envProviderNames: string[] = [],
envConfig: ServerModelsConfig | null = null,
): string | null {
const envProviders = envConfig?.providers ?? []
for (const single of FIXED_CRED_PROVIDERS) {
if (list.filter((p) => p.provider === single).length > 1) {
return `Only one ${PROVIDER_INFO[single].label} provider is supported (its credentials use fixed environment variables).`
}
// Its credentials are global; a panel instance would silently
// override the credentials env-configured models rely on
if (
list.some((p) => p.provider === single) &&
envProviders.some((p) => p.provider === single)
) {
return `${PROVIDER_INFO[single].label} is already configured in AI_MODELS_CONFIG / ai-models.json and shares global credentials. Manage it via the environment configuration instead.`
}
}
const names = list.map((p) => displayName(p))
if (new Set(names).size !== names.length) {
return "Provider display names must be unique."
}
const envNames = new Set(envProviderNames)
const envNames = new Set(envProviders.map((p) => p.name))
const clash = names.find((n) => envNames.has(n))
if (clash) {
return `"${clash}" is already defined in AI_MODELS_CONFIG / ai-models.json. Use a different display name.`

View File

@@ -85,6 +85,15 @@ export interface FlattenedModel {
baseUrlEnv?: string
}
// Providers whose server credentials live in fixed env vars
// (AWS_ACCESS_KEY_ID, GOOGLE_VERTEX_API_KEY, OLLAMA_API_KEY) with no
// apiKeyEnv redirection support — their credentials are global
export const FIXED_CRED_PROVIDERS: ProviderName[] = [
"bedrock",
"vertexai",
"ollama",
]
// Map provider names to models.dev logo names
export const PROVIDER_LOGO_MAP: Record<string, string> = {
openai: "openai",