From ec5b7d3bae8ba8771056d49d8cfa6b14a251fe20 Mon Sep 17 00:00:00 2001 From: Mi Tom <6468993+MDX-Tom@users.noreply.github.com> Date: Mon, 7 Sep 2026 10:44:22 +0800 Subject: [PATCH] fix(settings): make Codex auth cleanup opt-in --- .../components/general-basics-card.tsx | 17 ++++++++ apps/src/lib/api/normalize.ts | 1 + apps/src/lib/i18n/messages/en.ts | 3 ++ apps/src/lib/i18n/messages/ko.ts | 3 ++ apps/src/lib/i18n/messages/ru.ts | 3 ++ apps/src/lib/store/useAppStore.ts | 1 + apps/src/types/settings.ts | 1 + .../service/src/app_settings/api/current.rs | 14 ++++++- crates/service/src/app_settings/api/mod.rs | 5 ++- crates/service/src/app_settings/api/patch.rs | 21 +++++++--- crates/service/src/app_settings/mod.rs | 1 + crates/service/src/app_settings/shared.rs | 2 + crates/service/src/codex_profile.rs | 18 +++++++- crates/service/src/codex_profile_tests.rs | 37 ++++++++++++++++ crates/service/src/lib.rs | 12 +++--- crates/service/tests/app_settings.rs | 42 +++++++++++++++++++ 16 files changed, 164 insertions(+), 17 deletions(-) diff --git a/apps/src/app/settings/components/general-basics-card.tsx b/apps/src/app/settings/components/general-basics-card.tsx index cbd33d1fb..6eb23dff5 100644 --- a/apps/src/app/settings/components/general-basics-card.tsx +++ b/apps/src/app/settings/components/general-basics-card.tsx @@ -15,6 +15,7 @@ import type { AppSettings } from "@/types"; type GeneralBasicsSnapshot = Pick< AppSettings, | "updateAutoCheck" + | "removeRequiresOpenaiAuth" | "autoStartEnabled" | "autoStartSupported" | "showMainWindowOnStartup" @@ -143,6 +144,22 @@ export function GeneralBasicsCard({ } /> +
+
+ +

+ {t( + "开启后,在切换到 CodexManager 网关或同步配置时移除 requires_openai_auth;关闭时保留现有配置,默认关闭", + )} +

+
+ + updateSettings.mutate({ removeRequiresOpenaiAuth: value }) + } + /> +
diff --git a/apps/src/lib/api/normalize.ts b/apps/src/lib/api/normalize.ts index 9dd9024bd..17f4de5df 100644 --- a/apps/src/lib/api/normalize.ts +++ b/apps/src/lib/api/normalize.ts @@ -1812,6 +1812,7 @@ export function normalizeAppSettings(payload: unknown): AppSettings { ); return { updateAutoCheck: asBoolean(source.updateAutoCheck, true), + removeRequiresOpenaiAuth: asBoolean(source.removeRequiresOpenaiAuth, false), autoStartEnabled: asBoolean(source.autoStartEnabled, false), autoStartSupported: asBoolean(source.autoStartSupported, false), showMainWindowOnStartup: asBoolean(source.showMainWindowOnStartup, true), diff --git a/apps/src/lib/i18n/messages/en.ts b/apps/src/lib/i18n/messages/en.ts index f8c9f0378..c0ddca32f 100644 --- a/apps/src/lib/i18n/messages/en.ts +++ b/apps/src/lib/i18n/messages/en.ts @@ -184,6 +184,9 @@ export const EN_MESSAGES: MessageCatalog = { 基础设置: "Basic settings", 控制应用启动和窗口行为: "Control startup and window behavior.", 自动检查更新: "Check updates automatically", + "移除 requires_openai_auth": "Remove requires_openai_auth", + "开启后,在切换到 CodexManager 网关或同步配置时移除 requires_openai_auth;关闭时保留现有配置,默认关闭": + "When enabled, remove requires_openai_auth while switching to the CodexManager gateway or syncing the profile; when disabled, keep the existing configuration. Disabled by default.", "启动完成后在后台检查更新,并每 7 小时检查一次": "Check for updates in the background after startup, then every 7 hours.", "检测到新版本,是否现在更新?": diff --git a/apps/src/lib/i18n/messages/ko.ts b/apps/src/lib/i18n/messages/ko.ts index c7783318f..f290276e3 100644 --- a/apps/src/lib/i18n/messages/ko.ts +++ b/apps/src/lib/i18n/messages/ko.ts @@ -198,6 +198,9 @@ export const KO_MESSAGES: MessageCatalog = { "CodexManager는 Codex CLI 계정, 로컬 게이트웨이, 플랫폼 키, 요청 로그, 사용량 통계를 통합 관리하여 Codex 연결과 운영을 더 집중적이고 제어 가능하게 합니다.", 基础设置: "기본 설정", 自动检查更新: "자동 업데이트 확인", + "移除 requires_openai_auth": "requires_openai_auth 제거", + "开启后,在切换到 CodexManager 网关或同步配置时移除 requires_openai_auth;关闭时保留现有配置,默认关闭": + "켜면 CodexManager 게이트웨이로 전환하거나 프로필을 동기화할 때 requires_openai_auth를 제거하고, 끄면 기존 설정을 유지합니다. 기본값은 꺼짐입니다.", "启动完成后在后台检查更新,并每 7 小时检查一次": "시작이 완료되면 백그라운드에서 업데이트를 확인하고 이후 7시간마다 확인합니다.", "检测到新版本,是否现在更新?": diff --git a/apps/src/lib/i18n/messages/ru.ts b/apps/src/lib/i18n/messages/ru.ts index 29a8a134c..65257c626 100644 --- a/apps/src/lib/i18n/messages/ru.ts +++ b/apps/src/lib/i18n/messages/ru.ts @@ -184,6 +184,9 @@ export const RU_MESSAGES: MessageCatalog = { 基础设置: "Основные настройки", 控制应用启动和窗口行为: "Управление запуском приложения и поведением окна.", 自动检查更新: "Автопроверка обновлений", + "移除 requires_openai_auth": "Удалять requires_openai_auth", + "开启后,在切换到 CodexManager 网关或同步配置时移除 requires_openai_auth;关闭时保留现有配置,默认关闭": + "Если включено, удалять requires_openai_auth при переключении на шлюз CodexManager или синхронизации профиля; если выключено, сохранять текущую конфигурацию. По умолчанию выключено.", "启动完成后在后台检查更新,并每 7 小时检查一次": "Проверять обновления в фоне после запуска, а затем каждые 7 часов.", "检测到新版本,是否现在更新?": diff --git a/apps/src/lib/store/useAppStore.ts b/apps/src/lib/store/useAppStore.ts index 4f6bc9089..e9b992c04 100644 --- a/apps/src/lib/store/useAppStore.ts +++ b/apps/src/lib/store/useAppStore.ts @@ -65,6 +65,7 @@ export const useAppStore = create((set) => ({ }, appSettings: { updateAutoCheck: true, + removeRequiresOpenaiAuth: false, autoStartEnabled: false, autoStartSupported: false, showMainWindowOnStartup: true, diff --git a/apps/src/types/settings.ts b/apps/src/types/settings.ts index e06d4d8bc..b7e121684 100644 --- a/apps/src/types/settings.ts +++ b/apps/src/types/settings.ts @@ -51,6 +51,7 @@ export type GatewayTransportPatch = Partial; export interface AppSettings extends GatewayTransportValues { updateAutoCheck: boolean; + removeRequiresOpenaiAuth: boolean; autoStartEnabled: boolean; autoStartSupported: boolean; showMainWindowOnStartup: boolean; diff --git a/crates/service/src/app_settings/api/current.rs b/crates/service/src/app_settings/api/current.rs index 0735452a7..6a7565084 100644 --- a/crates/service/src/app_settings/api/current.rs +++ b/crates/service/src/app_settings/api/current.rs @@ -27,8 +27,9 @@ use super::{ save_persisted_bool_setting, sync_runtime_settings_from_storage, APP_SETTING_AUTHOR_SERVER_RECOMMENDATIONS_KEY, APP_SETTING_AUTHOR_SPONSORS_KEY, APP_SETTING_AUTO_START_ENABLED_KEY, APP_SETTING_CLOSE_TO_TRAY_ON_CLOSE_KEY, - APP_SETTING_ENV_OVERRIDES_KEY, APP_SETTING_GATEWAY_ACCOUNT_MAX_INFLIGHT_KEY, - APP_SETTING_GATEWAY_BACKGROUND_TASKS_KEY, APP_SETTING_GATEWAY_COMPACT_MODEL_FORWARD_RULES_KEY, + APP_SETTING_CODEX_PROFILE_REMOVE_REQUIRES_OPENAI_AUTH_KEY, APP_SETTING_ENV_OVERRIDES_KEY, + APP_SETTING_GATEWAY_ACCOUNT_MAX_INFLIGHT_KEY, APP_SETTING_GATEWAY_BACKGROUND_TASKS_KEY, + APP_SETTING_GATEWAY_COMPACT_MODEL_FORWARD_RULES_KEY, APP_SETTING_GATEWAY_FREE_ACCOUNT_MAX_MODEL_KEY, APP_SETTING_GATEWAY_MODEL_FORWARD_RULES_KEY, APP_SETTING_GATEWAY_ORIGINATOR_KEY, APP_SETTING_GATEWAY_QUOTA_GUARD_KEY, APP_SETTING_GATEWAY_RESIDENCY_REQUIREMENT_KEY, APP_SETTING_GATEWAY_ROUTE_STRATEGY_KEY, @@ -163,6 +164,11 @@ fn current_app_settings_value_inner( let runtime_time_zone = current_runtime_time_zone_value(); let update_auto_check = setting_bool(&settings, APP_SETTING_UPDATE_AUTO_CHECK_KEY, true); let auto_start_enabled = setting_bool(&settings, APP_SETTING_AUTO_START_ENABLED_KEY, false); + let remove_requires_openai_auth = setting_bool( + &settings, + APP_SETTING_CODEX_PROFILE_REMOVE_REQUIRES_OPENAI_AUTH_KEY, + false, + ); let show_main_window_on_startup = setting_bool(&settings, APP_SETTING_SHOW_MAIN_WINDOW_ON_STARTUP_KEY, true); let persisted_close_to_tray = @@ -391,6 +397,10 @@ fn current_app_settings_value_inner( "webAccessPasswordConfigured": web_access_password_configured(), }); if let Some(object) = result.as_object_mut() { + object.insert( + "removeRequiresOpenaiAuth".to_string(), + remove_requires_openai_auth.into(), + ); object.insert("zoomFactor".to_string(), zoom_factor.into()); object.insert("gatewayUserAgent".to_string(), gateway_user_agent.into()); object.insert( diff --git a/crates/service/src/app_settings/api/mod.rs b/crates/service/src/app_settings/api/mod.rs index acc8b53e5..66a867318 100644 --- a/crates/service/src/app_settings/api/mod.rs +++ b/crates/service/src/app_settings/api/mod.rs @@ -49,8 +49,9 @@ pub(super) use super::{normalize_optional_text, parse_bool_with_default}; pub(super) use super::{ APP_SETTING_AUTHOR_SERVER_RECOMMENDATIONS_KEY, APP_SETTING_AUTHOR_SPONSORS_KEY, APP_SETTING_AUTO_START_ENABLED_KEY, APP_SETTING_CLOSE_TO_TRAY_ON_CLOSE_KEY, - APP_SETTING_ENV_OVERRIDES_KEY, APP_SETTING_GATEWAY_ACCOUNT_MAX_INFLIGHT_KEY, - APP_SETTING_GATEWAY_BACKGROUND_TASKS_KEY, APP_SETTING_GATEWAY_COMPACT_MODEL_FORWARD_RULES_KEY, + APP_SETTING_CODEX_PROFILE_REMOVE_REQUIRES_OPENAI_AUTH_KEY, APP_SETTING_ENV_OVERRIDES_KEY, + APP_SETTING_GATEWAY_ACCOUNT_MAX_INFLIGHT_KEY, APP_SETTING_GATEWAY_BACKGROUND_TASKS_KEY, + APP_SETTING_GATEWAY_COMPACT_MODEL_FORWARD_RULES_KEY, APP_SETTING_GATEWAY_FREE_ACCOUNT_MAX_MODEL_KEY, APP_SETTING_GATEWAY_MODEL_FORWARD_RULES_KEY, APP_SETTING_GATEWAY_ORIGINATOR_KEY, APP_SETTING_GATEWAY_QUOTA_GUARD_KEY, APP_SETTING_GATEWAY_RESIDENCY_REQUIREMENT_KEY, APP_SETTING_GATEWAY_ROUTE_STRATEGY_KEY, diff --git a/crates/service/src/app_settings/api/patch.rs b/crates/service/src/app_settings/api/patch.rs index 1775691bb..fde558cf4 100644 --- a/crates/service/src/app_settings/api/patch.rs +++ b/crates/service/src/app_settings/api/patch.rs @@ -6,11 +6,12 @@ use super::author_links::{ normalize_author_link_items, serialize_author_link_items, AuthorLinkItem, }; use super::{ - save_persisted_app_setting, set_auto_start_enabled_setting, set_close_to_tray_on_close_setting, - set_codex_cli_guide_dismissed, set_env_overrides, set_gateway_account_max_inflight, - set_gateway_background_tasks, set_gateway_compact_model_forward_rules, - set_gateway_free_account_max_model, set_gateway_model_forward_rules, set_gateway_originator, - set_gateway_quota_guard, set_gateway_residency_requirement, set_gateway_route_strategy, + save_persisted_app_setting, save_persisted_bool_setting, set_auto_start_enabled_setting, + set_close_to_tray_on_close_setting, set_codex_cli_guide_dismissed, set_env_overrides, + set_gateway_account_max_inflight, set_gateway_background_tasks, + set_gateway_compact_model_forward_rules, set_gateway_free_account_max_model, + set_gateway_model_forward_rules, set_gateway_originator, set_gateway_quota_guard, + set_gateway_residency_requirement, set_gateway_route_strategy, set_gateway_sse_keepalive_enabled, set_gateway_sse_keepalive_interval_ms, set_gateway_thread_aware_account_distribution_enabled, set_gateway_upstream_proxy_bypass_hosts, set_gateway_upstream_proxy_url, set_gateway_upstream_stream_timeout_ms, @@ -20,13 +21,15 @@ use super::{ set_ui_appearance_preset, set_ui_locale, set_ui_low_transparency_enabled, set_ui_theme, set_ui_zoom_factor, set_update_auto_check_enabled, BackgroundTasksInput, QuotaGuardInput, APP_SETTING_AUTHOR_SERVER_RECOMMENDATIONS_KEY, APP_SETTING_AUTHOR_SPONSORS_KEY, - APP_SETTING_PLUGIN_MARKET_MODE_KEY, APP_SETTING_PLUGIN_MARKET_SOURCE_URL_KEY, + APP_SETTING_CODEX_PROFILE_REMOVE_REQUIRES_OPENAI_AUTH_KEY, APP_SETTING_PLUGIN_MARKET_MODE_KEY, + APP_SETTING_PLUGIN_MARKET_SOURCE_URL_KEY, }; #[derive(Debug, Clone, Default, Deserialize)] #[serde(rename_all = "camelCase")] pub(super) struct AppSettingsPatch { update_auto_check: Option, + remove_requires_openai_auth: Option, auto_start_enabled: Option, show_main_window_on_startup: Option, close_to_tray_on_close: Option, @@ -102,6 +105,12 @@ pub(super) fn apply_app_settings_patch(patch: AppSettingsPatch) -> Result<(), St if let Some(enabled) = patch.update_auto_check { set_update_auto_check_enabled(enabled)?; } + if let Some(enabled) = patch.remove_requires_openai_auth { + save_persisted_bool_setting( + APP_SETTING_CODEX_PROFILE_REMOVE_REQUIRES_OPENAI_AUTH_KEY, + enabled, + )?; + } if let Some(enabled) = patch.auto_start_enabled { set_auto_start_enabled_setting(enabled)?; } diff --git a/crates/service/src/app_settings/mod.rs b/crates/service/src/app_settings/mod.rs index 34ae048a7..1e75dc432 100644 --- a/crates/service/src/app_settings/mod.rs +++ b/crates/service/src/app_settings/mod.rs @@ -52,6 +52,7 @@ pub(crate) use shared::{normalize_optional_text, parse_bool_with_default}; pub use shared::{ APP_SETTING_AUTHOR_SERVER_RECOMMENDATIONS_KEY, APP_SETTING_AUTHOR_SPONSORS_KEY, APP_SETTING_AUTO_START_ENABLED_KEY, APP_SETTING_CLOSE_TO_TRAY_ON_CLOSE_KEY, + APP_SETTING_CODEX_PROFILE_REMOVE_REQUIRES_OPENAI_AUTH_KEY, APP_SETTING_DISTRIBUTION_ENABLED_KEY, APP_SETTING_ENV_OVERRIDES_KEY, APP_SETTING_GATEWAY_ACCOUNT_MAX_INFLIGHT_KEY, APP_SETTING_GATEWAY_BACKGROUND_TASKS_KEY, APP_SETTING_GATEWAY_COMPACT_MODEL_FORWARD_RULES_KEY, diff --git a/crates/service/src/app_settings/shared.rs b/crates/service/src/app_settings/shared.rs index e9bdbba98..5747b168c 100644 --- a/crates/service/src/app_settings/shared.rs +++ b/crates/service/src/app_settings/shared.rs @@ -11,6 +11,8 @@ pub const APP_SETTING_UI_CODEX_CLI_GUIDE_DISMISSED_KEY: &str = "ui.codex_cli_gui pub const APP_SETTING_UI_THEME_KEY: &str = "ui.theme"; pub const APP_SETTING_UI_APPEARANCE_PRESET_KEY: &str = "ui.appearance_preset"; pub const APP_SETTING_UI_LOCALE_KEY: &str = "ui.locale"; +pub const APP_SETTING_CODEX_PROFILE_REMOVE_REQUIRES_OPENAI_AUTH_KEY: &str = + "codex_profile.remove_requires_openai_auth"; pub const APP_SETTING_SERVICE_ADDR_KEY: &str = "app.service_addr"; pub const APP_SETTING_AUTHOR_SPONSORS_KEY: &str = "author.sponsors"; pub const APP_SETTING_AUTHOR_SERVER_RECOMMENDATIONS_KEY: &str = "author.server_recommendations"; diff --git a/crates/service/src/codex_profile.rs b/crates/service/src/codex_profile.rs index d8b05f919..3868ade50 100644 --- a/crates/service/src/codex_profile.rs +++ b/crates/service/src/codex_profile.rs @@ -425,6 +425,7 @@ pub(crate) fn apply_gateway( &paths.gateway_model_catalog_path, supports_websockets, &secret, + remove_requires_openai_auth_enabled(), )?; write_profile_files( &profile_dir, @@ -1931,6 +1932,14 @@ fn expand_home_prefix(input: &str) -> PathBuf { PathBuf::from(input) } +fn remove_requires_openai_auth_enabled() -> bool { + crate::app_settings::get_persisted_app_setting( + crate::app_settings::APP_SETTING_CODEX_PROFILE_REMOVE_REQUIRES_OPENAI_AUTH_KEY, + ) + .map(|value| crate::app_settings::parse_bool_with_default(&value, false)) + .unwrap_or(false) +} + fn profile_key(profile_dir: &Path) -> String { profile_dir.to_string_lossy().to_string() } @@ -2041,6 +2050,7 @@ fn patch_config_for_gateway( managed_catalog_path: &Path, supports_websockets: bool, bearer_token: &str, + remove_requires_openai_auth: bool, ) -> Result { let mut doc = parse_config(content.as_deref().unwrap_or(""))?; doc.as_table_mut() @@ -2076,8 +2086,11 @@ fn patch_config_for_gateway( // Codex only treats actor authorization as an extension capability for custom providers // that do not use ambient OpenAI auth. A provider-scoped bearer token works for local and // remote CodexManager gateways without coupling the profile to a movable desktop executable. - // It is mutually exclusive with command/env/ambient auth, so remove stale values first. - provider.remove("requires_openai_auth"); + // Keep the user's existing requires_openai_auth value unless the opt-in setting asks us to + // remove it. + if remove_requires_openai_auth { + provider.remove("requires_openai_auth"); + } set_provider_bearer_auth(provider, bearer_token)?; provider.insert("base_url", toml_value(base_url)); provider.insert("wire_api", toml_value("responses")); @@ -2162,6 +2175,7 @@ pub(crate) fn sync_active_gateway_profile_from_storage(storage: &Storage) -> Res &paths.gateway_model_catalog_path, supports_websockets, secret, + remove_requires_openai_auth_enabled(), )?; write_atomic(&profile_dir.join(CONFIG_FILE), &config_toml)?; if state.supports_websockets != Some(supports_websockets) { diff --git a/crates/service/src/codex_profile_tests.rs b/crates/service/src/codex_profile_tests.rs index f9093a6c7..9e7782f65 100644 --- a/crates/service/src/codex_profile_tests.rs +++ b/crates/service/src/codex_profile_tests.rs @@ -179,6 +179,7 @@ name = "Other" &managed_catalog, true, "cm-managed-key", + true, ) .expect("patch gateway"); @@ -220,11 +221,45 @@ name = "Other" &managed_catalog, false, "cm-managed-key", + true, ) .expect("disable gateway websocket"); assert!(without_websocket.contains("supports_websockets = false")); } +#[test] +fn gateway_config_preserves_requires_openai_auth_when_removal_is_disabled() { + let input = r#" +model_provider = "cm" + +[model_providers.cm] +name = "Custom Gateway" +requires_openai_auth = true +"#; + + let output = patch_config_for_gateway( + Some(input.to_string()), + "http://127.0.0.1:48770/v1", + Path::new("/tmp/gateway-models.json"), + false, + "cm-managed-key", + false, + ) + .expect("patch gateway without removing auth requirement"); + let doc = parse_config(&output).expect("parse patched gateway config"); + let provider = doc + .get("model_providers") + .and_then(Item::as_table) + .and_then(|providers| providers.get(PROVIDER_ID)) + .and_then(Item::as_table) + .expect("managed provider"); + + assert_eq!( + provider.get("requires_openai_auth").and_then(Item::as_bool), + Some(true) + ); +} + #[test] fn gateway_config_preserves_custom_managed_provider_values() { let input = r#" @@ -248,6 +283,7 @@ http_headers = { "x-existing-header" = "keep", "x-openai-actor-authorization" = &managed_catalog, true, "cm-managed-key", + true, ) .expect("patch gateway"); let doc = parse_config(&output).expect("parse patched gateway config"); @@ -336,6 +372,7 @@ fn invalid_toml_is_rejected() { Path::new("/tmp/gateway-models.json"), false, "cm-managed-key", + false, ) .is_err()); } diff --git a/crates/service/src/lib.rs b/crates/service/src/lib.rs index dabc52e92..b43b588b9 100644 --- a/crates/service/src/lib.rs +++ b/crates/service/src/lib.rs @@ -138,11 +138,13 @@ pub use app_settings::{ set_show_main_window_on_startup_setting, set_ui_appearance_preset, set_ui_low_transparency_enabled, set_ui_theme, set_update_auto_check_enabled, sync_runtime_settings_from_storage, BackgroundTasksInput, APP_SETTING_AUTO_START_ENABLED_KEY, - APP_SETTING_CLOSE_TO_TRAY_ON_CLOSE_KEY, APP_SETTING_DISTRIBUTION_ENABLED_KEY, - APP_SETTING_ENV_OVERRIDES_KEY, APP_SETTING_GATEWAY_ACCOUNT_MAX_INFLIGHT_KEY, - APP_SETTING_GATEWAY_BACKGROUND_TASKS_KEY, APP_SETTING_GATEWAY_FREE_ACCOUNT_MAX_MODEL_KEY, - APP_SETTING_GATEWAY_MODEL_FORWARD_RULES_KEY, APP_SETTING_GATEWAY_ORIGINATOR_KEY, - APP_SETTING_GATEWAY_QUOTA_GUARD_KEY, APP_SETTING_GATEWAY_REQUEST_COMPRESSION_ENABLED_KEY, + APP_SETTING_CLOSE_TO_TRAY_ON_CLOSE_KEY, + APP_SETTING_CODEX_PROFILE_REMOVE_REQUIRES_OPENAI_AUTH_KEY, + APP_SETTING_DISTRIBUTION_ENABLED_KEY, APP_SETTING_ENV_OVERRIDES_KEY, + APP_SETTING_GATEWAY_ACCOUNT_MAX_INFLIGHT_KEY, APP_SETTING_GATEWAY_BACKGROUND_TASKS_KEY, + APP_SETTING_GATEWAY_FREE_ACCOUNT_MAX_MODEL_KEY, APP_SETTING_GATEWAY_MODEL_FORWARD_RULES_KEY, + APP_SETTING_GATEWAY_ORIGINATOR_KEY, APP_SETTING_GATEWAY_QUOTA_GUARD_KEY, + APP_SETTING_GATEWAY_REQUEST_COMPRESSION_ENABLED_KEY, APP_SETTING_GATEWAY_RESIDENCY_REQUIREMENT_KEY, APP_SETTING_GATEWAY_ROUTE_STRATEGY_KEY, APP_SETTING_GATEWAY_SSE_KEEPALIVE_ENABLED_KEY, APP_SETTING_GATEWAY_SSE_KEEPALIVE_INTERVAL_MS_KEY, diff --git a/crates/service/tests/app_settings.rs b/crates/service/tests/app_settings.rs index a698e0a49..37e3d17b6 100644 --- a/crates/service/tests/app_settings.rs +++ b/crates/service/tests/app_settings.rs @@ -396,6 +396,48 @@ fn app_settings_roundtrip_gateway_user_agent_and_validates_header_value() { }); } +#[test] +fn app_settings_remove_requires_openai_auth_defaults_off_and_persists_updates() { + with_temp_db(|db_path| { + let defaults = codexmanager_service::app_settings_get().expect("read default settings"); + assert_eq!(defaults["removeRequiresOpenaiAuth"], false); + let storage = Storage::open(db_path).expect("open storage"); + assert_eq!( + storage + .get_app_setting( + codexmanager_service::APP_SETTING_CODEX_PROFILE_REMOVE_REQUIRES_OPENAI_AUTH_KEY + ) + .expect("read default persisted setting"), + None + ); + drop(storage); + + let enabled = codexmanager_service::app_settings_set(Some(&json!({ + "removeRequiresOpenaiAuth": true + }))) + .expect("enable requires_openai_auth removal"); + assert_eq!(enabled["removeRequiresOpenaiAuth"], true); + + let storage = Storage::open(db_path).expect("open storage"); + assert_eq!( + storage + .get_app_setting( + codexmanager_service::APP_SETTING_CODEX_PROFILE_REMOVE_REQUIRES_OPENAI_AUTH_KEY + ) + .expect("read persisted setting") + .as_deref(), + Some("1") + ); + drop(storage); + + let disabled = codexmanager_service::app_settings_set(Some(&json!({ + "removeRequiresOpenaiAuth": false + }))) + .expect("disable requires_openai_auth removal"); + assert_eq!(disabled["removeRequiresOpenaiAuth"], false); + }); +} + #[test] fn app_settings_rejects_password_mode_without_password() { with_temp_db(|_| {