Make core auth a separate crate

- Move auth-owned source and tests into `auth` as a standalone workspace crate.
- Move `create_client` into `codex-client` and import it directly where needed.

Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
Ahmed Ibrahim
2026-03-19 12:55:20 -07:00
co-authored by Codex
parent df7a587291
commit 60192f2a5f
65 changed files with 321 additions and 167 deletions
+41 -2
View File
@@ -408,6 +408,7 @@ dependencies = [
"base64 0.22.1",
"chrono",
"codex-app-server-protocol",
"codex-client",
"codex-core",
"codex-protocol",
"codex-utils-cargo-bin",
@@ -1425,6 +1426,7 @@ dependencies = [
"codex-arg0",
"codex-backend-client",
"codex-chatgpt",
"codex-client",
"codex-cloud-requirements",
"codex-core",
"codex-exec-server",
@@ -1596,6 +1598,34 @@ dependencies = [
"tokio-util",
]
[[package]]
name = "codex-auth"
version = "0.0.0"
dependencies = [
"anyhow",
"async-trait",
"base64 0.22.1",
"chrono",
"codex-app-server-protocol",
"codex-client",
"codex-keyring-store",
"codex-otel",
"codex-protocol",
"keyring",
"once_cell",
"pretty_assertions",
"reqwest",
"schemars 0.8.22",
"serde",
"serde_json",
"serial_test",
"sha2",
"tempfile",
"thiserror 2.0.18",
"tokio",
"tracing",
]
[[package]]
name = "codex-backend-client"
version = "0.0.0"
@@ -1626,6 +1656,7 @@ version = "0.0.0"
dependencies = [
"anyhow",
"clap",
"codex-client",
"codex-connectors",
"codex-core",
"codex-git",
@@ -1692,6 +1723,8 @@ version = "0.0.0"
dependencies = [
"async-trait",
"bytes",
"codex-config",
"codex-terminal",
"codex-utils-cargo-bin",
"codex-utils-rustls-provider",
"eventsource-stream",
@@ -1699,8 +1732,10 @@ dependencies = [
"http 1.4.0",
"opentelemetry",
"opentelemetry_sdk",
"os_info",
"pretty_assertions",
"rand 0.9.2",
"regex-lite",
"reqwest",
"rustls",
"rustls-native-certs",
@@ -1713,6 +1748,7 @@ dependencies = [
"tracing",
"tracing-opentelemetry",
"tracing-subscriber",
"wiremock",
"zstd",
]
@@ -1841,6 +1877,7 @@ dependencies = [
"codex-arg0",
"codex-artifacts",
"codex-async-utils",
"codex-auth",
"codex-client",
"codex-config",
"codex-connectors",
@@ -1895,7 +1932,6 @@ dependencies = [
"openssl-sys",
"opentelemetry",
"opentelemetry_sdk",
"os_info",
"predicates",
"pretty_assertions",
"rand 0.9.2",
@@ -1960,6 +1996,7 @@ dependencies = [
"codex-app-server-protocol",
"codex-apply-patch",
"codex-arg0",
"codex-client",
"codex-cloud-requirements",
"codex-core",
"codex-feedback",
@@ -2200,10 +2237,10 @@ version = "0.0.0"
dependencies = [
"anyhow",
"codex-arg0",
"codex-client",
"codex-core",
"codex-protocol",
"codex-shell-command",
"codex-terminal",
"codex-utils-cli",
"codex-utils-json-to-toml",
"core_test_support",
@@ -5826,8 +5863,10 @@ name = "mcp_test_support"
version = "0.0.0"
dependencies = [
"anyhow",
"codex-client",
"codex-core",
"codex-mcp-server",
"codex-terminal",
"codex-utils-cargo-bin",
"core_test_support",
"os_info",
+2
View File
@@ -10,6 +10,7 @@ members = [
"debug-client",
"apply-patch",
"arg0",
"auth",
"feedback",
"codex-backend-openapi-models",
"cloud-requirements",
@@ -97,6 +98,7 @@ codex-app-server-test-client = { path = "app-server-test-client" }
codex-apply-patch = { path = "apply-patch" }
codex-arg0 = { path = "arg0" }
codex-async-utils = { path = "async-utils" }
codex-auth = { path = "auth" }
codex-backend-client = { path = "backend-client" }
codex-chatgpt = { path = "chatgpt" }
codex-cli = { path = "cli" }
+1
View File
@@ -30,6 +30,7 @@ axum = { workspace = true, default-features = false, features = [
"ws",
] }
codex-arg0 = { workspace = true }
codex-client = { workspace = true }
codex-cloud-requirements = { workspace = true }
codex-core = { workspace = true }
codex-exec-server = { workspace = true }
@@ -176,6 +176,7 @@ use codex_app_server_protocol::build_turns_from_rollout_items;
use codex_arg0::Arg0DispatchPaths;
use codex_backend_client::Client as BackendClient;
use codex_chatgpt::connectors;
use codex_client::set_default_client_residency_requirement;
use codex_cloud_requirements::cloud_requirements_loader;
use codex_core::AuthManager;
use codex_core::CodexAuth;
@@ -201,7 +202,6 @@ use codex_core::config::types::McpServerTransportConfig;
use codex_core::config_loader::CloudRequirementsLoadError;
use codex_core::config_loader::CloudRequirementsLoadErrorCode;
use codex_core::config_loader::CloudRequirementsLoader;
use codex_core::default_client::set_default_client_residency_requirement;
use codex_core::error::CodexErr;
use codex_core::error::Result as CodexResult;
use codex_core::exec::ExecExpiration;
+5 -5
View File
@@ -47,6 +47,11 @@ use codex_app_server_protocol::ServerNotification;
use codex_app_server_protocol::ServerRequestPayload;
use codex_app_server_protocol::experimental_required_message;
use codex_arg0::Arg0DispatchPaths;
use codex_client::SetOriginatorError;
use codex_client::USER_AGENT_SUFFIX;
use codex_client::get_codex_user_agent;
use codex_client::set_default_client_residency_requirement;
use codex_client::set_default_originator;
use codex_core::AnalyticsEventsClient;
use codex_core::AuthManager;
use codex_core::ThreadManager;
@@ -57,11 +62,6 @@ use codex_core::auth::ExternalAuthTokens;
use codex_core::config::Config;
use codex_core::config_loader::CloudRequirementsLoader;
use codex_core::config_loader::LoaderOverrides;
use codex_core::default_client::SetOriginatorError;
use codex_core::default_client::USER_AGENT_SUFFIX;
use codex_core::default_client::get_codex_user_agent;
use codex_core::default_client::set_default_client_residency_requirement;
use codex_core::default_client::set_default_originator;
use codex_core::models_manager::collaboration_mode_presets::CollaborationModesConfig;
use codex_feedback::CodexFeedback;
use codex_protocol::ThreadId;
@@ -12,6 +12,7 @@ anyhow = { workspace = true }
base64 = { workspace = true }
chrono = { workspace = true }
codex-app-server-protocol = { workspace = true }
codex-client = { workspace = true }
codex-core = { workspace = true }
codex-protocol = { workspace = true }
codex-utils-cargo-bin = { workspace = true }
@@ -77,7 +77,7 @@ use codex_app_server_protocol::TurnInterruptParams;
use codex_app_server_protocol::TurnStartParams;
use codex_app_server_protocol::TurnSteerParams;
use codex_app_server_protocol::WindowsSandboxSetupStartParams;
use codex_core::default_client::CODEX_INTERNAL_ORIGINATOR_OVERRIDE_ENV_VAR;
use codex_client::CODEX_INTERNAL_ORIGINATOR_OVERRIDE_ENV_VAR;
use tokio::process::Command;
pub struct McpProcess {
+7
View File
@@ -0,0 +1,7 @@
load("//:defs.bzl", "codex_rust_crate")
codex_rust_crate(
name = "auth",
crate_name = "codex_auth",
crate_srcs = glob(["*.rs"]),
)
+39
View File
@@ -0,0 +1,39 @@
[package]
edition.workspace = true
license.workspace = true
name = "codex-auth"
version.workspace = true
[lib]
doctest = false
name = "codex_auth"
path = "lib.rs"
[lints]
workspace = true
[dependencies]
async-trait = { workspace = true }
base64 = { workspace = true }
chrono = { workspace = true, features = ["serde"] }
codex-app-server-protocol = { workspace = true }
codex-client = { workspace = true }
codex-keyring-store = { workspace = true }
codex-otel = { workspace = true }
codex-protocol = { workspace = true }
once_cell = { workspace = true }
reqwest = { workspace = true }
schemars = { workspace = true }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
sha2 = { workspace = true }
thiserror = { workspace = true }
tracing = { workspace = true }
[dev-dependencies]
anyhow = { workspace = true }
keyring = { workspace = true }
pretty_assertions = { workspace = true }
serial_test = { workspace = true }
tempfile = { workspace = true }
tokio = { workspace = true, features = ["macros", "rt-multi-thread"] }
@@ -1,5 +1,3 @@
mod storage;
use async_trait::async_trait;
use chrono::Utc;
use reqwest::StatusCode;
@@ -19,13 +17,12 @@ use codex_app_server_protocol::AuthMode as ApiAuthMode;
use codex_otel::TelemetryAuthMode;
use codex_protocol::config_types::ForcedLoginMethod;
pub use crate::auth::storage::AuthCredentialsStoreMode;
pub use crate::auth::storage::AuthDotJson;
use crate::auth::storage::AuthStorageBackend;
use crate::auth::storage::create_auth_storage;
use crate::config::Config;
use crate::error::RefreshTokenFailedError;
use crate::error::RefreshTokenFailedReason;
pub use crate::storage::AuthCredentialsStoreMode;
pub use crate::storage::AuthDotJson;
use crate::storage::AuthStorageBackend;
use crate::storage::create_auth_storage;
use crate::token_data::KnownPlan as InternalKnownPlan;
use crate::token_data::PlanType as InternalPlanType;
use crate::token_data::TokenData;
@@ -161,14 +158,14 @@ impl CodexAuth {
codex_home: &Path,
auth_dot_json: AuthDotJson,
auth_credentials_store_mode: AuthCredentialsStoreMode,
client: CodexHttpClient,
) -> std::io::Result<Self> {
let auth_mode = auth_dot_json.resolved_mode();
let client = codex_client::create_client();
if auth_mode == ApiAuthMode::ApiKey {
let Some(api_key) = auth_dot_json.openai_api_key.as_deref() else {
return Err(std::io::Error::other("API key auth is missing a key."));
};
return Ok(CodexAuth::from_api_key_with_client(api_key, client));
return Ok(CodexAuth::from_api_key(api_key));
}
let storage_mode = auth_dot_json.storage_mode(auth_credentials_store_mode);
@@ -189,7 +186,6 @@ impl CodexAuth {
}
}
/// Loads the available auth information from auth storage.
pub fn from_auth_storage(
codex_home: &Path,
auth_credentials_store_mode: AuthCredentialsStoreMode,
@@ -335,7 +331,7 @@ impl CodexAuth {
last_refresh: Some(Utc::now()),
};
let client = crate::default_client::create_client();
let client = codex_client::create_client();
let state = ChatgptAuthState {
auth_dot_json: Arc::new(Mutex::new(Some(auth_dot_json))),
client,
@@ -344,15 +340,11 @@ impl CodexAuth {
Self::Chatgpt(ChatgptAuth { state, storage })
}
fn from_api_key_with_client(api_key: &str, _client: CodexHttpClient) -> Self {
pub fn from_api_key(api_key: &str) -> Self {
Self::ApiKey(ApiKeyAuth {
api_key: api_key.to_owned(),
})
}
pub fn from_api_key(api_key: &str) -> Self {
Self::from_api_key_with_client(api_key, crate::default_client::create_client())
}
}
impl ChatgptAuth {
@@ -458,11 +450,19 @@ pub fn load_auth_dot_json(
storage.load()
}
pub fn enforce_login_restrictions(config: &Config) -> std::io::Result<()> {
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct AuthConfig {
pub codex_home: PathBuf,
pub auth_credentials_store_mode: AuthCredentialsStoreMode,
pub forced_login_method: Option<ForcedLoginMethod>,
pub forced_chatgpt_workspace_id: Option<String>,
}
pub fn enforce_login_restrictions(config: &AuthConfig) -> std::io::Result<()> {
let Some(auth) = load_auth(
&config.codex_home,
/*enable_codex_api_key_env*/ true,
config.cli_auth_credentials_store_mode,
config.auth_credentials_store_mode,
)?
else {
return Ok(());
@@ -486,7 +486,7 @@ pub fn enforce_login_restrictions(config: &Config) -> std::io::Result<()> {
return logout_with_message(
&config.codex_home,
message,
config.cli_auth_credentials_store_mode,
config.auth_credentials_store_mode,
);
}
}
@@ -504,7 +504,7 @@ pub fn enforce_login_restrictions(config: &Config) -> std::io::Result<()> {
format!(
"Failed to load ChatGPT credentials while enforcing workspace restrictions: {err}. Logging out."
),
config.cli_auth_credentials_store_mode,
config.auth_credentials_store_mode,
);
}
};
@@ -523,7 +523,7 @@ pub fn enforce_login_restrictions(config: &Config) -> std::io::Result<()> {
return logout_with_message(
&config.codex_home,
message,
config.cli_auth_credentials_store_mode,
config.auth_credentials_store_mode,
);
}
}
@@ -564,17 +564,12 @@ fn load_auth(
auth_credentials_store_mode: AuthCredentialsStoreMode,
) -> std::io::Result<Option<CodexAuth>> {
let build_auth = |auth_dot_json: AuthDotJson, storage_mode| {
let client = crate::default_client::create_client();
CodexAuth::from_auth_dot_json(codex_home, auth_dot_json, storage_mode, client)
CodexAuth::from_auth_dot_json(codex_home, auth_dot_json, storage_mode)
};
// API key via env var takes precedence over any other auth method.
if enable_codex_api_key_env && let Some(api_key) = read_codex_api_key_from_env() {
let client = crate::default_client::create_client();
return Ok(Some(CodexAuth::from_api_key_with_client(
api_key.as_str(),
client,
)));
return Ok(Some(CodexAuth::from_api_key(api_key.as_str())));
}
// External ChatGPT auth tokens live in the in-memory (ephemeral) store. Always check this
@@ -1077,7 +1072,7 @@ impl AuthManager {
}
/// Create an AuthManager with a specific CodexAuth, for testing only.
pub(crate) fn from_auth_for_testing(auth: CodexAuth) -> Arc<Self> {
pub fn from_auth_for_testing(auth: CodexAuth) -> Arc<Self> {
let cached = CachedAuth {
auth: Some(auth),
external_refresher: None,
@@ -1093,10 +1088,7 @@ impl AuthManager {
}
/// Create an AuthManager with a specific CodexAuth and codex home, for testing only.
pub(crate) fn from_auth_for_testing_with_home(
auth: CodexAuth,
codex_home: PathBuf,
) -> Arc<Self> {
pub fn from_auth_for_testing_with_home(auth: CodexAuth, codex_home: PathBuf) -> Arc<Self> {
let cached = CachedAuth {
auth: Some(auth),
external_refresher: None,
@@ -1,8 +1,6 @@
use super::*;
use crate::auth::storage::FileAuthStorage;
use crate::auth::storage::get_auth_file;
use crate::config::Config;
use crate::config::ConfigBuilder;
use crate::storage::FileAuthStorage;
use crate::storage::get_auth_file;
use crate::token_data::IdTokenInfo;
use crate::token_data::KnownPlan as InternalKnownPlan;
use crate::token_data::PlanType as InternalPlanType;
@@ -260,15 +258,13 @@ async fn build_config(
codex_home: &Path,
forced_login_method: Option<ForcedLoginMethod>,
forced_chatgpt_workspace_id: Option<String>,
) -> Config {
let mut config = ConfigBuilder::default()
.codex_home(codex_home.to_path_buf())
.build()
.await
.expect("config should load");
config.forced_login_method = forced_login_method;
config.forced_chatgpt_workspace_id = forced_chatgpt_workspace_id;
config
) -> AuthConfig {
AuthConfig {
codex_home: codex_home.to_path_buf(),
auth_credentials_store_mode: AuthCredentialsStoreMode::File,
forced_login_method,
forced_chatgpt_workspace_id,
}
}
/// Use sparingly.
+25
View File
@@ -0,0 +1,25 @@
use thiserror::Error;
#[derive(Debug, Clone, PartialEq, Eq, Error)]
#[error("{message}")]
pub struct RefreshTokenFailedError {
pub reason: RefreshTokenFailedReason,
pub message: String,
}
impl RefreshTokenFailedError {
pub fn new(reason: RefreshTokenFailedReason, message: impl Into<String>) -> Self {
Self {
reason,
message: message.into(),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RefreshTokenFailedReason {
Expired,
Exhausted,
Revoked,
Other,
}
+10
View File
@@ -0,0 +1,10 @@
pub mod error;
mod storage;
pub mod token_data;
mod util;
mod auth;
pub use auth::*;
pub use error::RefreshTokenFailedError;
pub use error::RefreshTokenFailedReason;
@@ -27,7 +27,7 @@ pub struct IdTokenInfo {
/// The ChatGPT subscription plan type
/// (e.g., "free", "plus", "pro", "business", "enterprise", "edu").
/// (Note: values may vary by backend.)
pub(crate) chatgpt_plan_type: Option<PlanType>,
pub chatgpt_plan_type: Option<PlanType>,
/// ChatGPT user identifier associated with the token, if present.
pub chatgpt_user_id: Option<String>,
/// Organization/workspace identifier associated with the token, if present.
@@ -55,13 +55,13 @@ impl IdTokenInfo {
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(untagged)]
pub(crate) enum PlanType {
pub enum PlanType {
Known(KnownPlan),
Unknown(String),
}
impl PlanType {
pub(crate) fn from_raw_value(raw: &str) -> Self {
pub fn from_raw_value(raw: &str) -> Self {
match raw.to_ascii_lowercase().as_str() {
"free" => Self::Known(KnownPlan::Free),
"go" => Self::Known(KnownPlan::Go),
@@ -78,7 +78,7 @@ impl PlanType {
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub(crate) enum KnownPlan {
pub enum KnownPlan {
Free,
Go,
Plus,
+16
View File
@@ -0,0 +1,16 @@
use tracing::debug;
pub(crate) fn try_parse_error_message(text: &str) -> String {
debug!("Parsing server error response: {}", text);
let json = serde_json::from_str::<serde_json::Value>(text).unwrap_or_default();
if let Some(error) = json.get("error")
&& let Some(message) = error.get("message")
&& let Some(message_str) = message.as_str()
{
return message_str.to_string();
}
if text.is_empty() {
return "Unknown error".to_string();
}
text.to_string()
}
+1 -1
View File
@@ -5,8 +5,8 @@ use crate::types::RateLimitStatusPayload;
use crate::types::TurnAttemptsSiblingTurnsResponse;
use anyhow::Result;
use codex_client::build_reqwest_client_with_custom_ca;
use codex_client::get_codex_user_agent;
use codex_core::auth::CodexAuth;
use codex_core::default_client::get_codex_user_agent;
use codex_protocol::account::PlanType as AccountPlanType;
use codex_protocol::protocol::CreditsSnapshot;
use codex_protocol::protocol::RateLimitSnapshot;
+1
View File
@@ -10,6 +10,7 @@ workspace = true
[dependencies]
anyhow = { workspace = true }
clap = { workspace = true, features = ["derive"] }
codex-client = { workspace = true }
codex-connectors = { workspace = true }
codex-core = { workspace = true }
codex-utils-cli = { workspace = true }
+1 -1
View File
@@ -1,5 +1,5 @@
use codex_client::create_client;
use codex_core::config::Config;
use codex_core::default_client::create_client;
use crate::chatgpt_token::get_chatgpt_token_data;
use crate::chatgpt_token::init_chatgpt_token_from_auth;
+3 -2
View File
@@ -9,6 +9,7 @@ pub use cli::Cli;
use anyhow::anyhow;
use chrono::Utc;
use codex_client::get_codex_user_agent;
use codex_cloud_tasks_client::TaskStatus;
use owo_colors::OwoColorize;
use owo_colors::Stream;
@@ -54,7 +55,7 @@ async fn init_backend(user_agent_suffix: &str) -> anyhow::Result<BackendContext>
});
}
let ua = codex_core::default_client::get_codex_user_agent();
let ua = get_codex_user_agent();
let mut http = codex_cloud_tasks_client::HttpClient::new(base_url.clone())?.with_user_agent(ua);
let style = if base_url.contains("/backend-api") {
"wham"
@@ -800,7 +801,7 @@ pub async fn run_main(cli: Cli, _codex_linux_sandbox_exe: Option<PathBuf>) -> an
append_error_log(format!(
"startup: wham_force_internal={} ua={}",
force_internal,
codex_core::default_client::get_codex_user_agent()
get_codex_user_agent()
));
// Non-blocking initial load so the in-box spinner can animate
app.status = "Loading tasks…".to_string();
+4 -2
View File
@@ -2,13 +2,15 @@ use base64::Engine as _;
use chrono::DateTime;
use chrono::Local;
use chrono::Utc;
use codex_client::USER_AGENT_SUFFIX;
use codex_client::get_codex_user_agent;
use reqwest::header::HeaderMap;
use codex_core::config::Config;
use codex_login::AuthManager;
pub fn set_user_agent_suffix(suffix: &str) {
if let Ok(mut guard) = codex_core::default_client::USER_AGENT_SUFFIX.lock() {
if let Ok(mut guard) = USER_AGENT_SUFFIX.lock() {
guard.replace(suffix.to_string());
}
}
@@ -78,7 +80,7 @@ pub async fn build_chatgpt_headers() -> HeaderMap {
use reqwest::header::USER_AGENT;
set_user_agent_suffix("codex_cloud_tasks_tui");
let ua = codex_core::default_client::get_codex_user_agent();
let ua = get_codex_user_agent();
let mut headers = HeaderMap::new();
headers.insert(
USER_AGENT,
+7 -2
View File
@@ -7,10 +7,14 @@ version.workspace = true
[dependencies]
async-trait = { workspace = true }
bytes = { workspace = true }
codex-config = { workspace = true }
codex-terminal = { workspace = true }
codex-utils-rustls-provider = { workspace = true }
eventsource-stream = { workspace = true }
futures = { workspace = true }
http = { workspace = true }
opentelemetry = { workspace = true }
os_info = { workspace = true }
rand = { workspace = true }
reqwest = { workspace = true, features = ["json", "stream"] }
rustls = { workspace = true }
@@ -19,10 +23,9 @@ rustls-pki-types = { workspace = true }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
thiserror = { workspace = true }
tokio = { workspace = true, features = ["macros", "rt", "time", "sync"] }
tokio = { workspace = true, features = ["macros", "rt", "rt-multi-thread", "sync", "time"] }
tracing = { workspace = true }
tracing-opentelemetry = { workspace = true }
codex-utils-rustls-provider = { workspace = true }
zstd = { workspace = true }
[lints]
@@ -32,5 +35,7 @@ workspace = true
codex-utils-cargo-bin = { workspace = true }
opentelemetry_sdk = { workspace = true }
pretty_assertions = { workspace = true }
regex-lite = { workspace = true }
tempfile = { workspace = true }
tracing-subscriber = { workspace = true }
wiremock = { workspace = true }
@@ -1,9 +1,7 @@
use crate::config_loader::ResidencyRequirement;
use crate::spawn::CODEX_SANDBOX_ENV_VAR;
use codex_client::BuildCustomCaTransportError;
use codex_client::CodexHttpClient;
pub use codex_client::CodexRequestBuilder;
use codex_client::build_reqwest_client_with_custom_ca;
use crate::custom_ca::BuildCustomCaTransportError;
use crate::custom_ca::build_reqwest_client_with_custom_ca;
use crate::default_client::CodexHttpClient;
use codex_config::ResidencyRequirement;
use codex_terminal::user_agent;
use reqwest::header::HeaderMap;
use reqwest::header::HeaderValue;
@@ -152,7 +150,7 @@ pub fn get_codex_user_agent() -> String {
/// Invalid characters are replaced with an underscore.
///
/// If the user agent fails to parse, it falls back to fallback and then to ORIGINATOR.
fn sanitize_user_agent(candidate: String, fallback: &str) -> String {
pub fn sanitize_user_agent(candidate: String, fallback: &str) -> String {
if HeaderValue::from_str(candidate.as_str()).is_ok() {
return candidate;
}
@@ -232,9 +230,9 @@ pub fn default_headers() -> HeaderMap {
}
fn is_sandboxed() -> bool {
std::env::var(CODEX_SANDBOX_ENV_VAR).as_deref() == Ok("seatbelt")
std::env::var("CODEX_SANDBOX").as_deref() == Ok("seatbelt")
}
#[cfg(test)]
#[path = "default_client_tests.rs"]
#[path = "create_client_tests.rs"]
mod tests;
@@ -1,7 +1,18 @@
use super::*;
use core_test_support::skip_if_no_network;
use codex_config::ResidencyRequirement;
use pretty_assertions::assert_eq;
macro_rules! skip_if_no_network {
() => {
if std::env::var("CODEX_SANDBOX_NETWORK_DISABLED").is_ok() {
println!(
"Skipping test because it cannot execute when network is disabled in a Codex sandbox."
);
return;
}
};
}
#[test]
fn test_get_codex_user_agent() {
let user_agent = get_codex_user_agent();
+18
View File
@@ -1,3 +1,4 @@
mod create_client;
mod custom_ca;
mod default_client;
mod error;
@@ -7,6 +8,23 @@ mod sse;
mod telemetry;
mod transport;
pub use crate::create_client::CODEX_INTERNAL_ORIGINATOR_OVERRIDE_ENV_VAR;
pub use crate::create_client::DEFAULT_ORIGINATOR;
pub use crate::create_client::Originator;
pub use crate::create_client::RESIDENCY_HEADER_NAME;
pub use crate::create_client::SetOriginatorError;
pub use crate::create_client::USER_AGENT_SUFFIX;
pub use crate::create_client::build_reqwest_client;
pub use crate::create_client::create_client;
pub use crate::create_client::default_headers;
pub use crate::create_client::get_codex_user_agent;
pub use crate::create_client::is_first_party_chat_originator;
pub use crate::create_client::is_first_party_originator;
pub use crate::create_client::originator;
pub use crate::create_client::sanitize_user_agent;
pub use crate::create_client::set_default_client_residency_requirement;
pub use crate::create_client::set_default_originator;
pub use crate::create_client::try_build_reqwest_client;
pub use crate::custom_ca::BuildCustomCaTransportError;
/// Test-only subprocess hook for custom CA coverage.
///
+1 -1
View File
@@ -31,6 +31,7 @@ codex-api = { workspace = true }
codex-app-server-protocol = { workspace = true }
codex-apply-patch = { workspace = true }
codex-async-utils = { workspace = true }
codex-auth = { workspace = true }
codex-client = { workspace = true }
codex-connectors = { workspace = true }
codex-config = { workspace = true }
@@ -74,7 +75,6 @@ keyring = { workspace = true, features = ["crypto-rust"] }
libc = { workspace = true }
notify = { workspace = true }
once_cell = { workspace = true }
os_info = { workspace = true }
rand = { workspace = true }
regex-lite = { workspace = true }
reqwest = { workspace = true, features = ["json", "stream"] }
+5 -4
View File
@@ -1,9 +1,10 @@
use crate::AuthManager;
use crate::config::Config;
use crate::default_client::create_client;
use crate::git_info::collect_git_info;
use crate::git_info::get_git_repo_root;
use crate::plugins::PluginTelemetryMetadata;
use codex_client::create_client;
use codex_client::originator;
use codex_protocol::protocol::SkillScope;
use serde::Serialize;
use sha1::Digest;
@@ -525,7 +526,7 @@ async fn send_track_skill_invocations(auth_manager: &AuthManager, job: TrackSkil
thread_id: Some(tracking.thread_id.clone()),
invoke_type: Some(invocation.invocation_type),
model_slug: Some(tracking.model_slug.clone()),
product_client_id: Some(crate::default_client::originator().value),
product_client_id: Some(originator().value),
repo_url,
skill_scope: Some(skill_scope.to_string()),
},
@@ -629,7 +630,7 @@ fn codex_app_metadata(tracking: &TrackEventsContext, app: AppInvocation) -> Code
thread_id: Some(tracking.thread_id.clone()),
turn_id: Some(tracking.turn_id.clone()),
app_name: app.app_name,
product_client_id: Some(crate::default_client::originator().value),
product_client_id: Some(originator().value),
invoke_type: app.invocation_type,
model_slug: Some(tracking.model_slug.clone()),
}
@@ -654,7 +655,7 @@ fn codex_plugin_metadata(plugin: PluginTelemetryMetadata) -> CodexPluginMetadata
.map(|connector_id| connector_id.0)
.collect()
}),
product_client_id: Some(crate::default_client::originator().value),
product_client_id: Some(originator().value),
}
}
+4 -4
View File
@@ -109,7 +109,7 @@ fn app_mentioned_event_serializes_expected_shape() {
"thread_id": "thread-1",
"turn_id": "turn-1",
"app_name": "Calendar",
"product_client_id": crate::default_client::originator().value,
"product_client_id": originator().value,
"invoke_type": "explicit",
"model_slug": "gpt-5"
}
@@ -147,7 +147,7 @@ fn app_used_event_serializes_expected_shape() {
"thread_id": "thread-2",
"turn_id": "turn-2",
"app_name": "Google Drive",
"product_client_id": crate::default_client::originator().value,
"product_client_id": originator().value,
"invoke_type": "implicit",
"model_slug": "gpt-5"
}
@@ -210,7 +210,7 @@ fn plugin_used_event_serializes_expected_shape() {
"has_skills": true,
"mcp_server_count": 2,
"connector_ids": ["calendar", "drive"],
"product_client_id": crate::default_client::originator().value,
"product_client_id": originator().value,
"thread_id": "thread-3",
"turn_id": "turn-3",
"model_slug": "gpt-5"
@@ -239,7 +239,7 @@ fn plugin_management_event_serializes_expected_shape() {
"has_skills": true,
"mcp_server_count": 2,
"connector_ids": ["calendar", "drive"],
"product_client_id": crate::default_client::originator().value
"product_client_id": originator().value
}
})
);
+1 -1
View File
@@ -8,8 +8,8 @@ use tracing::warn;
use crate::codex::Session;
use crate::codex::TurnContext;
use crate::compact::content_items_to_text;
use crate::default_client::build_reqwest_client;
use crate::event_mapping::is_contextual_user_message_content;
use codex_client::build_reqwest_client;
use codex_protocol::models::MessagePhase;
use codex_protocol::models::ResponseItem;
+3 -2
View File
@@ -97,7 +97,6 @@ use crate::auth::RefreshTokenError;
use crate::client_common::Prompt;
use crate::client_common::ResponseEvent;
use crate::client_common::ResponseStream;
use crate::default_client::build_reqwest_client;
use crate::error::CodexErr;
use crate::error::Result;
use crate::flags::CODEX_RS_SSE_FIXTURE;
@@ -111,6 +110,8 @@ use crate::tools::spec::create_tools_json_for_responses_api;
use crate::util::FeedbackRequestTags;
use crate::util::emit_feedback_auth_recovery_tags;
use crate::util::emit_feedback_request_tags_with_auth_env;
use codex_client::build_reqwest_client;
use codex_client::default_headers;
pub const OPENAI_BETA_HEADER: &str = "OpenAI-Beta";
pub const X_CODEX_TURN_STATE_HEADER: &str = "x-codex-turn-state";
@@ -568,7 +569,7 @@ impl ModelClient {
websocket_connect_timeout,
ApiWebSocketResponsesClient::new(api_provider, api_auth).connect(
headers,
crate::default_client::default_headers(),
default_headers(),
turn_state,
Some(websocket_telemetry),
),
+2 -1
View File
@@ -58,6 +58,7 @@ use chrono::Local;
use chrono::Utc;
use codex_app_server_protocol::McpServerElicitationRequest;
use codex_app_server_protocol::McpServerElicitationRequestParams;
use codex_client::originator;
use codex_exec_server::Environment;
use codex_hooks::HookEvent;
use codex_hooks::HookEventAfterAgent;
@@ -1580,7 +1581,7 @@ impl Session {
let auth_mode = auth.map(CodexAuth::auth_mode).map(TelemetryAuthMode::from);
let account_id = auth.and_then(CodexAuth::get_account_id);
let account_email = auth.and_then(CodexAuth::get_account_email);
let originator = crate::default_client::originator().value;
let originator = originator().value;
let terminal_type = user_agent();
let session_model = session_configuration.collaboration_mode.model().to_string();
let auth_env_telemetry = collect_auth_env_telemetry(
+3 -3
View File
@@ -30,9 +30,6 @@ use crate::config::types::AppToolApproval;
use crate::config::types::AppsConfigToml;
use crate::config::types::ToolSuggestDiscoverableType;
use crate::config_loader::AppsRequirementsToml;
use crate::default_client::create_client;
use crate::default_client::is_first_party_chat_originator;
use crate::default_client::originator;
use crate::features::Feature;
use crate::mcp::CODEX_APPS_MCP_SERVER_NAME;
use crate::mcp::McpManager;
@@ -47,6 +44,9 @@ use crate::plugins::list_tool_suggest_discoverable_plugins;
use crate::token_data::TokenData;
use crate::tools::discoverable::DiscoverablePluginInfo;
use crate::tools::discoverable::DiscoverableTool;
use codex_client::create_client;
use codex_client::is_first_party_chat_originator;
use codex_client::originator;
pub use codex_connectors::CONNECTORS_CACHE_TTL;
const CONNECTORS_READY_TIMEOUT_ON_EMPTY_TOOLS: Duration = Duration::from_secs(30);
+2 -24
View File
@@ -9,6 +9,8 @@ use chrono::Datelike;
use chrono::Local;
use chrono::Utc;
use codex_async_utils::CancelErr;
pub use codex_auth::RefreshTokenFailedError;
pub use codex_auth::RefreshTokenFailedReason;
use codex_protocol::ThreadId;
use codex_protocol::protocol::CodexErrorInfo;
use codex_protocol::protocol::ErrorEvent;
@@ -261,30 +263,6 @@ impl std::fmt::Display for ResponseStreamFailed {
}
}
#[derive(Debug, Clone, PartialEq, Eq, Error)]
#[error("{message}")]
pub struct RefreshTokenFailedError {
pub reason: RefreshTokenFailedReason,
pub message: String,
}
impl RefreshTokenFailedError {
pub fn new(reason: RefreshTokenFailedReason, message: impl Into<String>) -> Self {
Self {
reason,
message: message.into(),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RefreshTokenFailedReason {
Expired,
Exhausted,
Revoked,
Other,
}
#[derive(Debug)]
pub struct UnexpectedResponseError {
pub status: StatusCode,
+2 -3
View File
@@ -10,7 +10,7 @@ pub mod api_bridge;
mod apply_patch;
mod apps;
mod arc_monitor;
pub mod auth;
pub use codex_auth as auth;
mod auth_env_telemetry;
mod client;
mod client_common;
@@ -76,7 +76,7 @@ mod shell_detect;
mod stream_events_utils;
pub mod test_support;
mod text_encoding;
pub mod token_data;
pub use codex_auth::token_data;
mod truncate;
mod unified_exec;
pub mod windows_sandbox;
@@ -110,7 +110,6 @@ pub type CodexConversation = CodexThread;
pub use analytics_client::AnalyticsEventsClient;
pub use auth::AuthManager;
pub use auth::CodexAuth;
pub mod default_client;
pub mod project_doc;
mod rollout;
pub(crate) mod safety;
+2 -2
View File
@@ -22,11 +22,11 @@ use crate::config::edit::ConfigEditsBuilder;
use crate::config::load_global_mcp_servers;
use crate::config::types::McpServerConfig;
use crate::config::types::McpServerTransportConfig;
use crate::default_client::is_first_party_originator;
use crate::default_client::originator;
use crate::features::Feature;
use crate::skills::SkillMetadata;
use crate::skills::model::SkillToolDependency;
use codex_client::is_first_party_originator;
use codex_client::originator;
const SKILL_MCP_DEPENDENCY_PROMPT_ID: &str = "skill_mcp_dependency_install";
const MCP_DEPENDENCY_OPTION_INSTALL: &str = "Install";
+1 -1
View File
@@ -7,7 +7,6 @@ use crate::auth::CodexAuth;
use crate::auth_env_telemetry::AuthEnvTelemetry;
use crate::auth_env_telemetry::collect_auth_env_telemetry;
use crate::config::Config;
use crate::default_client::build_reqwest_client;
use crate::error::CodexErr;
use crate::error::Result as CoreResult;
use crate::model_provider_info::ModelProviderInfo;
@@ -22,6 +21,7 @@ use codex_api::ModelsClient;
use codex_api::RequestTelemetry;
use codex_api::ReqwestTransport;
use codex_api::TransportError;
use codex_client::build_reqwest_client;
use codex_otel::TelemetryAuthMode;
use codex_protocol::config_types::CollaborationModeMask;
use codex_protocol::openai_models::ModelInfo;
+1 -1
View File
@@ -1,8 +1,8 @@
use crate::config::Config;
use crate::config::types::OtelExporterKind as Kind;
use crate::config::types::OtelHttpProtocol as Protocol;
use crate::default_client::originator;
use crate::features::Feature;
use codex_client::originator;
use codex_otel::OtelProvider;
use codex_otel::config::OtelExporter;
use codex_otel::config::OtelHttpProtocol;
+1 -1
View File
@@ -1,4 +1,4 @@
use crate::default_client::build_reqwest_client;
use codex_client::build_reqwest_client;
use reqwest::Client;
use serde::Deserialize;
use std::fs;
+1 -1
View File
@@ -1,6 +1,6 @@
use crate::auth::CodexAuth;
use crate::config::Config;
use crate::default_client::build_reqwest_client;
use codex_client::build_reqwest_client;
use serde::Deserialize;
use std::time::Duration;
use url::Url;
+1 -1
View File
@@ -4,7 +4,6 @@ use crate::auth::read_openai_api_key_from_env;
use crate::codex::Session;
use crate::config::RealtimeWsMode;
use crate::config::RealtimeWsVersion;
use crate::default_client::default_headers;
use crate::error::CodexErr;
use crate::error::Result as CodexResult;
use crate::realtime_context::build_realtime_startup_context;
@@ -22,6 +21,7 @@ use codex_api::RealtimeSessionMode;
use codex_api::RealtimeWebsocketClient;
use codex_api::endpoint::realtime_websocket::RealtimeWebsocketEvents;
use codex_api::endpoint::realtime_websocket::RealtimeWebsocketWriter;
use codex_client::default_headers;
use codex_protocol::protocol::CodexErrorInfo;
use codex_protocol::protocol::ConversationAudioParams;
use codex_protocol::protocol::ConversationStartParams;
+1 -1
View File
@@ -40,13 +40,13 @@ use super::metadata;
use super::policy::EventPersistenceMode;
use super::policy::is_persisted_response_item;
use crate::config::Config;
use crate::default_client::originator;
use crate::git_info::collect_git_info;
use crate::path_utils;
use crate::state_db;
use crate::state_db::StateDbHandle;
use crate::truncate::TruncationPolicy;
use crate::truncate::truncate_text;
use codex_client::originator;
use codex_protocol::protocol::EventMsg;
use codex_protocol::protocol::InitialHistory;
use codex_protocol::protocol::ResumedHistory;
+1 -1
View File
@@ -8,7 +8,7 @@ use std::time::Duration;
use crate::auth::CodexAuth;
use crate::config::Config;
use crate::default_client::build_reqwest_client;
use codex_client::build_reqwest_client;
const REMOTE_SKILLS_API_TIMEOUT: Duration = Duration::from_secs(30);
-15
View File
@@ -217,21 +217,6 @@ pub(crate) fn error_or_panic(message: impl std::string::ToString) {
}
}
pub(crate) fn try_parse_error_message(text: &str) -> String {
debug!("Parsing server error response: {}", text);
let json = serde_json::from_str::<serde_json::Value>(text).unwrap_or_default();
if let Some(error) = json.get("error")
&& let Some(message) = error.get("message")
&& let Some(message_str) = message.as_str()
{
return message_str.to_string();
}
if text.is_empty() {
return "Unknown error".to_string();
}
text.to_string()
}
pub fn resolve_path(base: &Path, path: &PathBuf) -> PathBuf {
if path.is_absolute() {
path.clone()
+1 -1
View File
@@ -3,11 +3,11 @@ use crate::config::ConfigToml;
use crate::config::edit::ConfigEditsBuilder;
use crate::config::profile::ConfigProfile;
use crate::config::types::WindowsSandboxModeToml;
use crate::default_client::originator;
use crate::features::Feature;
use crate::features::Features;
use crate::features::FeaturesToml;
use crate::protocol::SandboxPolicy;
use codex_client::originator;
use codex_otel::sanitize_metric_tag_value;
use codex_protocol::config_types::WindowsSandboxLevel;
use std::collections::BTreeMap;
+1 -1
View File
@@ -1,3 +1,4 @@
use codex_client::originator;
use codex_core::CodexAuth;
use codex_core::ModelClient;
use codex_core::ModelProviderInfo;
@@ -8,7 +9,6 @@ use codex_core::ThreadManager;
use codex_core::WireApi;
use codex_core::auth::AuthCredentialsStoreMode;
use codex_core::built_in_model_providers;
use codex_core::default_client::originator;
use codex_core::error::CodexErr;
use codex_core::features::Feature;
use codex_core::models_manager::collaboration_mode_presets::CollaborationModesConfig;
+2 -1
View File
@@ -6,6 +6,7 @@ use std::time::Duration;
use std::time::Instant;
use anyhow::Result;
use codex_client::originator;
use codex_core::CodexAuth;
use codex_core::features::Feature;
use codex_protocol::protocol::EventMsg;
@@ -394,7 +395,7 @@ async fn explicit_plugin_mentions_track_plugin_used_analytics() -> Result<()> {
);
assert_eq!(
event["event_params"]["product_client_id"],
serde_json::json!(codex_core::default_client::originator().value)
serde_json::json!(originator().value)
);
assert_eq!(event["event_params"]["model_slug"], "gpt-5");
assert!(event["event_params"]["thread_id"].as_str().is_some());
@@ -36,7 +36,7 @@ pub(crate) struct ExecServerFileSystem {
impl Default for ExecServerFileSystem {
fn default() -> Self {
Self {
file_system: Arc::new(Environment.get_filesystem()),
file_system: Arc::new(Environment::default().get_filesystem()),
}
}
}
+1
View File
@@ -21,6 +21,7 @@ clap = { workspace = true, features = ["derive"] }
codex-arg0 = { workspace = true }
codex-app-server-client = { workspace = true }
codex-app-server-protocol = { workspace = true }
codex-client = { workspace = true }
codex-cloud-requirements = { workspace = true }
codex-core = { workspace = true }
codex-feedback = { workspace = true }
+9 -3
View File
@@ -45,6 +45,7 @@ use codex_cloud_requirements::cloud_requirements_loader;
use codex_core::AuthManager;
use codex_core::LMSTUDIO_OSS_PROVIDER_ID;
use codex_core::OLLAMA_OSS_PROVIDER_ID;
use codex_core::auth::AuthConfig;
use codex_core::auth::enforce_login_restrictions;
use codex_core::check_execpolicy_for_warnings;
use codex_core::config::Config;
@@ -98,8 +99,8 @@ use uuid::Uuid;
use crate::cli::Command as ExecCommand;
use crate::event_processor::CodexStatus;
use crate::event_processor::EventProcessor;
use codex_core::default_client::set_default_client_residency_requirement;
use codex_core::default_client::set_default_originator;
use codex_client::set_default_client_residency_requirement;
use codex_client::set_default_originator;
use codex_core::find_thread_path_by_id_str;
use codex_core::find_thread_path_by_name_str;
@@ -381,7 +382,12 @@ 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(&config) {
if let Err(err) = enforce_login_restrictions(&AuthConfig {
codex_home: config.codex_home.clone(),
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(),
}) {
eprintln!("{err}");
std::process::exit(1);
}
+1 -1
View File
@@ -1,7 +1,7 @@
#![cfg(not(target_os = "windows"))]
#![allow(clippy::expect_used, clippy::unwrap_used)]
use codex_core::default_client::CODEX_INTERNAL_ORIGINATOR_OVERRIDE_ENV_VAR;
use codex_client::CODEX_INTERNAL_ORIGINATOR_OVERRIDE_ENV_VAR;
use core_test_support::responses;
use core_test_support::test_codex_exec::test_codex_exec;
use wiremock::matchers::header;
+1 -1
View File
@@ -29,10 +29,10 @@ use base64::Engine;
use chrono::Utc;
use codex_app_server_protocol::AuthMode;
use codex_client::build_reqwest_client_with_custom_ca;
use codex_client::originator;
use codex_core::auth::AuthCredentialsStoreMode;
use codex_core::auth::AuthDotJson;
use codex_core::auth::save_auth;
use codex_core::default_client::originator;
use codex_core::token_data::TokenData;
use codex_core::token_data::parse_chatgpt_jwt_claims;
use rand::RngCore;
+1 -1
View File
@@ -18,6 +18,7 @@ workspace = true
[dependencies]
anyhow = { workspace = true }
codex-arg0 = { workspace = true }
codex-client = { workspace = true }
codex-core = { workspace = true }
codex-protocol = { workspace = true }
codex-shell-command = { workspace = true }
@@ -40,7 +41,6 @@ tracing-subscriber = { workspace = true, features = ["env-filter", "fmt"] }
[dev-dependencies]
core_test_support = { workspace = true }
codex-terminal = { workspace = true }
mcp_test_support = { workspace = true }
os_info = { workspace = true }
pretty_assertions = { workspace = true }
+2 -2
View File
@@ -1,11 +1,11 @@
use std::collections::HashMap;
use codex_arg0::Arg0DispatchPaths;
use codex_client::USER_AGENT_SUFFIX;
use codex_client::get_codex_user_agent;
use codex_core::AuthManager;
use codex_core::ThreadManager;
use codex_core::config::Config;
use codex_core::default_client::USER_AGENT_SUFFIX;
use codex_core::default_client::get_codex_user_agent;
use codex_core::models_manager::collaboration_mode_presets::CollaborationModesConfig;
use codex_protocol::ThreadId;
use codex_protocol::protocol::SessionSource;
@@ -9,8 +9,10 @@ path = "lib.rs"
[dependencies]
anyhow = { workspace = true }
codex-client = { workspace = true }
codex-core = { workspace = true }
codex-mcp-server = { workspace = true }
codex-terminal = { workspace = true }
codex-utils-cargo-bin = { workspace = true }
rmcp = { workspace = true }
os_info = { workspace = true }
@@ -10,6 +10,7 @@ use tokio::process::ChildStdin;
use tokio::process::ChildStdout;
use anyhow::Context;
use codex_client::originator;
use codex_mcp_server::CodexToolCallParam;
use codex_terminal::user_agent;
@@ -151,7 +152,7 @@ impl McpProcess {
let initialized = self.read_jsonrpc_message().await?;
let os_info = os_info::get();
let build_version = env!("CARGO_PKG_VERSION");
let originator = codex_core::default_client::originator().value;
let originator = originator().value;
let user_agent = format!(
"{originator}/{build_version} ({} {}; {}) {} (elicitation test; 0.0.0)",
os_info.os_type(),
+2 -1
View File
@@ -40,6 +40,7 @@ use crate::update_action::UpdateAction;
use crate::version::CODEX_CLI_VERSION;
use codex_ansi_escape::ansi_escape_line;
use codex_app_server_protocol::ConfigLayerSource;
use codex_client::originator;
use codex_core::AuthManager;
use codex_core::CodexAuth;
use codex_core::ThreadManager;
@@ -2078,7 +2079,7 @@ impl App {
auth_ref.and_then(CodexAuth::get_account_id),
auth_ref.and_then(CodexAuth::get_account_email),
auth_mode,
codex_core::default_client::originator().value,
originator().value,
config.otel.log_user_prompt,
user_agent(),
SessionSource::Cli,
+8 -2
View File
@@ -7,12 +7,14 @@ use additional_dirs::add_dir_warning_message;
use app::App;
pub use app::AppExitInfo;
pub use app::ExitReason;
use codex_client::set_default_client_residency_requirement;
use codex_cloud_requirements::cloud_requirements_loader;
use codex_core::AuthManager;
use codex_core::CodexAuth;
use codex_core::INTERACTIVE_SESSION_SOURCES;
use codex_core::RolloutRecorder;
use codex_core::ThreadSortKey;
use codex_core::auth::AuthConfig;
use codex_core::auth::AuthMode;
use codex_core::auth::enforce_login_restrictions;
use codex_core::check_execpolicy_for_warnings;
@@ -26,7 +28,6 @@ use codex_core::config_loader::CloudRequirementsLoader;
use codex_core::config_loader::ConfigLoadError;
use codex_core::config_loader::LoaderOverrides;
use codex_core::config_loader::format_config_error_with_source;
use codex_core::default_client::set_default_client_residency_requirement;
use codex_core::find_thread_path_by_id_str;
use codex_core::find_thread_path_by_name_str;
use codex_core::format_exec_policy_error_with_source;
@@ -454,7 +455,12 @@ pub async fn run_main(
}
#[allow(clippy::print_stderr)]
if let Err(err) = enforce_login_restrictions(&config) {
if let Err(err) = enforce_login_restrictions(&AuthConfig {
codex_home: config.codex_home.clone(),
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(),
}) {
eprintln!("{err}");
std::process::exit(1);
}
+1 -1
View File
@@ -5,8 +5,8 @@ use crate::update_action::UpdateAction;
use chrono::DateTime;
use chrono::Duration;
use chrono::Utc;
use codex_client::create_client;
use codex_core::config::Config;
use codex_core::default_client::create_client;
use serde::Deserialize;
use serde::Serialize;
use std::path::Path;
+1 -1
View File
@@ -4,10 +4,10 @@ use crate::audio_device::preferred_input_config;
use crate::audio_device::select_configured_input_device_and_config;
use base64::Engine;
use codex_client::build_reqwest_client_with_custom_ca;
use codex_client::get_codex_user_agent;
use codex_core::auth::AuthCredentialsStoreMode;
use codex_core::config::Config;
use codex_core::config::find_codex_home;
use codex_core::default_client::get_codex_user_agent;
use codex_login::AuthMode;
use codex_login::CodexAuth;
use codex_protocol::protocol::ConversationAudioParams;
+2 -1
View File
@@ -60,6 +60,7 @@ use codex_app_server_protocol::SkillsListResponse;
use codex_app_server_protocol::ThreadRollbackResponse;
use codex_app_server_protocol::Turn;
use codex_app_server_protocol::TurnStatus;
use codex_client::originator;
use codex_core::config::Config;
use codex_core::config::ConfigBuilder;
use codex_core::config::ConfigOverrides;
@@ -2964,7 +2965,7 @@ impl App {
/*account_id*/ None,
bootstrap.account_email.clone(),
auth_mode,
codex_core::default_client::originator().value,
originator().value,
config.otel.log_user_prompt,
user_agent(),
SessionSource::Cli,
+8 -2
View File
@@ -20,7 +20,9 @@ use codex_app_server_protocol::Thread as AppServerThread;
use codex_app_server_protocol::ThreadListParams;
use codex_app_server_protocol::ThreadSortKey as AppServerThreadSortKey;
use codex_app_server_protocol::ThreadSourceKind;
use codex_client::set_default_client_residency_requirement;
use codex_cloud_requirements::cloud_requirements_loader_for_storage;
use codex_core::auth::AuthConfig;
use codex_core::auth::enforce_login_restrictions;
use codex_core::check_execpolicy_for_warnings;
use codex_core::config::Config;
@@ -33,7 +35,6 @@ use codex_core::config_loader::CloudRequirementsLoader;
use codex_core::config_loader::ConfigLoadError;
use codex_core::config_loader::LoaderOverrides;
use codex_core::config_loader::format_config_error_with_source;
use codex_core::default_client::set_default_client_residency_requirement;
use codex_core::format_exec_policy_error_with_source;
use codex_core::path_utils;
use codex_core::read_session_meta_line;
@@ -777,7 +778,12 @@ pub async fn run_main(
if matches!(app_server_target, AppServerTarget::Embedded) {
#[allow(clippy::print_stderr)]
if let Err(err) = enforce_login_restrictions(&config) {
if let Err(err) = enforce_login_restrictions(&AuthConfig {
codex_home: config.codex_home.clone(),
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(),
}) {
eprintln!("{err}");
std::process::exit(1);
}
+1 -1
View File
@@ -5,8 +5,8 @@ use crate::update_action::UpdateAction;
use chrono::DateTime;
use chrono::Duration;
use chrono::Utc;
use codex_client::create_client;
use codex_core::config::Config;
use codex_core::default_client::create_client;
use serde::Deserialize;
use serde::Serialize;
use std::path::Path;
+1 -1
View File
@@ -2,10 +2,10 @@ use crate::app_event::AppEvent;
use crate::app_event_sender::AppEventSender;
use base64::Engine;
use codex_client::build_reqwest_client_with_custom_ca;
use codex_client::get_codex_user_agent;
use codex_core::auth::AuthCredentialsStoreMode;
use codex_core::config::Config;
use codex_core::config::find_codex_home;
use codex_core::default_client::get_codex_user_agent;
use codex_login::AuthMode;
use codex_login::CodexAuth;
use codex_protocol::protocol::ConversationAudioParams;