Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions codex-rs/app-server/src/config_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ use tracing::warn;
#[derive(Clone)]
pub(crate) struct ConfigManager {
codex_home: PathBuf,
auth_home: PathBuf,
cli_overrides: Arc<RwLock<Vec<(String, TomlValue)>>>,
runtime_feature_enablement: Arc<RwLock<BTreeMap<String, bool>>>,
loader_overrides: LoaderOverrides,
Expand All @@ -39,6 +40,7 @@ pub(crate) struct ConfigManager {
impl ConfigManager {
pub(crate) fn new(
codex_home: PathBuf,
auth_home: PathBuf,
cli_overrides: Vec<(String, TomlValue)>,
loader_overrides: LoaderOverrides,
strict_config: bool,
Expand All @@ -48,6 +50,7 @@ impl ConfigManager {
) -> Self {
Self {
codex_home,
auth_home,
cli_overrides: Arc::new(RwLock::new(cli_overrides)),
runtime_feature_enablement: Arc::new(RwLock::new(BTreeMap::new())),
loader_overrides,
Expand Down Expand Up @@ -168,6 +171,7 @@ impl ConfigManager {
self.current_cli_overrides(),
)
.await?;
config.auth_home = AbsolutePathBuf::from_absolute_path(self.auth_home.clone())?;
if self.loader_overrides.user_config_path.is_some()
|| self.loader_overrides.user_config_profile.is_some()
{
Expand Down Expand Up @@ -240,6 +244,7 @@ impl ConfigManager {

let mut config = codex_core::config::ConfigBuilder::default()
.codex_home(self.codex_home.clone())
.auth_home(self.auth_home.clone())
.cli_overrides(merged_cli_overrides)
.loader_overrides(self.loader_overrides.clone())
.strict_config(self.strict_config)
Expand Down Expand Up @@ -306,6 +311,7 @@ impl ConfigManager {
cloud_config_bundle: CloudConfigBundleLoader,
) -> Self {
Self::new(
codex_home.clone(),
codex_home,
cli_overrides,
loader_overrides,
Expand Down
1 change: 1 addition & 0 deletions codex-rs/app-server/src/in_process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,7 @@ async fn start_uninitialized(args: InProcessStartArgs) -> IoResult<InProcessClie
let processor_outgoing = Arc::clone(&outgoing_message_sender);
let config_manager = ConfigManager::new(
args.config.codex_home.to_path_buf(),
args.config.auth_home.to_path_buf(),
args.cli_overrides,
args.loader_overrides,
args.strict_config,
Expand Down
1 change: 1 addition & 0 deletions codex-rs/app-server/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,7 @@ pub async fn run_main_with_transport_options(
.map(Arc::new)
.map_err(std::io::Error::other)?;
let config_manager = ConfigManager::new(
codex_home.to_path_buf(),
codex_home.to_path_buf(),
cli_kv_overrides.clone(),
loader_overrides,
Expand Down
1 change: 1 addition & 0 deletions codex-rs/app-server/src/mcp_refresh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ mod tests {
bad_loads: AtomicUsize::new(0),
});
let config_manager = ConfigManager::new(
temp_dir.path().to_path_buf(),
temp_dir.path().to_path_buf(),
Vec::new(),
LoaderOverrides::without_managed_config_for_tests(),
Expand Down
1 change: 1 addition & 0 deletions codex-rs/app-server/src/message_processor_tracing_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ async fn build_test_processor(
AuthManager::shared_from_config(config.as_ref(), /*enable_codex_api_key_env*/ false).await;
let config_manager = ConfigManager::new(
config.codex_home.to_path_buf(),
config.auth_home.to_path_buf(),
Vec::new(),
LoaderOverrides::default(),
/*strict_config*/ false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -612,6 +612,7 @@ mod thread_processor_behavior_tests {
supports_websockets: true,
};
let config_manager = ConfigManager::new(
temp_dir.path().to_path_buf(),
temp_dir.path().to_path_buf(),
Vec::new(),
LoaderOverrides::default(),
Expand Down
3 changes: 2 additions & 1 deletion codex-rs/cloud-config/src/bundle_loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,13 @@ pub fn cloud_config_bundle_loader(

pub async fn cloud_config_bundle_loader_for_storage(
codex_home: PathBuf,
auth_home: PathBuf,
enable_codex_api_key_env: bool,
credentials_store_mode: AuthCredentialsStoreMode,
chatgpt_base_url: String,
) -> CloudConfigBundleLoader {
let auth_manager = AuthManager::shared(
codex_home.clone(),
auth_home,
enable_codex_api_key_env,
credentials_store_mode,
Some(chatgpt_base_url.clone()),
Expand Down
16 changes: 16 additions & 0 deletions codex-rs/core/src/config/config_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,22 @@ async fn load_config_normalizes_relative_cwd_override() -> std::io::Result<()> {
Ok(())
}

#[tokio::test]
async fn config_builder_auth_home_overrides_auth_storage_only() -> std::io::Result<()> {
let codex_home = tempdir()?;
let auth_home = codex_home.path().join("auth-profiles").join("work");
let config = ConfigBuilder::without_managed_config_for_tests()
.codex_home(codex_home.path().to_path_buf())
.auth_home(auth_home.clone())
.build()
.await?;

assert_eq!(config.codex_home, codex_home.abs());
assert_eq!(config.auth_home.to_path_buf(), auth_home);
assert_eq!(AuthManagerConfig::codex_home(&config), auth_home);
Ok(())
}

#[tokio::test]
async fn load_config_loads_global_agents_instructions() -> std::io::Result<()> {
let codex_home = tempdir()?;
Expand Down
32 changes: 27 additions & 5 deletions codex-rs/core/src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -852,6 +852,10 @@ pub struct Config {
/// can be overridden by the `CODEX_LAB_HOME` environment variable).
pub codex_home: AbsolutePathBuf,

/// Directory used for auth credential storage for this invocation. Defaults
/// to `codex_home`, but may point at an auth profile home.
pub auth_home: AbsolutePathBuf,

/// Directory where Codex stores the SQLite state DB.
pub sqlite_home: PathBuf,

Expand Down Expand Up @@ -1104,7 +1108,7 @@ pub struct TerminalResizeReflowConfig {

impl AuthManagerConfig for Config {
fn codex_home(&self) -> PathBuf {
self.codex_home.to_path_buf()
self.auth_home.to_path_buf()
}

fn cli_auth_credentials_store_mode(&self) -> AuthCredentialsStoreMode {
Expand All @@ -1123,6 +1127,7 @@ impl AuthManagerConfig for Config {
#[derive(Clone, Default)]
pub struct ConfigBuilder {
codex_home: Option<PathBuf>,
auth_home: Option<PathBuf>,
cli_overrides: Option<Vec<(String, TomlValue)>>,
harness_overrides: Option<ConfigOverrides>,
loader_overrides: Option<LoaderOverrides>,
Expand All @@ -1138,6 +1143,11 @@ impl ConfigBuilder {
self
}

pub fn auth_home(mut self, auth_home: PathBuf) -> Self {
self.auth_home = Some(auth_home);
self
}

pub fn cli_overrides(mut self, cli_overrides: Vec<(String, TomlValue)>) -> Self {
self.cli_overrides = Some(cli_overrides);
self
Expand Down Expand Up @@ -1184,6 +1194,7 @@ impl ConfigBuilder {
async fn build_inner(self) -> std::io::Result<Config> {
let Self {
codex_home,
auth_home,
cli_overrides,
harness_overrides,
loader_overrides,
Expand All @@ -1196,6 +1207,10 @@ impl ConfigBuilder {
Some(codex_home) => AbsolutePathBuf::from_absolute_path(codex_home)?,
None => find_codex_home()?,
};
let auth_home = match auth_home {
Some(auth_home) => AbsolutePathBuf::from_absolute_path(auth_home)?,
None => codex_home.clone(),
};
let cli_overrides = cli_overrides.unwrap_or_default();
let mut harness_overrides = harness_overrides.unwrap_or_default();
let loader_overrides = loader_overrides.unwrap_or_default();
Expand Down Expand Up @@ -1274,20 +1289,23 @@ impl ConfigBuilder {
lock_config_layer_stack,
)
.await?;
config.auth_home = auth_home;
config.config_lock_toml = Some(Arc::new(expected_lock_config));
config.config_lock_allow_codex_version_mismatch = allow_codex_version_mismatch;
config.config_lock_save_fields_resolved_from_model_catalog =
save_fields_resolved_from_model_catalog;
return Ok(config);
}
Config::load_config_with_layer_stack(
let mut config = Config::load_config_with_layer_stack(
LOCAL_FS.as_ref(),
config_toml,
harness_overrides,
codex_home,
config_layer_stack,
)
.await
.await?;
config.auth_home = auth_home;
Ok(config)
}

#[cfg(test)]
Expand Down Expand Up @@ -1502,7 +1520,7 @@ impl Config {
.map(AbsolutePathBuf::try_from)
.transpose()?;

Self::load_config_with_layer_stack(
let mut config = Self::load_config_with_layer_stack(
LOCAL_FS.as_ref(),
cfg,
ConfigOverrides {
Expand All @@ -1513,7 +1531,9 @@ impl Config {
refreshed_config.codex_home.clone(),
config_layer_stack,
)
.await
.await?;
config.auth_home = refreshed_config.auth_home.clone();
Ok(config)
}

/// This is the preferred way to create an instance of [Config].
Expand Down Expand Up @@ -2673,6 +2693,7 @@ impl Config {
workspace_roots: workspace_roots_override,
} = overrides;
let bypass_hook_trust = bypass_hook_trust.unwrap_or_default();
let auth_home = codex_home.clone();

if bypass_hook_trust {
startup_warnings.push(
Expand Down Expand Up @@ -3543,6 +3564,7 @@ impl Config {
agent_job_max_runtime_seconds,
agent_interrupt_message_enabled,
codex_home,
auth_home,
sqlite_home,
log_dir,
config_lock_export_dir: cfg
Expand Down
11 changes: 10 additions & 1 deletion codex-rs/exec/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ use codex_login::AuthConfig;
use codex_login::default_client::set_default_client_residency_requirement;
use codex_login::default_client::set_default_originator;
use codex_login::enforce_login_restrictions;
use codex_login::profile_home;
use codex_model_provider_info::LMSTUDIO_OSS_PROVIDER_ID;
use codex_model_provider_info::OLLAMA_OSS_PROVIDER_ID;
use codex_otel::set_parent_from_context;
Expand Down Expand Up @@ -265,6 +266,7 @@ pub async fn run_main(cli: Cli, arg0_paths: Arg0DispatchPaths) -> anyhow::Result
oss,
oss_provider,
config_profile_v2,
auth_profile,
sandbox_mode: sandbox_mode_cli_arg,
dangerously_bypass_approvals_and_sandbox,
bypass_hook_trust,
Expand Down Expand Up @@ -323,6 +325,11 @@ pub async fn run_main(cli: Cli, arg0_paths: Arg0DispatchPaths) -> anyhow::Result
let user_config_path = config_profile_v2
.as_ref()
.map(|profile_v2| resolve_profile_v2_config_path(&codex_home, profile_v2));
let auth_home = match auth_profile.as_deref() {
Some(profile) => profile_home(&codex_home, profile)
.map_err(|err| anyhow::anyhow!("invalid --auth-profile {profile:?}: {err}"))?,
None => codex_home.to_path_buf(),
};
let loader_overrides = LoaderOverrides {
user_config_path,
user_config_profile: config_profile_v2,
Expand All @@ -347,6 +354,7 @@ pub async fn run_main(cli: Cli, arg0_paths: Arg0DispatchPaths) -> anyhow::Result
.unwrap_or_else(|| "https://chatgpt.com/backend-api/".to_string());
let cloud_config_bundle = cloud_config_bundle_loader_for_storage(
codex_home.to_path_buf(),
auth_home.clone(),
/*enable_codex_api_key_env*/ false,
bootstrap_config_toml
.cli_auth_credentials_store
Expand Down Expand Up @@ -435,6 +443,7 @@ pub async fn run_main(cli: Cli, arg0_paths: Arg0DispatchPaths) -> anyhow::Result
let build_config = |overrides| {
ConfigBuilder::default()
.codex_home(codex_home.to_path_buf())
.auth_home(auth_home.clone())
.cli_overrides(cli_kv_overrides.clone())
.harness_overrides(overrides)
.loader_overrides(loader_overrides.clone())
Expand Down Expand Up @@ -464,7 +473,7 @@ pub async fn run_main(cli: Cli, arg0_paths: Arg0DispatchPaths) -> anyhow::Result
set_default_client_residency_requirement(config.enforce_residency.value());

if let Err(err) = enforce_login_restrictions(&AuthConfig {
codex_home: config.codex_home.to_path_buf(),
codex_home: config.auth_home.to_path_buf(),
auth_credentials_store_mode: config.cli_auth_credentials_store_mode,
forced_login_method: config.forced_login_method,
forced_chatgpt_workspace_id: config.forced_chatgpt_workspace_id.clone(),
Expand Down
Loading
Loading