mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-07-24 12:44:18 +08:00
fix(proxy): inject a single auth placeholder on managed Claude takeover (#5095)
Switching the Claude provider from a third-party (DeepSeek/MiMo/...) to a managed Codex provider wrote both ANTHROPIC_API_KEY and ANTHROPIC_AUTH_TOKEN as PROXY_MANAGED into ~/.claude/settings.json, making Claude Code warn "Both ANTHROPIC_AUTH_TOKEN and ANTHROPIC_API_KEY set - auth may not work as expected" on every run. The double key is an accretion artifact: the ManagedAccount takeover policy originally injected only ANTHROPIC_API_KEY (Copilot, #1049), and the Codex fix that preserved ANTHROPIC_AUTH_TOKEN to avoid the login prompt (#3784 / PR #3789) added the token on top without removing the API key insert. Inject exactly one placeholder instead: AUTH_TOKEN for Codex-managed providers (keeps the #3784 fix), API_KEY for Copilot (keeps the #1049 behavior). Local-proxy auth is unaffected - the forwarder resolves the PROXY_MANAGED placeholder from either header. Updates the three Codex takeover tests to assert API_KEY is absent and adds a regression test for the exact third-party -> Codex switch from the report. Fixes #4919
This commit is contained in:
@@ -192,17 +192,22 @@ impl ProxyService {
|
||||
for key in token_keys {
|
||||
env.remove(key);
|
||||
}
|
||||
env.insert(
|
||||
"ANTHROPIC_API_KEY".to_string(),
|
||||
json!(PROXY_TOKEN_PLACEHOLDER),
|
||||
);
|
||||
// 只注入一个认证键:两者同时存在会触发 Claude Code 的
|
||||
// "Both ANTHROPIC_AUTH_TOKEN and ANTHROPIC_API_KEY set" 警告(#4919)。
|
||||
// - Codex 系保留 AUTH_TOKEN:缺该键 Claude Code 会弹登录提示(#3784)。
|
||||
// 无条件注入而非"已存在才保留":热切换路径传入的是 provider
|
||||
// settings(预设不含该键),且旧版接管已把存量用户 live 中的键删光。
|
||||
// - Copilot 仅 API_KEY:避免与 /login 管理的 key 冲突(#1049)。
|
||||
if keep_auth_token {
|
||||
// 无条件注入而非"已存在才保留":热切换路径传入的是 provider
|
||||
// settings(预设不含该键),且旧版接管已把存量用户 live 中的键删光。
|
||||
env.insert(
|
||||
"ANTHROPIC_AUTH_TOKEN".to_string(),
|
||||
json!(PROXY_TOKEN_PLACEHOLDER),
|
||||
);
|
||||
} else {
|
||||
env.insert(
|
||||
"ANTHROPIC_API_KEY".to_string(),
|
||||
json!(PROXY_TOKEN_PLACEHOLDER),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3084,7 +3089,8 @@ mod tests {
|
||||
assert_env_str(env, "ANTHROPIC_DEFAULT_SONNET_MODEL_NAME", Some("gpt-5.4"));
|
||||
assert_env_str(env, "ANTHROPIC_DEFAULT_OPUS_MODEL", Some("claude-opus-4-8"));
|
||||
assert_env_str(env, "ANTHROPIC_DEFAULT_OPUS_MODEL_NAME", Some("gpt-5.4"));
|
||||
assert_env_str(env, "ANTHROPIC_API_KEY", Some(PROXY_TOKEN_PLACEHOLDER));
|
||||
// Codex 系只保留 AUTH_TOKEN;双键会触发 Claude Code 告警(#4919)
|
||||
assert_env_str(env, "ANTHROPIC_API_KEY", None);
|
||||
assert_env_str(env, "ANTHROPIC_AUTH_TOKEN", Some(PROXY_TOKEN_PLACEHOLDER));
|
||||
}
|
||||
|
||||
@@ -3117,7 +3123,7 @@ mod tests {
|
||||
.get("env")
|
||||
.and_then(|value| value.as_object())
|
||||
.expect("env should exist");
|
||||
assert_env_str(env, "ANTHROPIC_API_KEY", Some(PROXY_TOKEN_PLACEHOLDER));
|
||||
assert_env_str(env, "ANTHROPIC_API_KEY", None);
|
||||
assert_env_str(env, "ANTHROPIC_AUTH_TOKEN", Some(PROXY_TOKEN_PLACEHOLDER));
|
||||
}
|
||||
|
||||
@@ -3149,10 +3155,49 @@ mod tests {
|
||||
.get("env")
|
||||
.and_then(|value| value.as_object())
|
||||
.expect("env should exist");
|
||||
assert_env_str(env, "ANTHROPIC_API_KEY", Some(PROXY_TOKEN_PLACEHOLDER));
|
||||
assert_env_str(env, "ANTHROPIC_API_KEY", None);
|
||||
assert_env_str(env, "ANTHROPIC_AUTH_TOKEN", Some(PROXY_TOKEN_PLACEHOLDER));
|
||||
}
|
||||
|
||||
// #4919 复现场景:从第三方 Claude 供应商(live 已有 AUTH_TOKEN)切换到
|
||||
// Codex 受管供应商时,只应保留 AUTH_TOKEN 占位符,不得同时写入 API_KEY。
|
||||
#[test]
|
||||
fn managed_account_claude_takeover_codex_from_third_party_keeps_single_auth_key() {
|
||||
let mut provider = Provider::with_id(
|
||||
"codex".to_string(),
|
||||
"Codex".to_string(),
|
||||
json!({
|
||||
"env": {
|
||||
"ANTHROPIC_BASE_URL": "https://chatgpt.com/backend-api/codex"
|
||||
}
|
||||
}),
|
||||
None,
|
||||
);
|
||||
provider.meta = Some(ProviderMeta {
|
||||
provider_type: Some("codex_oauth".to_string()),
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
let mut live_config = json!({
|
||||
"env": {
|
||||
"ANTHROPIC_BASE_URL": "https://api.deepseek.com/anthropic",
|
||||
"ANTHROPIC_AUTH_TOKEN": "sk-third-party"
|
||||
}
|
||||
});
|
||||
ProxyService::apply_claude_takeover_fields_for_provider(
|
||||
&mut live_config,
|
||||
"http://127.0.0.1:15721",
|
||||
&provider,
|
||||
);
|
||||
|
||||
let env = live_config
|
||||
.get("env")
|
||||
.and_then(|value| value.as_object())
|
||||
.expect("env should exist");
|
||||
assert_env_str(env, "ANTHROPIC_AUTH_TOKEN", Some(PROXY_TOKEN_PLACEHOLDER));
|
||||
assert_env_str(env, "ANTHROPIC_API_KEY", None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn managed_account_claude_takeover_copilot_removes_stale_auth_token() {
|
||||
let mut provider = Provider::with_id(
|
||||
|
||||
Reference in New Issue
Block a user