fix(cli): avoid default env overrides for profiles (#2119)

* fix(cli): avoid default env overrides for profiles

* test(cli): lock auth mode profile handoff behavior

* test(cli): restore prompt flag coverage

---------

Co-authored-by: liushiao <liushiao@bytedance.com>
This commit is contained in:
Sskift
2026-05-26 23:30:36 +08:00
committed by GitHub
parent e03f7f945d
commit 2c12371257
+134 -40
View File
@@ -1464,33 +1464,28 @@ fn build_tui_command(
);
}
cmd.env("DEEPSEEK_MODEL", &resolved_runtime.model);
cmd.env("DEEPSEEK_BASE_URL", &resolved_runtime.base_url);
cmd.env("DEEPSEEK_PROVIDER", resolved_runtime.provider.as_str());
if let Some(auth_mode) = resolved_runtime.auth_mode.as_ref() {
cmd.env("DEEPSEEK_AUTH_MODE", auth_mode);
if let Some(provider) = cli.provider {
let provider: ProviderKind = provider.into();
cmd.env("DEEPSEEK_PROVIDER", provider.as_str());
}
if !resolved_runtime.http_headers.is_empty() {
let encoded = resolved_runtime
.http_headers
.iter()
.map(|(name, value)| format!("{}={}", name.trim(), value.trim()))
.collect::<Vec<_>>()
.join(",");
cmd.env("DEEPSEEK_HTTP_HEADERS", encoded);
}
if let Some(api_key) = resolved_runtime.api_key.as_ref() {
if matches!(
resolved_runtime.api_key_source,
Some(RuntimeApiKeySource::Keyring)
) && let Some(api_key) = resolved_runtime.api_key.as_ref()
{
// TUI reloads auth_mode from config/profile, but it does not re-query the
// platform keyring on normal startup. Bridge only the recovered secret;
// replaying auth_mode here would turn it back into a profile override.
cmd.env("DEEPSEEK_API_KEY", api_key);
for var in provider_env_vars(resolved_runtime.provider) {
if *var != "DEEPSEEK_API_KEY" {
cmd.env(var, api_key);
}
}
let source = resolved_runtime
.api_key_source
.unwrap_or(RuntimeApiKeySource::Env)
.as_env_value();
cmd.env("DEEPSEEK_API_KEY_SOURCE", source);
cmd.env(
"DEEPSEEK_API_KEY_SOURCE",
RuntimeApiKeySource::Keyring.as_env_value(),
);
}
if let Some(model) = cli.model.as_ref() {
@@ -2630,14 +2625,6 @@ mod tests {
command_env(&cmd, "DEEPSEEK_PROVIDER").as_deref(),
Some("openai")
);
assert_eq!(
command_env(&cmd, "DEEPSEEK_MODEL").as_deref(),
Some("glm-5")
);
assert_eq!(
command_env(&cmd, "DEEPSEEK_BASE_URL").as_deref(),
Some("https://openai-compatible.example/v4")
);
assert_eq!(
command_env(&cmd, "DEEPSEEK_API_KEY").as_deref(),
Some("resolved-openai-key")
@@ -2650,10 +2637,7 @@ mod tests {
command_env(&cmd, "DEEPSEEK_API_KEY_SOURCE").as_deref(),
Some("keyring")
);
assert_eq!(
command_env(&cmd, "DEEPSEEK_AUTH_MODE").as_deref(),
Some("api_key")
);
assert_eq!(command_env(&cmd, "DEEPSEEK_AUTH_MODE"), None);
let args: Vec<String> = cmd
.get_args()
.map(|arg| arg.to_string_lossy().into_owned())
@@ -2665,6 +2649,55 @@ mod tests {
);
}
#[test]
fn build_tui_command_does_not_export_default_runtime_overrides_for_profiles() {
let _lock = env_lock();
let dir = tempfile::TempDir::new().expect("tempdir");
let custom = dir
.path()
.join(format!("custom-tui{}", std::env::consts::EXE_SUFFIX));
std::fs::write(&custom, b"").unwrap();
let custom_str = custom.to_string_lossy().into_owned();
let _bin = ScopedEnvVar::set("DEEPSEEK_TUI_BIN", &custom_str);
let cli = parse_ok(&["deepseek", "--profile", "google"]);
let mut resolved_headers = std::collections::BTreeMap::new();
resolved_headers.insert("X-From-Base".to_string(), "base".to_string());
let resolved = ResolvedRuntimeOptions {
provider: ProviderKind::Deepseek,
model: "deepseek-v4-pro".to_string(),
api_key: Some("config-file-key".to_string()),
api_key_source: Some(RuntimeApiKeySource::ConfigFile),
base_url: "https://api.deepseek.com/beta".to_string(),
auth_mode: Some("api_key".to_string()),
output_mode: None,
log_level: None,
telemetry: false,
approval_policy: None,
sandbox_mode: None,
yolo: None,
http_headers: resolved_headers,
};
let cmd = build_tui_command(&cli, &resolved, Vec::new()).expect("command");
assert_eq!(command_env(&cmd, "DEEPSEEK_PROVIDER"), None);
assert_eq!(command_env(&cmd, "DEEPSEEK_MODEL"), None);
assert_eq!(command_env(&cmd, "DEEPSEEK_BASE_URL"), None);
assert_eq!(command_env(&cmd, "DEEPSEEK_API_KEY"), None);
assert_eq!(command_env(&cmd, "DEEPSEEK_API_KEY_SOURCE"), None);
assert_eq!(command_env(&cmd, "DEEPSEEK_AUTH_MODE"), None);
assert_eq!(command_env(&cmd, "DEEPSEEK_HTTP_HEADERS"), None);
let args: Vec<String> = cmd
.get_args()
.map(|arg| arg.to_string_lossy().into_owned())
.collect();
assert!(
args.windows(2).any(|pair| pair == ["--profile", "google"]),
"expected profile forwarding in args: {args:?}"
);
}
#[test]
fn build_tui_command_allows_moonshot_and_forwards_kimi_key() {
let _lock = env_lock();
@@ -2689,7 +2722,7 @@ mod tests {
provider: ProviderKind::Moonshot,
model: "kimi-k2.6".to_string(),
api_key: Some("resolved-kimi-key".to_string()),
api_key_source: Some(RuntimeApiKeySource::Env),
api_key_source: Some(RuntimeApiKeySource::Keyring),
base_url: "https://api.moonshot.ai/v1".to_string(),
auth_mode: Some("api_key".to_string()),
output_mode: None,
@@ -2710,10 +2743,6 @@ mod tests {
command_env(&cmd, "DEEPSEEK_MODEL").as_deref(),
Some("kimi-k2.6")
);
assert_eq!(
command_env(&cmd, "DEEPSEEK_BASE_URL").as_deref(),
Some("https://api.moonshot.ai/v1")
);
assert_eq!(
command_env(&cmd, "DEEPSEEK_API_KEY").as_deref(),
Some("resolved-kimi-key")
@@ -2728,12 +2757,67 @@ mod tests {
);
assert_eq!(
command_env(&cmd, "DEEPSEEK_API_KEY_SOURCE").as_deref(),
Some("env")
Some("keyring")
);
assert_eq!(command_env(&cmd, "DEEPSEEK_AUTH_MODE"), None);
}
#[test]
fn build_tui_command_exports_explicit_provider_model_and_base_url() {
let _lock = env_lock();
let dir = tempfile::TempDir::new().expect("tempdir");
let custom = dir
.path()
.join(format!("custom-tui{}", std::env::consts::EXE_SUFFIX));
std::fs::write(&custom, b"").unwrap();
let custom_str = custom.to_string_lossy().into_owned();
let _bin = ScopedEnvVar::set("DEEPSEEK_TUI_BIN", &custom_str);
let cli = parse_ok(&[
"deepseek",
"--profile",
"google",
"--provider",
"openai",
"--model",
"glm-5",
"--base-url",
"https://openai-compatible.example/v4",
]);
let resolved = ResolvedRuntimeOptions {
provider: ProviderKind::Openai,
model: "glm-5".to_string(),
api_key: None,
api_key_source: None,
base_url: "https://openai-compatible.example/v4".to_string(),
auth_mode: None,
output_mode: None,
log_level: None,
telemetry: false,
approval_policy: None,
sandbox_mode: None,
yolo: None,
http_headers: std::collections::BTreeMap::new(),
};
let cmd = build_tui_command(&cli, &resolved, Vec::new()).expect("command");
assert_eq!(
command_env(&cmd, "DEEPSEEK_PROVIDER").as_deref(),
Some("openai")
);
assert_eq!(
command_env(&cmd, "DEEPSEEK_MODEL").as_deref(),
Some("glm-5")
);
assert_eq!(
command_env(&cmd, "DEEPSEEK_BASE_URL").as_deref(),
Some("https://openai-compatible.example/v4")
);
}
#[test]
fn build_tui_command_forwards_provider_env_vars_for_all_providers() {
fn build_tui_command_forwards_provider_keyring_env_vars_for_all_providers() {
let _lock = env_lock();
let dir = tempfile::TempDir::new().expect("tempdir");
let custom = dir
@@ -2788,7 +2872,7 @@ mod tests {
provider,
model: "test-model".to_string(),
api_key: Some("test-key".to_string()),
api_key_source: Some(RuntimeApiKeySource::Env),
api_key_source: Some(RuntimeApiKeySource::Keyring),
base_url: "http://localhost:8000/v1".to_string(),
auth_mode: Some("api_key".to_string()),
output_mode: None,
@@ -2815,6 +2899,16 @@ mod tests {
"{flag}: {var} not forwarded"
);
}
assert_eq!(
command_env(&cmd, "DEEPSEEK_API_KEY_SOURCE").as_deref(),
Some("keyring"),
"{flag}: expected keyring source bridge"
);
assert_eq!(
command_env(&cmd, "DEEPSEEK_AUTH_MODE"),
None,
"{flag}: auth mode should come from config/profile, not env handoff"
);
}
}