Onboard: require explicit mode for env secret refs

This commit is contained in:
joshavant
2026-02-24 15:04:04 -06:00
committed by Peter Steinberger
parent 103d02f98c
commit 04aa856fc0
15 changed files with 477 additions and 109 deletions

View File

@@ -6,10 +6,12 @@ import {
validateApiKeyInput,
} from "./auth-choice.api-key.js";
import {
normalizeSecretInputModeInput,
createAuthChoiceAgentModelNoter,
createAuthChoiceDefaultModelApplier,
createAuthChoiceModelStateBridge,
ensureApiKeyFromOptionEnvOrPrompt,
resolveSecretInputModeForEnvSelection,
normalizeTokenProviderInput,
} from "./auth-choice.apply-helpers.js";
import { applyAuthChoiceHuggingface } from "./auth-choice.apply.huggingface.js";
@@ -19,6 +21,7 @@ import {
applyGoogleGeminiModelDefault,
GOOGLE_GEMINI_DEFAULT_MODEL,
} from "./google-gemini-model-default.js";
import type { ApiKeyStorageOptions } from "./onboard-auth.credentials.js";
import {
applyAuthProfileConfig,
applyCloudflareAiGatewayConfig,
@@ -80,7 +83,7 @@ import {
setZaiApiKey,
ZAI_DEFAULT_MODEL_REF,
} from "./onboard-auth.js";
import type { AuthChoice } from "./onboard-types.js";
import type { AuthChoice, SecretInputMode } from "./onboard-types.js";
import { OPENCODE_ZEN_DEFAULT_MODEL } from "./opencode-zen-model-default.js";
import { detectZaiEndpoint } from "./zai-endpoint-detect.js";
@@ -124,7 +127,11 @@ type SimpleApiKeyProviderFlow = {
expectedProviders: string[];
envLabel: string;
promptMessage: string;
setCredential: (apiKey: string, agentDir?: string) => void | Promise<void>;
setCredential: (
apiKey: string,
agentDir?: string,
options?: ApiKeyStorageOptions,
) => void | Promise<void>;
defaultModel: string;
applyDefaultConfig: ApiKeyProviderConfigApplier;
applyProviderConfig: ApiKeyProviderConfigApplier;
@@ -327,6 +334,7 @@ export async function applyAuthChoiceApiProviders(
let authChoice = params.authChoice;
const normalizedTokenProvider = normalizeTokenProviderInput(params.opts?.tokenProvider);
const requestedSecretInputMode = normalizeSecretInputModeInput(params.opts?.secretInputMode);
if (authChoice === "apiKey" && params.opts?.tokenProvider) {
if (normalizedTokenProvider !== "anthropic" && normalizedTokenProvider !== "openai") {
authChoice = API_KEY_TOKEN_PROVIDER_AUTH_CHOICE[normalizedTokenProvider ?? ""] ?? authChoice;
@@ -355,7 +363,7 @@ export async function applyAuthChoiceApiProviders(
expectedProviders: string[];
envLabel: string;
promptMessage: string;
setCredential: (apiKey: string) => void | Promise<void>;
setCredential: (apiKey: string, mode?: SecretInputMode) => void | Promise<void>;
defaultModel: string;
applyDefaultConfig: (
config: ApplyAuthChoiceParams["config"],
@@ -374,11 +382,12 @@ export async function applyAuthChoiceApiProviders(
token: params.opts?.token,
provider,
tokenProvider,
secretInputMode: requestedSecretInputMode,
expectedProviders,
envLabel,
promptMessage,
setCredential: async (apiKey) => {
await setCredential(apiKey);
setCredential: async (apiKey, mode) => {
await setCredential(apiKey, mode);
},
noteMessage,
noteTitle,
@@ -421,6 +430,7 @@ export async function applyAuthChoiceApiProviders(
await ensureApiKeyFromOptionEnvOrPrompt({
token: params.opts?.token,
tokenProvider: normalizedTokenProvider,
secretInputMode: requestedSecretInputMode,
expectedProviders: ["litellm"],
provider: "litellm",
envLabel: "LITELLM_API_KEY",
@@ -428,7 +438,8 @@ export async function applyAuthChoiceApiProviders(
normalize: normalizeApiKeyInput,
validate: validateApiKeyInput,
prompter: params.prompter,
setCredential: async (apiKey) => setLitellmApiKey(apiKey, params.agentDir),
setCredential: async (apiKey, mode) =>
setLitellmApiKey(apiKey, params.agentDir, { secretInputMode: mode }),
noteMessage:
"LiteLLM provides a unified API to 100+ LLM providers.\nGet your API key from your LiteLLM proxy or https://litellm.ai\nDefault proxy runs on http://localhost:4000",
noteTitle: "LiteLLM",
@@ -460,8 +471,10 @@ export async function applyAuthChoiceApiProviders(
expectedProviders: simpleApiKeyProviderFlow.expectedProviders,
envLabel: simpleApiKeyProviderFlow.envLabel,
promptMessage: simpleApiKeyProviderFlow.promptMessage,
setCredential: async (apiKey) =>
simpleApiKeyProviderFlow.setCredential(apiKey, params.agentDir),
setCredential: async (apiKey, mode) =>
simpleApiKeyProviderFlow.setCredential(apiKey, params.agentDir, {
secretInputMode: mode ?? requestedSecretInputMode,
}),
defaultModel: simpleApiKeyProviderFlow.defaultModel,
applyDefaultConfig: simpleApiKeyProviderFlow.applyDefaultConfig,
applyProviderConfig: simpleApiKeyProviderFlow.applyProviderConfig,
@@ -498,6 +511,9 @@ export async function applyAuthChoiceApiProviders(
const optsApiKey = normalizeApiKeyInput(params.opts?.cloudflareAiGatewayApiKey ?? "");
let resolvedApiKey = "";
if (accountId && gatewayId && optsApiKey) {
await setCloudflareAiGatewayConfig(accountId, gatewayId, optsApiKey, params.agentDir, {
secretInputMode: requestedSecretInputMode,
});
resolvedApiKey = optsApiKey;
}
@@ -509,12 +525,22 @@ export async function applyAuthChoiceApiProviders(
});
if (useExisting) {
await ensureAccountGateway();
const mode = await resolveSecretInputModeForEnvSelection({
prompter: params.prompter,
explicitMode: requestedSecretInputMode,
});
await setCloudflareAiGatewayConfig(accountId, gatewayId, envKey.apiKey, params.agentDir, {
secretInputMode: mode,
});
resolvedApiKey = normalizeApiKeyInput(envKey.apiKey);
}
}
if (!resolvedApiKey && optsApiKey) {
await ensureAccountGateway();
await setCloudflareAiGatewayConfig(accountId, gatewayId, optsApiKey, params.agentDir, {
secretInputMode: requestedSecretInputMode,
});
resolvedApiKey = optsApiKey;
}
@@ -525,9 +551,10 @@ export async function applyAuthChoiceApiProviders(
validate: validateApiKeyInput,
});
resolvedApiKey = normalizeApiKeyInput(String(key ?? ""));
await setCloudflareAiGatewayConfig(accountId, gatewayId, resolvedApiKey, params.agentDir, {
secretInputMode: requestedSecretInputMode,
});
}
await setCloudflareAiGatewayConfig(accountId, gatewayId, resolvedApiKey, params.agentDir);
nextConfig = applyAuthProfileConfig(nextConfig, {
profileId: "cloudflare-ai-gateway:default",
provider: "cloudflare-ai-gateway",
@@ -555,13 +582,15 @@ export async function applyAuthChoiceApiProviders(
token: params.opts?.token,
provider: "google",
tokenProvider: normalizedTokenProvider,
secretInputMode: requestedSecretInputMode,
expectedProviders: ["google"],
envLabel: "GEMINI_API_KEY",
promptMessage: "Enter Gemini API key",
normalize: normalizeApiKeyInput,
validate: validateApiKeyInput,
prompter: params.prompter,
setCredential: async (apiKey) => setGeminiApiKey(apiKey, params.agentDir),
setCredential: async (apiKey, mode) =>
setGeminiApiKey(apiKey, params.agentDir, { secretInputMode: mode }),
});
nextConfig = applyAuthProfileConfig(nextConfig, {
profileId: "google:default",
@@ -597,13 +626,15 @@ export async function applyAuthChoiceApiProviders(
token: params.opts?.token,
provider: "zai",
tokenProvider: normalizedTokenProvider,
secretInputMode: requestedSecretInputMode,
expectedProviders: ["zai"],
envLabel: "ZAI_API_KEY",
promptMessage: "Enter Z.AI API key",
normalize: normalizeApiKeyInput,
validate: validateApiKeyInput,
prompter: params.prompter,
setCredential: async (apiKey) => setZaiApiKey(apiKey, params.agentDir),
setCredential: async (apiKey, mode) =>
setZaiApiKey(apiKey, params.agentDir, { secretInputMode: mode }),
});
// zai-api-key: auto-detect endpoint + choose a working default model.