Enforce managed authentication requirements locally (#37132)

## Why

Authentication restrictions must apply before stored or environment-provided credentials can be used, including during bootstrap before cloud requirements are fetched.

## What changed

- Add local `requirements.toml` allowlists for login methods and ChatGPT workspaces. Ignore these fields in cloud-provided requirements.
- Combine managed workspace allowlists with existing workspace restrictions by intersection, and fail closed when the resulting policy permits no usable login method.
- Centralize policy checks in the authentication manager so CLI, TUI, app-server, external-auth, and credential-loading paths consistently reject disallowed authentication before token hydration or network requests.

## Testing

- Cover policy composition, workspace intersection, invalid stored and external credentials, bootstrap enforcement, and login endpoint restrictions.

GitOrigin-RevId: efef22b248f3c3333e9aa55423e539efa2d2dd48
This commit is contained in:
Abhinav
2026-08-05 18:03:40 +00:00
committed by copyberry
parent 4cb8676d3a
commit 2994f545a7
36 changed files with 1121 additions and 328 deletions

View File

@@ -63,10 +63,9 @@ use codex_core::config::Config;
use codex_core::config::ConfigBuilder;
use codex_core::config::ConfigOverrides;
use codex_core::config::ConfigTomlLoadResult;
use codex_core::config::bootstrap_auth_config;
use codex_core::config::find_codex_home;
use codex_core::config::load_config_toml_with_layer_stack;
use codex_core::config::resolve_bootstrap_auth_keyring_backend_kind;
use codex_core::config::resolve_bootstrap_auth_route_config;
use codex_core::config::resolve_oss_provider;
use codex_core::config::resolve_profile_v2_config_path;
use codex_core::find_thread_meta_by_name_str;
@@ -75,7 +74,6 @@ use codex_core::path_utils;
use codex_core::read_session_meta_line;
use codex_feedback::CodexFeedback;
use codex_git_utils::get_git_repo_root;
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;
@@ -342,28 +340,9 @@ pub async fn run_main(cli: Cli, arg0_paths: Arg0DispatchPaths) -> anyhow::Result
)
.await;
let bootstrap_config_toml = &bootstrap_config.config_toml;
let chatgpt_base_url = bootstrap_config_toml
.chatgpt_base_url
.clone()
.unwrap_or_else(|| "https://chatgpt.com/backend-api/".to_string());
let auth_route_config = resolve_bootstrap_auth_route_config(
bootstrap_config_toml,
bootstrap_config
.config_layer_stack
.requirements()
.feature_requirements
.as_ref(),
)?;
let cloud_config_bundle = cloud_config_bundle_loader_for_storage(
codex_home.to_path_buf(),
bootstrap_auth_config(&codex_home, &bootstrap_config)?,
/*enable_codex_api_key_env*/ false,
bootstrap_config_toml
.cli_auth_credentials_store
.unwrap_or_default(),
resolve_bootstrap_auth_keyring_backend_kind(&bootstrap_config)?,
chatgpt_base_url,
auth_route_config,
)
.await;
let run_cli_overrides = cli_kv_overrides.clone();
@@ -480,18 +459,7 @@ pub async fn run_main(cli: Cli, arg0_paths: Arg0DispatchPaths) -> anyhow::Result
set_default_client_residency_requirement(config.enforce_residency.value());
let auth_route_config = config.auth_route_config();
if let Err(err) = enforce_login_restrictions(&AuthConfig {
codex_home: config.codex_home.to_path_buf(),
auth_credentials_store_mode: config.cli_auth_credentials_store_mode,
keyring_backend_kind: config.auth_keyring_backend_kind(),
forced_login_method: config.forced_login_method,
forced_chatgpt_workspace_id: config.forced_chatgpt_workspace_id.clone(),
chatgpt_base_url: Some(config.chatgpt_base_url.clone()),
auth_route_config,
})
.await
{
if let Err(err) = enforce_login_restrictions(&config.auth_config()).await {
eprintln!("{err}");
std::process::exit(1);
}