mirror of
https://github.com/openai/codex.git
synced 2026-10-19 16:17:49 +00:00
Respect configured authentication in the thread manager sample (#48004)
## Why The sample hardcoded file-based credential storage and omitted configured auth routing and login restrictions. It should use the configured credentials, including secure storage in `cargo run` builds. ## What changed - Load authentication settings through the shared bootstrap path and re-export the required helpers and types from `codex-core-api`. - Honor CLI and MCP credential stores, `features.secret_auth_storage`, auth routing, the ChatGPT base URL, and system proxy settings. - Preserve managed login-method and ChatGPT workspace restrictions while keeping the sample's built-in execution settings. - Document the sample's authentication configuration behavior. GitOrigin-RevId: b49883537acbebf9266b3970d2709e8e7d1bf217
This commit is contained in:
@@ -8,6 +8,9 @@ pub use codex_app_server_protocol::item_event_to_server_notification;
|
||||
pub use codex_arg0::Arg0DispatchPaths;
|
||||
pub use codex_arg0::arg0_dispatch_or_else;
|
||||
pub use codex_config::ConfigLayerStack;
|
||||
pub use codex_config::ConfigLoadOptions;
|
||||
pub use codex_config::ConfigRequirements;
|
||||
pub use codex_config::ConfigRequirementsToml;
|
||||
pub use codex_config::config_toml::ProjectConfig;
|
||||
pub use codex_config::config_toml::RealtimeAudioConfig;
|
||||
pub use codex_config::config_toml::RealtimeConfig;
|
||||
@@ -64,7 +67,10 @@ pub use codex_core::config::NetworkProxySpec;
|
||||
pub use codex_core::config::Permissions;
|
||||
pub use codex_core::config::TerminalResizeReflowConfig;
|
||||
pub use codex_core::config::ThreadStoreConfig;
|
||||
pub use codex_core::config::bootstrap_auth_config;
|
||||
pub use codex_core::config::find_codex_home;
|
||||
pub use codex_core::config::load_config_toml_with_layer_stack;
|
||||
pub use codex_core::config::resolve_bootstrap_respect_system_proxy;
|
||||
pub use codex_core::init_state_db;
|
||||
pub use codex_core::local_agent_graph_store_from_state_db;
|
||||
pub use codex_core::passthrough_image_store;
|
||||
|
||||
@@ -4,6 +4,12 @@ Small one-shot binary that starts a Codex thread with `ThreadManager` from
|
||||
`codex-core-api`, submits a single user turn, and prints the final assistant
|
||||
message.
|
||||
|
||||
Authentication uses the configured credential storage under `CODEX_HOME`, including
|
||||
`cli_auth_credentials_store`, `mcp_oauth_credentials_store`, and
|
||||
`features.secret_auth_storage`. Local managed authentication requirements and auth
|
||||
routing settings are respected. This also applies to `cargo run` builds. Other
|
||||
execution settings remain the sample's built-in configuration.
|
||||
|
||||
```sh
|
||||
cargo run -p codex-thread-manager-sample -- "Say hello"
|
||||
```
|
||||
|
||||
@@ -13,7 +13,7 @@ use codex_core_api::AltScreenMode;
|
||||
use codex_core_api::ApprovalsReviewer;
|
||||
use codex_core_api::Arg0DispatchPaths;
|
||||
use codex_core_api::AskForApproval;
|
||||
use codex_core_api::AuthCredentialsStoreMode;
|
||||
use codex_core_api::AuthKeyringBackendKind;
|
||||
use codex_core_api::AuthManager;
|
||||
use codex_core_api::AutoCompactTokenLimitScope;
|
||||
use codex_core_api::CodexAppsToolsCache;
|
||||
@@ -21,11 +21,15 @@ use codex_core_api::CodexHomeUserInstructionsProvider;
|
||||
use codex_core_api::CodexThread;
|
||||
use codex_core_api::Config;
|
||||
use codex_core_api::ConfigLayerStack;
|
||||
use codex_core_api::ConfigLoadOptions;
|
||||
use codex_core_api::ConfigRequirements;
|
||||
use codex_core_api::ConfigRequirementsToml;
|
||||
use codex_core_api::Constrained;
|
||||
use codex_core_api::EnvironmentManager;
|
||||
use codex_core_api::EventMsg;
|
||||
use codex_core_api::ExecServerRuntimePaths;
|
||||
use codex_core_api::ExtensionRegistryBuilder;
|
||||
use codex_core_api::Feature;
|
||||
use codex_core_api::Features;
|
||||
use codex_core_api::GhostSnapshotConfig;
|
||||
use codex_core_api::History;
|
||||
@@ -34,7 +38,6 @@ use codex_core_api::ModelAvailabilityNuxConfig;
|
||||
use codex_core_api::MultiAgentV2Config;
|
||||
use codex_core_api::NewThread;
|
||||
use codex_core_api::Notice;
|
||||
use codex_core_api::OAuthCredentialsStoreMode;
|
||||
use codex_core_api::OPENAI_PROVIDER_ID;
|
||||
use codex_core_api::OtelConfig;
|
||||
use codex_core_api::PermissionProfile;
|
||||
@@ -59,14 +62,17 @@ use codex_core_api::UriBasedFileOpener;
|
||||
use codex_core_api::UserInput;
|
||||
use codex_core_api::WebSearchMode;
|
||||
use codex_core_api::arg0_dispatch_or_else;
|
||||
use codex_core_api::bootstrap_auth_config;
|
||||
use codex_core_api::build_models_manager;
|
||||
use codex_core_api::built_in_model_providers;
|
||||
use codex_core_api::find_codex_home;
|
||||
use codex_core_api::init_state_db;
|
||||
use codex_core_api::install_image_generation_extension;
|
||||
use codex_core_api::item_event_to_server_notification;
|
||||
use codex_core_api::load_config_toml_with_layer_stack;
|
||||
use codex_core_api::local_agent_graph_store_from_state_db;
|
||||
use codex_core_api::passthrough_image_store;
|
||||
use codex_core_api::resolve_bootstrap_respect_system_proxy;
|
||||
use codex_core_api::resolve_installation_id;
|
||||
use codex_core_api::set_default_originator;
|
||||
use codex_core_api::thread_store_from_config;
|
||||
@@ -114,7 +120,7 @@ async fn run_main(arg0_paths: Arg0DispatchPaths) -> anyhow::Result<()> {
|
||||
args.prompt.join(" ")
|
||||
};
|
||||
|
||||
let config = new_config(args.model, arg0_paths)?;
|
||||
let config = new_config(args.model, arg0_paths).await?;
|
||||
let state_db = init_state_db(&config).await;
|
||||
|
||||
let auth_manager =
|
||||
@@ -176,9 +182,52 @@ async fn run_main(arg0_paths: Arg0DispatchPaths) -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn new_config(model: Option<String>, arg0_paths: Arg0DispatchPaths) -> anyhow::Result<Config> {
|
||||
async fn new_config(
|
||||
model: Option<String>,
|
||||
arg0_paths: Arg0DispatchPaths,
|
||||
) -> anyhow::Result<Config> {
|
||||
let codex_home = find_codex_home().context("find Codex home")?;
|
||||
let cwd = AbsolutePathBuf::current_dir().context("resolve current directory")?;
|
||||
// Resolve auth through the shared bootstrap path so cargo-run builds retain the configured
|
||||
// secure store instead of the full Config loader's local-development file-store override.
|
||||
let bootstrap = load_config_toml_with_layer_stack(
|
||||
codex_home.as_path(),
|
||||
Some(&cwd),
|
||||
Vec::new(),
|
||||
ConfigLoadOptions::default(),
|
||||
)
|
||||
.await
|
||||
.context("load authentication configuration")?;
|
||||
let auth_config = bootstrap_auth_config(codex_home.as_path(), &bootstrap)?;
|
||||
let requirements = bootstrap.config_layer_stack.requirements();
|
||||
let requirements_toml = bootstrap.config_layer_stack.requirements_toml();
|
||||
// Preserve auth restrictions for every manager rebuilt from Config without importing
|
||||
// execution settings, plugins, or hooks from the bootstrap configuration.
|
||||
let config_layer_stack = ConfigLayerStack::new(
|
||||
Vec::new(),
|
||||
ConfigRequirements {
|
||||
allowed_login_methods: requirements.allowed_login_methods.clone(),
|
||||
allowed_chatgpt_workspaces: requirements.allowed_chatgpt_workspaces.clone(),
|
||||
..Default::default()
|
||||
},
|
||||
ConfigRequirementsToml {
|
||||
allowed_login_methods: requirements_toml.allowed_login_methods.clone(),
|
||||
allowed_chatgpt_workspaces: requirements_toml.allowed_chatgpt_workspaces.clone(),
|
||||
..Default::default()
|
||||
},
|
||||
)?;
|
||||
let mcp_oauth_credentials_store_mode = bootstrap
|
||||
.config_toml
|
||||
.mcp_oauth_credentials_store
|
||||
.unwrap_or_default();
|
||||
let respect_system_proxy = resolve_bootstrap_respect_system_proxy(
|
||||
&bootstrap.config_toml,
|
||||
bootstrap
|
||||
.config_layer_stack
|
||||
.requirements()
|
||||
.feature_requirements
|
||||
.as_ref(),
|
||||
)?;
|
||||
let model_provider_id = OPENAI_PROVIDER_ID.to_string();
|
||||
let model_providers = built_in_model_providers(/*openai_base_url*/ None);
|
||||
let model_provider = model_providers
|
||||
@@ -188,8 +237,8 @@ fn new_config(model: Option<String>, arg0_paths: Arg0DispatchPaths) -> anyhow::R
|
||||
|
||||
let mut config = Config {
|
||||
application_network_policy: Default::default(),
|
||||
application_auth_route_config: None,
|
||||
config_layer_stack: ConfigLayerStack::default(),
|
||||
application_auth_route_config: Some(auth_config.auth_route_config.clone()),
|
||||
config_layer_stack,
|
||||
startup_warnings: Vec::new(),
|
||||
bypass_hook_trust: false,
|
||||
model,
|
||||
@@ -256,11 +305,11 @@ fn new_config(model: Option<String>, arg0_paths: Arg0DispatchPaths) -> anyhow::R
|
||||
cwd: cwd.clone(),
|
||||
workspace_roots: vec![cwd],
|
||||
workspace_roots_explicit: false,
|
||||
cli_auth_credentials_store_mode: AuthCredentialsStoreMode::File,
|
||||
cli_auth_credentials_store_mode: auth_config.auth_credentials_store_mode,
|
||||
mcp_servers: Constrained::allow_any(HashMap::new()),
|
||||
mcp_enterprise_managed_auth: None,
|
||||
non_prefixed_mcp_tool_servers: None,
|
||||
mcp_oauth_credentials_store_mode: OAuthCredentialsStoreMode::File,
|
||||
mcp_oauth_credentials_store_mode,
|
||||
mcp_oauth_callback_port: None,
|
||||
mcp_oauth_callback_url: None,
|
||||
mcp_optional_startup_grace: std::time::Duration::from_secs(1),
|
||||
@@ -292,8 +341,11 @@ fn new_config(model: Option<String>, arg0_paths: Arg0DispatchPaths) -> anyhow::R
|
||||
model_reasoning_summary: None,
|
||||
model_catalog: None,
|
||||
model_verbosity: None,
|
||||
chatgpt_base_url: "https://chatgpt.com/backend-api/".to_string(),
|
||||
respect_system_proxy: false,
|
||||
chatgpt_base_url: auth_config
|
||||
.chatgpt_base_url
|
||||
.clone()
|
||||
.unwrap_or_else(|| "https://chatgpt.com/backend-api/".to_string()),
|
||||
respect_system_proxy,
|
||||
apps_mcp_product_sku: None,
|
||||
responses_api_metadata: BTreeMap::new(),
|
||||
realtime_audio: RealtimeAudioConfig::default(),
|
||||
@@ -305,8 +357,8 @@ fn new_config(model: Option<String>, arg0_paths: Arg0DispatchPaths) -> anyhow::R
|
||||
experimental_realtime_ws_startup_context: None,
|
||||
experimental_realtime_start_instructions: None,
|
||||
experimental_thread_store: ThreadStoreConfig::Local,
|
||||
forced_chatgpt_workspace_id: None,
|
||||
forced_login_method: None,
|
||||
forced_chatgpt_workspace_id: auth_config.forced_chatgpt_workspace_id.clone(),
|
||||
forced_login_method: auth_config.forced_login_method,
|
||||
web_search_mode: Constrained::allow_any(WebSearchMode::Disabled),
|
||||
web_search_config: None,
|
||||
experimental_request_user_input_enabled: true,
|
||||
@@ -339,6 +391,11 @@ fn new_config(model: Option<String>, arg0_paths: Arg0DispatchPaths) -> anyhow::R
|
||||
.features
|
||||
.set(Features::with_defaults())
|
||||
.context("configure default features")?;
|
||||
// AuthManager and MCP both derive their credential backend from Config.
|
||||
config.features.set_enabled(
|
||||
Feature::SecretAuthStorage,
|
||||
auth_config.keyring_backend_kind == AuthKeyringBackendKind::Secrets,
|
||||
)?;
|
||||
Ok(config)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user