Add Codex auth preservation setting

This commit is contained in:
Jason
2026-05-30 14:13:58 +08:00
parent 8f83fa2063
commit 2683af57cb
12 changed files with 171 additions and 3 deletions
+7 -3
View File
@@ -788,9 +788,9 @@ pub fn read_codex_live_settings() -> Result<Value, AppError> {
/// Route a Codex live write between full auth+config or config-only.
///
/// Official providers with usable login material own `auth.json`; everyone
/// else only touches `config.toml` so the user's ChatGPT login cache survives
/// third-party switches.
/// Official providers with usable login material own `auth.json`. Third-party
/// providers only touch `config.toml` when the compatibility setting is enabled
/// so the user's ChatGPT login cache survives provider switches.
pub fn write_codex_live_for_provider(
category: Option<&str>,
auth: &Value,
@@ -798,6 +798,10 @@ pub fn write_codex_live_for_provider(
) -> Result<(), AppError> {
if category == Some("official") && codex_auth_has_login_material(auth) {
write_codex_live_atomic(auth, config_text)
} else if category != Some("official")
&& !crate::settings::preserve_codex_official_auth_on_switch()
{
write_codex_live_atomic(auth, config_text)
} else {
let live_config = prepare_codex_provider_live_config(auth, config_text.unwrap_or(""))?;
write_codex_live_config_atomic(Some(&live_config))
+90
View File
@@ -2637,6 +2637,96 @@ wire_api = "responses"
);
}
#[test]
#[serial]
fn codex_custom_provider_live_write_can_overwrite_auth_when_preserve_disabled() {
let _home = TempHome::new();
crate::settings::reload_settings().expect("reload settings");
crate::settings::update_settings(crate::settings::AppSettings {
preserve_codex_official_auth_on_switch: false,
..Default::default()
})
.expect("disable Codex official auth preservation");
let db = Arc::new(Database::memory().expect("init db"));
let service = ProxyService::new(db);
let oauth_auth = json!({
"auth_mode": "chatgpt",
"tokens": {
"id_token": "oauth-id",
"access_token": "oauth-access"
}
});
crate::codex_config::write_codex_live_atomic(
&oauth_auth,
Some(
r#"model_provider = "openai"
model = "gpt-5-codex"
"#,
),
)
.expect("seed live OAuth auth");
let mut provider = Provider::with_id(
"rightcode".to_string(),
"RightCode".to_string(),
json!({
"auth": {
"OPENAI_API_KEY": "rightcode-key"
},
"config": r#"model_provider = "rightcode"
model = "gpt-5-codex"
[model_providers.rightcode]
name = "RightCode"
base_url = "https://rightcode.example/v1"
wire_api = "responses"
"#
}),
None,
);
provider.category = Some("custom".to_string());
let takeover_auth = json!({
"OPENAI_API_KEY": PROXY_TOKEN_PLACEHOLDER
});
let takeover_settings = json!({
"auth": takeover_auth,
"config": r#"model_provider = "rightcode"
model = "gpt-5-codex"
[model_providers.rightcode]
name = "RightCode"
base_url = "http://127.0.0.1:15721/v1"
wire_api = "responses"
"#
});
service
.write_codex_live_for_provider(&takeover_settings, Some(&provider))
.expect("write provider-driven Codex live config");
let live_auth: Value =
crate::config::read_json_file(&crate::codex_config::get_codex_auth_path())
.expect("read live auth");
assert_eq!(
live_auth,
json!({
"OPENAI_API_KEY": PROXY_TOKEN_PLACEHOLDER
}),
"disabled preservation should let third-party switches overwrite auth.json"
);
let live_config = std::fs::read_to_string(crate::codex_config::get_codex_config_path())
.expect("read live config");
assert!(
!live_config.contains("experimental_bearer_token"),
"provider token should stay in auth.json when preservation is disabled"
);
crate::settings::update_settings(crate::settings::AppSettings::default())
.expect("reset settings");
}
#[test]
fn update_toml_base_url_updates_active_model_provider_base_url() {
let input = r#"
+14
View File
@@ -253,6 +253,9 @@ pub struct AppSettings {
/// Whether to show the failover toggle independently on the main page
#[serde(default)]
pub enable_failover_toggle: bool,
/// Keep Codex ChatGPT login material in auth.json when switching to third-party providers
#[serde(default = "default_true")]
pub preserve_codex_official_auth_on_switch: bool,
/// User has confirmed the failover toggle first-run notice
#[serde(default, skip_serializing_if = "Option::is_none")]
pub failover_confirmed: Option<bool>,
@@ -366,6 +369,7 @@ impl Default for AppSettings {
usage_confirmed: None,
stream_check_confirmed: None,
enable_failover_toggle: false,
preserve_codex_official_auth_on_switch: true,
failover_confirmed: None,
first_run_notice_confirmed: None,
common_config_confirmed: None,
@@ -699,6 +703,16 @@ pub fn get_hermes_override_dir() -> Option<PathBuf> {
.map(|p| resolve_override_path(p))
}
pub fn preserve_codex_official_auth_on_switch() -> bool {
settings_store()
.read()
.unwrap_or_else(|e| {
log::warn!("设置锁已毒化,使用恢复值: {e}");
e.into_inner()
})
.preserve_codex_official_auth_on_switch
}
// ===== 当前供应商管理函数 =====
/// 获取指定应用类型的当前供应商 ID(从本地 settings 读取)