mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
auth: move domain mode below app wire types (#29721)
## Why Authentication mode is a domain concept used by login, model selection, telemetry, and transports. Keeping the canonical type in app-server protocol forces those lower-level crates to depend on an unrelated wire API. ## What changed - Added canonical `codex_protocol::auth::AuthMode` domain values. - Kept the app-server wire DTO unchanged and added an explicit app-side conversion. - Removed production app-server-protocol dependencies from login, model-provider-info, models-manager, and otel call paths. ## Stack This is PR 2 of 6, stacked on [PR #29714](https://github.com/openai/codex/pull/29714). Review only the delta from `codex/split-json-rpc-protocols`. Next: [PR #29722](https://github.com/openai/codex/pull/29722). ## Validation - Auth and login coverage passed in the focused protocol/domain test run. - App-server account and auth conversion coverage passed.
This commit is contained in:
committed by
GitHub
Unverified
parent
806a4b66c9
commit
31372078d1
Generated
+1
-4
@@ -2163,6 +2163,7 @@ dependencies = [
|
||||
"codex-core",
|
||||
"codex-login",
|
||||
"codex-model-provider",
|
||||
"codex-protocol",
|
||||
"codex-state",
|
||||
"codex-uds",
|
||||
"codex-utils-absolute-path",
|
||||
@@ -3263,7 +3264,6 @@ dependencies = [
|
||||
"base64 0.22.1",
|
||||
"chrono",
|
||||
"codex-agent-identity",
|
||||
"codex-app-server-protocol",
|
||||
"codex-client",
|
||||
"codex-config",
|
||||
"codex-keyring-store",
|
||||
@@ -3498,7 +3498,6 @@ name = "codex-model-provider-info"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"codex-api",
|
||||
"codex-app-server-protocol",
|
||||
"codex-protocol",
|
||||
"codex-utils-absolute-path",
|
||||
"http 1.4.0",
|
||||
@@ -3515,7 +3514,6 @@ name = "codex-models-manager"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"codex-app-server-protocol",
|
||||
"codex-collaboration-mode-templates",
|
||||
"codex-login",
|
||||
"codex-otel",
|
||||
@@ -3591,7 +3589,6 @@ version = "0.0.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"codex-api",
|
||||
"codex-app-server-protocol",
|
||||
"codex-protocol",
|
||||
"codex-utils-absolute-path",
|
||||
"codex-utils-string",
|
||||
|
||||
@@ -55,6 +55,7 @@ uuid = { workspace = true, features = ["serde", "v7"] }
|
||||
[dev-dependencies]
|
||||
chrono = { workspace = true }
|
||||
codex-config = { workspace = true }
|
||||
codex-protocol = { workspace = true }
|
||||
pretty_assertions = { workspace = true }
|
||||
tempfile = { workspace = true }
|
||||
tokio = { workspace = true, features = ["test-util"] }
|
||||
|
||||
@@ -18,7 +18,6 @@ use crate::transport::CHANNEL_CAPACITY;
|
||||
use crate::transport::ConnectionOrigin;
|
||||
use crate::transport::TransportEvent;
|
||||
use base64::Engine;
|
||||
use codex_app_server_protocol::AuthMode;
|
||||
use codex_app_server_protocol::ConfigWarningNotification;
|
||||
use codex_app_server_protocol::JSONRPCMessage;
|
||||
use codex_app_server_protocol::RemoteControlConnectionStatus;
|
||||
@@ -36,6 +35,7 @@ use codex_login::CodexAuth;
|
||||
use codex_login::save_auth;
|
||||
use codex_login::token_data::TokenData;
|
||||
use codex_login::token_data::parse_chatgpt_jwt_claims;
|
||||
use codex_protocol::auth::AuthMode;
|
||||
use codex_state::RemoteControlEnrollmentRecord;
|
||||
use codex_state::StateRuntime;
|
||||
use futures::SinkExt;
|
||||
|
||||
@@ -1813,7 +1813,6 @@ mod tests {
|
||||
use crate::transport::remote_control::protocol::StreamId;
|
||||
use crate::transport::remote_control::protocol::normalize_remote_control_url;
|
||||
use chrono::Utc;
|
||||
use codex_app_server_protocol::AuthMode;
|
||||
use codex_app_server_protocol::ConfigWarningNotification;
|
||||
use codex_app_server_protocol::JSONRPCMessage;
|
||||
use codex_app_server_protocol::JSONRPCNotification;
|
||||
@@ -1826,6 +1825,7 @@ mod tests {
|
||||
use codex_login::save_auth;
|
||||
use codex_login::token_data::TokenData;
|
||||
use codex_login::token_data::parse_chatgpt_jwt_claims;
|
||||
use codex_protocol::auth::AuthMode;
|
||||
use codex_state::StateRuntime;
|
||||
use futures::StreamExt;
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
use codex_app_server_protocol::AuthMode as ApiAuthMode;
|
||||
use codex_protocol::auth::AuthMode;
|
||||
|
||||
/// Converts the domain auth mode owned by `codex-protocol` into the app-server wire type owned by
|
||||
/// `codex-app-server-protocol`.
|
||||
///
|
||||
/// The types stay separate so app-server protocol ownership does not leak into domain crates.
|
||||
/// Because this crate owns neither type, Rust's orphan rules require an explicit conversion
|
||||
/// function instead of a `From` implementation.
|
||||
pub(crate) fn auth_mode_to_api(auth_mode: AuthMode) -> ApiAuthMode {
|
||||
match auth_mode {
|
||||
AuthMode::ApiKey => ApiAuthMode::ApiKey,
|
||||
AuthMode::Chatgpt => ApiAuthMode::Chatgpt,
|
||||
AuthMode::ChatgptAuthTokens => ApiAuthMode::ChatgptAuthTokens,
|
||||
AuthMode::AgentIdentity => ApiAuthMode::AgentIdentity,
|
||||
AuthMode::PersonalAccessToken => ApiAuthMode::PersonalAccessToken,
|
||||
AuthMode::BedrockApiKey => ApiAuthMode::BedrockApiKey,
|
||||
}
|
||||
}
|
||||
@@ -82,6 +82,7 @@ const SQLITE_RECOVERY_CONFIG_WARNING_SUMMARY: &str = "Codex rebuilt its local da
|
||||
mod analytics_utils;
|
||||
mod app_server_tracing;
|
||||
mod attestation;
|
||||
mod auth_mode;
|
||||
mod bespoke_event_handling;
|
||||
mod command_exec;
|
||||
mod config;
|
||||
|
||||
@@ -50,7 +50,6 @@ use crate::transport::AppServerTransport;
|
||||
use crate::transport::RemoteControlHandle;
|
||||
use codex_analytics::AnalyticsEventsClient;
|
||||
use codex_analytics::AppServerRpcTransport;
|
||||
use codex_app_server_protocol::AuthMode as LoginAuthMode;
|
||||
use codex_app_server_protocol::ChatgptAuthTokensRefreshParams;
|
||||
use codex_app_server_protocol::ChatgptAuthTokensRefreshReason;
|
||||
use codex_app_server_protocol::ChatgptAuthTokensRefreshResponse;
|
||||
@@ -80,6 +79,7 @@ use codex_login::auth::ExternalAuthRefreshContext;
|
||||
use codex_login::auth::ExternalAuthRefreshReason;
|
||||
use codex_login::auth::ExternalAuthTokens;
|
||||
use codex_protocol::ThreadId;
|
||||
use codex_protocol::auth::AuthMode as LoginAuthMode;
|
||||
use codex_protocol::protocol::SessionSource;
|
||||
use codex_protocol::protocol::W3cTraceContext;
|
||||
use codex_rollout::StateDbHandle;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use super::*;
|
||||
use crate::auth_mode::auth_mode_to_api;
|
||||
use chrono::DateTime;
|
||||
|
||||
mod rate_limit_resets;
|
||||
@@ -179,7 +180,10 @@ impl AccountRequestProcessor {
|
||||
fn current_account_updated_notification(&self) -> AccountUpdatedNotification {
|
||||
let auth = self.auth_manager.auth_cached();
|
||||
AccountUpdatedNotification {
|
||||
auth_mode: auth.as_ref().map(CodexAuth::api_auth_mode),
|
||||
auth_mode: auth
|
||||
.as_ref()
|
||||
.map(CodexAuth::api_auth_mode)
|
||||
.map(auth_mode_to_api),
|
||||
plan_type: auth.as_ref().and_then(CodexAuth::account_plan_type),
|
||||
}
|
||||
}
|
||||
@@ -693,7 +697,10 @@ impl AccountRequestProcessor {
|
||||
)
|
||||
.await;
|
||||
let payload_v2 = AccountUpdatedNotification {
|
||||
auth_mode: auth.as_ref().map(CodexAuth::api_auth_mode),
|
||||
auth_mode: auth
|
||||
.as_ref()
|
||||
.map(CodexAuth::api_auth_mode)
|
||||
.map(auth_mode_to_api),
|
||||
plan_type: auth.as_ref().and_then(CodexAuth::account_plan_type),
|
||||
};
|
||||
outgoing
|
||||
@@ -730,7 +737,8 @@ impl AccountRequestProcessor {
|
||||
.auth_manager
|
||||
.auth_cached()
|
||||
.as_ref()
|
||||
.map(CodexAuth::api_auth_mode))
|
||||
.map(CodexAuth::api_auth_mode)
|
||||
.map(auth_mode_to_api))
|
||||
}
|
||||
|
||||
async fn logout_v2(&self, request_id: ConnectionRequestId) -> Result<(), JSONRPCErrorError> {
|
||||
@@ -801,7 +809,7 @@ impl AccountRequestProcessor {
|
||||
Some(auth) => {
|
||||
let permanent_refresh_failure =
|
||||
self.auth_manager.refresh_failure_for_auth(&auth).is_some();
|
||||
let auth_mode = auth.api_auth_mode();
|
||||
let auth_mode = auth_mode_to_api(auth.api_auth_mode());
|
||||
let (reported_auth_method, token_opt) = if matches!(
|
||||
auth,
|
||||
CodexAuth::AgentIdentity(_) | CodexAuth::PersonalAccessToken(_)
|
||||
|
||||
@@ -24,6 +24,7 @@ use codex_mcp::oauth_login_support;
|
||||
use codex_mcp::should_retry_without_scopes;
|
||||
use codex_plugin::PluginId;
|
||||
use codex_plugin::PluginTelemetryMetadata;
|
||||
use codex_protocol::auth::AuthMode as DomainAuthMode;
|
||||
use codex_rmcp_client::perform_oauth_login_silent;
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -567,7 +568,7 @@ impl PluginRequestProcessor {
|
||||
let include_global_remote =
|
||||
!explicit_marketplace_kinds && config.features.enabled(Feature::RemotePlugin);
|
||||
let use_remote_global_catalog =
|
||||
include_global_remote && auth_mode.is_some_and(AuthMode::uses_codex_backend);
|
||||
include_global_remote && auth_mode.is_some_and(DomainAuthMode::uses_codex_backend);
|
||||
let remote_plugin_service_config = RemotePluginServiceConfig {
|
||||
chatgpt_base_url: config.chatgpt_base_url.clone(),
|
||||
};
|
||||
|
||||
@@ -6,13 +6,13 @@ use base64::Engine;
|
||||
use base64::engine::general_purpose::URL_SAFE_NO_PAD;
|
||||
use chrono::DateTime;
|
||||
use chrono::Utc;
|
||||
use codex_app_server_protocol::AuthMode;
|
||||
use codex_config::types::AuthCredentialsStoreMode;
|
||||
use codex_login::AuthDotJson;
|
||||
use codex_login::AuthKeyringBackendKind;
|
||||
use codex_login::save_auth;
|
||||
use codex_login::token_data::TokenData;
|
||||
use codex_login::token_data::parse_chatgpt_jwt_claims;
|
||||
use codex_protocol::auth::AuthMode;
|
||||
use serde_json::json;
|
||||
|
||||
/// Builder for writing a fake ChatGPT auth.json in tests.
|
||||
|
||||
@@ -27,7 +27,6 @@ use codex_app_server_protocol::AppReview;
|
||||
use codex_app_server_protocol::AppScreenshot;
|
||||
use codex_app_server_protocol::AppsListParams;
|
||||
use codex_app_server_protocol::AppsListResponse;
|
||||
use codex_app_server_protocol::AuthMode;
|
||||
use codex_app_server_protocol::JSONRPCError;
|
||||
use codex_app_server_protocol::JSONRPCResponse;
|
||||
use codex_app_server_protocol::RequestId;
|
||||
@@ -38,6 +37,7 @@ use codex_config::types::AuthCredentialsStoreMode;
|
||||
use codex_login::AuthDotJson;
|
||||
use codex_login::AuthKeyringBackendKind;
|
||||
use codex_login::save_auth;
|
||||
use codex_protocol::auth::AuthMode;
|
||||
use pretty_assertions::assert_eq;
|
||||
use rmcp::handler::server::ServerHandler;
|
||||
use rmcp::model::JsonObject;
|
||||
|
||||
+32
-34
@@ -53,6 +53,7 @@ use codex_login::default_client::build_reqwest_client;
|
||||
use codex_login::default_client::default_headers;
|
||||
use codex_login::load_auth_dot_json;
|
||||
use codex_model_provider::create_model_provider;
|
||||
use codex_protocol::auth::AuthMode;
|
||||
use codex_protocol::protocol::AskForApproval;
|
||||
use codex_terminal_detection::Multiplexer;
|
||||
use codex_terminal_detection::TerminalInfo;
|
||||
@@ -1323,27 +1324,27 @@ fn provider_specific_auth_check(
|
||||
|
||||
fn stored_auth_mode(auth: &codex_login::AuthDotJson) -> &'static str {
|
||||
match stored_auth_mode_value(auth) {
|
||||
codex_app_server_protocol::AuthMode::ApiKey => "api_key",
|
||||
codex_app_server_protocol::AuthMode::Chatgpt => "chatgpt",
|
||||
codex_app_server_protocol::AuthMode::ChatgptAuthTokens => "chatgpt_auth_tokens",
|
||||
codex_app_server_protocol::AuthMode::AgentIdentity => "agent_identity",
|
||||
codex_app_server_protocol::AuthMode::PersonalAccessToken => "personal_access_token",
|
||||
codex_app_server_protocol::AuthMode::BedrockApiKey => "bedrock_api_key",
|
||||
AuthMode::ApiKey => "api_key",
|
||||
AuthMode::Chatgpt => "chatgpt",
|
||||
AuthMode::ChatgptAuthTokens => "chatgpt_auth_tokens",
|
||||
AuthMode::AgentIdentity => "agent_identity",
|
||||
AuthMode::PersonalAccessToken => "personal_access_token",
|
||||
AuthMode::BedrockApiKey => "bedrock_api_key",
|
||||
}
|
||||
}
|
||||
|
||||
fn stored_auth_mode_value(auth: &AuthDotJson) -> codex_app_server_protocol::AuthMode {
|
||||
fn stored_auth_mode_value(auth: &AuthDotJson) -> AuthMode {
|
||||
if let Some(mode) = auth.auth_mode {
|
||||
return mode;
|
||||
}
|
||||
if auth.personal_access_token.is_some() {
|
||||
codex_app_server_protocol::AuthMode::PersonalAccessToken
|
||||
AuthMode::PersonalAccessToken
|
||||
} else if auth.bedrock_api_key.is_some() {
|
||||
codex_app_server_protocol::AuthMode::BedrockApiKey
|
||||
AuthMode::BedrockApiKey
|
||||
} else if auth.openai_api_key.is_some() {
|
||||
codex_app_server_protocol::AuthMode::ApiKey
|
||||
AuthMode::ApiKey
|
||||
} else {
|
||||
codex_app_server_protocol::AuthMode::Chatgpt
|
||||
AuthMode::Chatgpt
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1353,7 +1354,7 @@ fn stored_auth_issues(
|
||||
) -> Vec<&'static str> {
|
||||
let mut issues = Vec::new();
|
||||
match stored_auth_mode_value(auth) {
|
||||
codex_app_server_protocol::AuthMode::ApiKey => {
|
||||
AuthMode::ApiKey => {
|
||||
let stored_key_present = auth
|
||||
.openai_api_key
|
||||
.as_deref()
|
||||
@@ -1364,7 +1365,7 @@ fn stored_auth_issues(
|
||||
issues.push("API key auth is missing an API key");
|
||||
}
|
||||
}
|
||||
codex_app_server_protocol::AuthMode::Chatgpt => {
|
||||
AuthMode::Chatgpt => {
|
||||
match auth.tokens.as_ref() {
|
||||
Some(tokens) => {
|
||||
if tokens.access_token.trim().is_empty() {
|
||||
@@ -1380,7 +1381,7 @@ fn stored_auth_issues(
|
||||
issues.push("ChatGPT auth is missing refresh metadata");
|
||||
}
|
||||
}
|
||||
codex_app_server_protocol::AuthMode::ChatgptAuthTokens => {
|
||||
AuthMode::ChatgptAuthTokens => {
|
||||
match auth.tokens.as_ref() {
|
||||
Some(tokens) => {
|
||||
if tokens.access_token.trim().is_empty() {
|
||||
@@ -1396,7 +1397,7 @@ fn stored_auth_issues(
|
||||
issues.push("external ChatGPT auth is missing refresh metadata");
|
||||
}
|
||||
}
|
||||
codex_app_server_protocol::AuthMode::AgentIdentity => {
|
||||
AuthMode::AgentIdentity => {
|
||||
if auth
|
||||
.agent_identity
|
||||
.as_ref()
|
||||
@@ -1405,7 +1406,7 @@ fn stored_auth_issues(
|
||||
issues.push("agent identity auth is missing an agent identity token");
|
||||
}
|
||||
}
|
||||
codex_app_server_protocol::AuthMode::PersonalAccessToken => {
|
||||
AuthMode::PersonalAccessToken => {
|
||||
if auth
|
||||
.personal_access_token
|
||||
.as_deref()
|
||||
@@ -1414,7 +1415,7 @@ fn stored_auth_issues(
|
||||
issues.push("personal access token auth is missing a personal access token");
|
||||
}
|
||||
}
|
||||
codex_app_server_protocol::AuthMode::BedrockApiKey => {
|
||||
AuthMode::BedrockApiKey => {
|
||||
if auth.bedrock_api_key.is_none() {
|
||||
issues.push("Bedrock API key auth is missing a Bedrock API key");
|
||||
}
|
||||
@@ -2462,12 +2463,12 @@ fn websocket_error_detail(err: &ApiError) -> String {
|
||||
|
||||
fn auth_mode_name(auth: &CodexAuth) -> &'static str {
|
||||
match auth.auth_mode() {
|
||||
codex_app_server_protocol::AuthMode::ApiKey => "api_key",
|
||||
codex_app_server_protocol::AuthMode::Chatgpt => "chatgpt",
|
||||
codex_app_server_protocol::AuthMode::ChatgptAuthTokens => "chatgpt_auth_tokens",
|
||||
codex_app_server_protocol::AuthMode::AgentIdentity => "agent_identity",
|
||||
codex_app_server_protocol::AuthMode::PersonalAccessToken => "personal_access_token",
|
||||
codex_app_server_protocol::AuthMode::BedrockApiKey => "bedrock_api_key",
|
||||
AuthMode::ApiKey => "api_key",
|
||||
AuthMode::Chatgpt => "chatgpt",
|
||||
AuthMode::ChatgptAuthTokens => "chatgpt_auth_tokens",
|
||||
AuthMode::AgentIdentity => "agent_identity",
|
||||
AuthMode::PersonalAccessToken => "personal_access_token",
|
||||
AuthMode::BedrockApiKey => "bedrock_api_key",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2600,15 +2601,12 @@ fn provider_auth_reachability_mode_from_auth(
|
||||
return ProviderAuthReachabilityMode::Chatgpt;
|
||||
}
|
||||
match stored_auth.map(stored_auth_mode_value) {
|
||||
Some(AuthMode::ApiKey | AuthMode::BedrockApiKey) => ProviderAuthReachabilityMode::ApiKey,
|
||||
Some(
|
||||
codex_app_server_protocol::AuthMode::ApiKey
|
||||
| codex_app_server_protocol::AuthMode::BedrockApiKey,
|
||||
) => ProviderAuthReachabilityMode::ApiKey,
|
||||
Some(
|
||||
codex_app_server_protocol::AuthMode::Chatgpt
|
||||
| codex_app_server_protocol::AuthMode::ChatgptAuthTokens
|
||||
| codex_app_server_protocol::AuthMode::AgentIdentity
|
||||
| codex_app_server_protocol::AuthMode::PersonalAccessToken,
|
||||
AuthMode::Chatgpt
|
||||
| AuthMode::ChatgptAuthTokens
|
||||
| AuthMode::AgentIdentity
|
||||
| AuthMode::PersonalAccessToken,
|
||||
)
|
||||
| None => ProviderAuthReachabilityMode::Chatgpt,
|
||||
}
|
||||
@@ -3502,7 +3500,7 @@ mod tests {
|
||||
#[test]
|
||||
fn stored_auth_validation_rejects_missing_api_key() {
|
||||
let auth = AuthDotJson {
|
||||
auth_mode: Some(codex_app_server_protocol::AuthMode::ApiKey),
|
||||
auth_mode: Some(AuthMode::ApiKey),
|
||||
openai_api_key: None,
|
||||
tokens: None,
|
||||
last_refresh: None,
|
||||
@@ -3554,7 +3552,7 @@ mod tests {
|
||||
assert_eq!(stored_auth_mode(&auth), "personal_access_token");
|
||||
assert!(stored_auth_issues(&auth, |_| false).is_empty());
|
||||
|
||||
auth.auth_mode = Some(codex_app_server_protocol::AuthMode::PersonalAccessToken);
|
||||
auth.auth_mode = Some(AuthMode::PersonalAccessToken);
|
||||
auth.personal_access_token = None;
|
||||
assert_eq!(
|
||||
stored_auth_issues(&auth, |_| false),
|
||||
@@ -3565,7 +3563,7 @@ mod tests {
|
||||
#[test]
|
||||
fn provider_reachability_mode_uses_api_key_auth() {
|
||||
let api_key_auth = AuthDotJson {
|
||||
auth_mode: Some(codex_app_server_protocol::AuthMode::ApiKey),
|
||||
auth_mode: Some(AuthMode::ApiKey),
|
||||
openai_api_key: Some("sk-test".to_string()),
|
||||
tokens: None,
|
||||
last_refresh: None,
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
//! into a one-shot CLI command while still producing a durable `codex-login.log` artifact that
|
||||
//! support can request from users.
|
||||
|
||||
use codex_app_server_protocol::AuthMode;
|
||||
use codex_config::types::AuthCredentialsStoreMode;
|
||||
use codex_core::config::Config;
|
||||
use codex_login::AuthKeyringBackendKind;
|
||||
@@ -20,6 +19,7 @@ use codex_login::login_with_api_key;
|
||||
use codex_login::logout_with_revoke;
|
||||
use codex_login::run_device_code_login;
|
||||
use codex_login::run_login_server;
|
||||
use codex_protocol::auth::AuthMode;
|
||||
use codex_protocol::config_types::ForcedLoginMethod;
|
||||
use codex_utils_cli::CliConfigOverrides;
|
||||
use std::fs::OpenOptions;
|
||||
|
||||
@@ -2,7 +2,6 @@ use anyhow::Context;
|
||||
use anyhow::Result;
|
||||
use anyhow::bail;
|
||||
use clap::Parser;
|
||||
use codex_app_server_protocol::AuthMode;
|
||||
use codex_core::config::Config;
|
||||
use codex_core::config::find_codex_home;
|
||||
use codex_core_plugins::ConfiguredMarketplace;
|
||||
@@ -22,6 +21,7 @@ use codex_login::CodexAuth;
|
||||
use codex_login::auth::read_codex_api_key_from_env;
|
||||
use codex_plugin::PluginId;
|
||||
use codex_plugin::validate_plugin_segment;
|
||||
use codex_protocol::auth::AuthMode;
|
||||
use codex_utils_cli::CliConfigOverrides;
|
||||
use serde::Serialize;
|
||||
use std::collections::HashMap;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use codex_app_server_protocol::AuthMode;
|
||||
use codex_plugin::AppDeclaration;
|
||||
use codex_protocol::auth::AuthMode;
|
||||
use std::collections::HashMap;
|
||||
use std::collections::HashSet;
|
||||
|
||||
|
||||
@@ -15,9 +15,9 @@ use crate::test_support::write_curated_plugin_sha_with;
|
||||
use crate::test_support::write_file;
|
||||
use crate::test_support::write_openai_api_curated_marketplace;
|
||||
use crate::test_support::write_openai_curated_marketplace;
|
||||
use codex_app_server_protocol::AuthMode;
|
||||
use codex_config::CONFIG_TOML_FILE;
|
||||
use codex_login::CodexAuth;
|
||||
use codex_protocol::auth::AuthMode;
|
||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
use pretty_assertions::assert_eq;
|
||||
use serde_json::json;
|
||||
|
||||
@@ -15,7 +15,6 @@ use crate::remote::RemoteInstalledPlugin;
|
||||
use crate::store::PluginStore;
|
||||
use crate::store::plugin_version_for_source;
|
||||
use crate::store::plugin_version_for_source_with_fallback_manifest;
|
||||
use codex_app_server_protocol::AuthMode;
|
||||
use codex_config::ConfigLayerStack;
|
||||
use codex_config::HooksFile;
|
||||
use codex_config::types::McpServerConfig;
|
||||
@@ -39,6 +38,7 @@ use codex_plugin::PluginHookSource;
|
||||
use codex_plugin::PluginId;
|
||||
use codex_plugin::PluginIdError;
|
||||
use codex_plugin::app_connector_ids_from_declarations;
|
||||
use codex_protocol::auth::AuthMode;
|
||||
use codex_protocol::protocol::Product;
|
||||
use codex_protocol::protocol::SkillScope;
|
||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
|
||||
@@ -54,7 +54,6 @@ use crate::store::PluginStore;
|
||||
use crate::store::PluginStoreError;
|
||||
use crate::tool_suggest_metadata::ToolSuggestMetadataCache;
|
||||
use codex_analytics::AnalyticsEventsClient;
|
||||
use codex_app_server_protocol::AuthMode;
|
||||
use codex_config::ConfigLayerStack;
|
||||
use codex_config::clear_user_plugin;
|
||||
use codex_config::set_user_plugin_enabled;
|
||||
@@ -75,6 +74,7 @@ use codex_plugin::PluginIdError;
|
||||
use codex_plugin::PluginTelemetryMetadata;
|
||||
use codex_plugin::app_connector_ids_from_declarations;
|
||||
use codex_plugin::prompt_safe_plugin_description;
|
||||
use codex_protocol::auth::AuthMode;
|
||||
use codex_protocol::protocol::HookEventName;
|
||||
use codex_protocol::protocol::Product;
|
||||
use codex_tools::DiscoverablePluginInfo;
|
||||
|
||||
@@ -25,7 +25,6 @@ use crate::test_support::write_curated_plugin_sha_with as write_curated_plugin_s
|
||||
use crate::test_support::write_file;
|
||||
use crate::test_support::write_openai_api_curated_marketplace;
|
||||
use crate::test_support::write_openai_curated_marketplace;
|
||||
use codex_app_server_protocol::AuthMode;
|
||||
use codex_app_server_protocol::ConfigLayerSource;
|
||||
use codex_config::AppToolApproval;
|
||||
use codex_config::CONFIG_TOML_FILE;
|
||||
@@ -44,6 +43,7 @@ use codex_core_skills::config_rules::SkillConfigRules;
|
||||
use codex_login::CodexAuth;
|
||||
use codex_plugin::AppDeclaration;
|
||||
use codex_plugin::PluginId;
|
||||
use codex_protocol::auth::AuthMode;
|
||||
use codex_protocol::protocol::HookEventName;
|
||||
use codex_protocol::protocol::Product;
|
||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
|
||||
@@ -2,7 +2,6 @@ use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use std::sync::RwLock;
|
||||
|
||||
use codex_app_server_protocol::AuthMode;
|
||||
use codex_core_skills::config_rules::SkillConfigRules;
|
||||
use codex_plugin::AppDeclaration;
|
||||
use codex_plugin::PluginCapabilitySummary;
|
||||
@@ -10,6 +9,7 @@ use codex_plugin::PluginId;
|
||||
use codex_plugin::PluginIdError;
|
||||
use codex_plugin::app_connector_ids_from_declarations;
|
||||
use codex_plugin::prompt_safe_plugin_description;
|
||||
use codex_protocol::auth::AuthMode;
|
||||
use codex_protocol::protocol::Product;
|
||||
use tokio::sync::Semaphore;
|
||||
|
||||
|
||||
@@ -61,7 +61,6 @@ use codex_api::auth_header_telemetry;
|
||||
use codex_api::build_session_headers;
|
||||
use codex_api::create_text_param_for_request;
|
||||
use codex_api::response_create_client_metadata;
|
||||
use codex_app_server_protocol::AuthMode;
|
||||
use codex_login::AuthManager;
|
||||
use codex_login::CodexAuth;
|
||||
use codex_login::RefreshTokenError;
|
||||
@@ -69,6 +68,7 @@ use codex_login::UnauthorizedRecovery;
|
||||
use codex_login::default_client::build_reqwest_client;
|
||||
use codex_otel::SessionTelemetry;
|
||||
use codex_otel::current_span_w3c_trace_context;
|
||||
use codex_protocol::auth::AuthMode;
|
||||
|
||||
use codex_protocol::ThreadId;
|
||||
use codex_protocol::config_types::ReasoningSummary as ReasoningSummaryConfig;
|
||||
|
||||
@@ -16,7 +16,6 @@ use crate::test_support::responses_metadata as test_responses_metadata;
|
||||
use codex_api::ApiError;
|
||||
use codex_api::ResponseEvent;
|
||||
use codex_api::TransportError;
|
||||
use codex_app_server_protocol::AuthMode;
|
||||
use codex_login::AuthManager;
|
||||
use codex_login::CodexAuth;
|
||||
use codex_model_provider::BearerAuthProvider;
|
||||
@@ -28,6 +27,7 @@ use codex_model_provider_info::WireApi;
|
||||
use codex_model_provider_info::create_oss_provider_with_base_url;
|
||||
use codex_otel::SessionTelemetry;
|
||||
use codex_protocol::ThreadId;
|
||||
use codex_protocol::auth::AuthMode;
|
||||
use codex_protocol::models::ContentItem;
|
||||
use codex_protocol::models::ResponseItem;
|
||||
use codex_protocol::openai_models::ModelInfo;
|
||||
|
||||
@@ -25,7 +25,7 @@ use codex_analytics::CompactionImplementation;
|
||||
use codex_analytics::CompactionPhase;
|
||||
use codex_analytics::CompactionReason;
|
||||
use codex_analytics::CompactionTrigger;
|
||||
use codex_app_server_protocol::AuthMode;
|
||||
use codex_protocol::auth::AuthMode;
|
||||
use codex_protocol::error::CodexErr;
|
||||
use codex_protocol::error::Result as CodexResult;
|
||||
use codex_protocol::items::ContextCompactionItem;
|
||||
|
||||
@@ -22,13 +22,13 @@ use codex_api::RealtimeWebsocketClient;
|
||||
use codex_api::RealtimeWebsocketEvents;
|
||||
use codex_api::RealtimeWebsocketWriter;
|
||||
use codex_api::map_api_error;
|
||||
use codex_app_server_protocol::AuthMode;
|
||||
use codex_config::config_toml::RealtimeWsMode;
|
||||
use codex_config::config_toml::RealtimeWsVersion;
|
||||
use codex_login::CodexAuth;
|
||||
use codex_login::default_client::default_headers;
|
||||
use codex_login::read_openai_api_key_from_env;
|
||||
use codex_model_provider_info::ModelProviderInfo;
|
||||
use codex_protocol::auth::AuthMode;
|
||||
use codex_protocol::error::CodexErr;
|
||||
use codex_protocol::error::Result as CodexResult;
|
||||
use codex_protocol::models::MessagePhase;
|
||||
|
||||
@@ -11,7 +11,6 @@ workspace = true
|
||||
base64 = { workspace = true }
|
||||
chrono = { workspace = true, features = ["serde"] }
|
||||
codex-agent-identity = { workspace = true }
|
||||
codex-app-server-protocol = { workspace = true }
|
||||
codex-client = { workspace = true }
|
||||
codex-config = { workspace = true }
|
||||
codex-keyring-store = { workspace = true }
|
||||
|
||||
@@ -2,8 +2,8 @@ use super::*;
|
||||
use crate::auth::storage::FileAuthStorage;
|
||||
use crate::auth::storage::get_auth_file;
|
||||
use crate::token_data::IdTokenInfo;
|
||||
use codex_app_server_protocol::AuthMode;
|
||||
use codex_protocol::account::PlanType as AccountPlanType;
|
||||
use codex_protocol::auth::AuthMode;
|
||||
use codex_protocol::auth::KnownPlan as InternalKnownPlan;
|
||||
use codex_protocol::auth::PlanType as InternalPlanType;
|
||||
use codex_protocol::protocol::SessionSource;
|
||||
@@ -162,7 +162,7 @@ async fn stored_agent_identity_jwt_keeps_auth_json_unchanged() -> anyhow::Result
|
||||
save_auth(
|
||||
codex_home.path(),
|
||||
&AuthDotJson {
|
||||
auth_mode: Some(ApiAuthMode::AgentIdentity),
|
||||
auth_mode: Some(AuthMode::AgentIdentity),
|
||||
openai_api_key: None,
|
||||
tokens: None,
|
||||
last_refresh: None,
|
||||
@@ -897,7 +897,7 @@ async fn loads_api_key_from_auth_json() {
|
||||
fn logout_removes_auth_file() -> Result<(), std::io::Error> {
|
||||
let dir = tempdir()?;
|
||||
let auth_dot_json = AuthDotJson {
|
||||
auth_mode: Some(ApiAuthMode::ApiKey),
|
||||
auth_mode: Some(AuthMode::ApiKey),
|
||||
openai_api_key: Some("sk-test-key".to_string()),
|
||||
tokens: None,
|
||||
last_refresh: None,
|
||||
@@ -1045,7 +1045,7 @@ async fn external_bearer_only_auth_manager_uses_cached_provider_token() {
|
||||
assert_eq!(first.as_deref(), Some("provider-token"));
|
||||
assert_eq!(second.as_deref(), Some("provider-token"));
|
||||
assert_eq!(manager.auth_mode(), Some(AuthMode::ApiKey));
|
||||
assert_eq!(manager.get_api_auth_mode(), Some(ApiAuthMode::ApiKey));
|
||||
assert_eq!(manager.get_api_auth_mode(), Some(AuthMode::ApiKey));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -1822,7 +1822,7 @@ async fn enforce_login_restrictions_logs_out_for_agent_identity_workspace_mismat
|
||||
save_auth(
|
||||
codex_home.path(),
|
||||
&AuthDotJson {
|
||||
auth_mode: Some(ApiAuthMode::AgentIdentity),
|
||||
auth_mode: Some(AuthMode::AgentIdentity),
|
||||
openai_api_key: None,
|
||||
tokens: None,
|
||||
last_refresh: None,
|
||||
|
||||
@@ -7,7 +7,7 @@ use serde::Serialize;
|
||||
use super::manager::save_auth;
|
||||
use super::storage::AuthDotJson;
|
||||
use super::storage::AuthKeyringBackendKind;
|
||||
use codex_app_server_protocol::AuthMode;
|
||||
use codex_protocol::auth::AuthMode;
|
||||
|
||||
/// Managed Amazon Bedrock API key persisted in `auth.json`.
|
||||
#[derive(Deserialize, Serialize, Clone, Debug, PartialEq, Eq)]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use codex_app_server_protocol::AuthMode;
|
||||
use codex_config::types::AuthCredentialsStoreMode;
|
||||
use codex_protocol::auth::AuthMode;
|
||||
use pretty_assertions::assert_eq;
|
||||
use serial_test::serial;
|
||||
use tempfile::tempdir;
|
||||
|
||||
@@ -2,7 +2,7 @@ use super::manager::ExternalAuth;
|
||||
use super::manager::ExternalAuthFuture;
|
||||
use super::manager::ExternalAuthRefreshContext;
|
||||
use super::manager::ExternalAuthTokens;
|
||||
use codex_app_server_protocol::AuthMode;
|
||||
use codex_protocol::auth::AuthMode;
|
||||
use codex_protocol::config_types::ModelProviderAuthInfo;
|
||||
use std::fmt;
|
||||
use std::io;
|
||||
|
||||
@@ -20,8 +20,7 @@ use tokio::sync::watch;
|
||||
use tracing::instrument;
|
||||
|
||||
use codex_agent_identity::ChatGptEnvironment;
|
||||
use codex_app_server_protocol::AuthMode;
|
||||
use codex_app_server_protocol::AuthMode as ApiAuthMode;
|
||||
use codex_protocol::auth::AuthMode;
|
||||
use codex_protocol::config_types::ForcedLoginMethod;
|
||||
use codex_protocol::config_types::ModelProviderAuthInfo;
|
||||
|
||||
@@ -242,13 +241,13 @@ impl CodexAuth {
|
||||
auth_route_config: Option<&AuthRouteConfig>,
|
||||
) -> std::io::Result<Self> {
|
||||
let auth_mode = auth_dot_json.resolved_mode();
|
||||
if auth_mode == ApiAuthMode::ApiKey {
|
||||
if auth_mode == AuthMode::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(Self::from_api_key(api_key));
|
||||
}
|
||||
if auth_mode == ApiAuthMode::AgentIdentity {
|
||||
if auth_mode == AuthMode::AgentIdentity {
|
||||
let Some(agent_identity) = auth_dot_json.agent_identity.clone() else {
|
||||
return Err(std::io::Error::other(
|
||||
"agent identity auth is missing agent identity auth material.",
|
||||
@@ -282,7 +281,7 @@ impl CodexAuth {
|
||||
}
|
||||
}
|
||||
}
|
||||
if auth_mode == ApiAuthMode::PersonalAccessToken {
|
||||
if auth_mode == AuthMode::PersonalAccessToken {
|
||||
let Some(personal_access_token) = auth_dot_json.personal_access_token.as_deref() else {
|
||||
return Err(std::io::Error::other(
|
||||
"personal access token auth is missing a personal access token.",
|
||||
@@ -291,7 +290,7 @@ impl CodexAuth {
|
||||
return Self::from_personal_access_token(personal_access_token, auth_route_config)
|
||||
.await;
|
||||
}
|
||||
if auth_mode == ApiAuthMode::BedrockApiKey {
|
||||
if auth_mode == AuthMode::BedrockApiKey {
|
||||
let Some(auth) = auth_dot_json.bedrock_api_key else {
|
||||
return Err(std::io::Error::other(
|
||||
"Bedrock API key auth is missing a Bedrock API key.",
|
||||
@@ -308,7 +307,7 @@ impl CodexAuth {
|
||||
};
|
||||
|
||||
match auth_mode {
|
||||
ApiAuthMode::Chatgpt => {
|
||||
AuthMode::Chatgpt => {
|
||||
let storage = create_auth_storage(
|
||||
codex_home.to_path_buf(),
|
||||
storage_mode,
|
||||
@@ -316,15 +315,13 @@ impl CodexAuth {
|
||||
);
|
||||
Ok(Self::Chatgpt(ChatgptAuth { state, storage }))
|
||||
}
|
||||
ApiAuthMode::ChatgptAuthTokens => {
|
||||
Ok(Self::ChatgptAuthTokens(ChatgptAuthTokens { state }))
|
||||
}
|
||||
ApiAuthMode::ApiKey => unreachable!("api key mode is handled above"),
|
||||
ApiAuthMode::AgentIdentity => unreachable!("agent identity mode is handled above"),
|
||||
ApiAuthMode::PersonalAccessToken => {
|
||||
AuthMode::ChatgptAuthTokens => Ok(Self::ChatgptAuthTokens(ChatgptAuthTokens { state })),
|
||||
AuthMode::ApiKey => unreachable!("api key mode is handled above"),
|
||||
AuthMode::AgentIdentity => unreachable!("agent identity mode is handled above"),
|
||||
AuthMode::PersonalAccessToken => {
|
||||
unreachable!("personal access token mode is handled above")
|
||||
}
|
||||
ApiAuthMode::BedrockApiKey => unreachable!("bedrock api key mode is handled above"),
|
||||
AuthMode::BedrockApiKey => unreachable!("bedrock api key mode is handled above"),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -395,6 +392,9 @@ impl CodexAuth {
|
||||
))
|
||||
}
|
||||
|
||||
/// Returns the effective backend auth mode.
|
||||
///
|
||||
/// Externally managed ChatGPT tokens are normalized to [`AuthMode::Chatgpt`].
|
||||
pub fn auth_mode(&self) -> AuthMode {
|
||||
match self {
|
||||
Self::ApiKey(_) => AuthMode::ApiKey,
|
||||
@@ -405,14 +405,15 @@ impl CodexAuth {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn api_auth_mode(&self) -> ApiAuthMode {
|
||||
/// Returns the precise kind of credentials backing this authentication.
|
||||
pub fn api_auth_mode(&self) -> AuthMode {
|
||||
match self {
|
||||
Self::ApiKey(_) => ApiAuthMode::ApiKey,
|
||||
Self::Chatgpt(_) => ApiAuthMode::Chatgpt,
|
||||
Self::ChatgptAuthTokens(_) => ApiAuthMode::ChatgptAuthTokens,
|
||||
Self::AgentIdentity(_) => ApiAuthMode::AgentIdentity,
|
||||
Self::PersonalAccessToken(_) => ApiAuthMode::PersonalAccessToken,
|
||||
Self::BedrockApiKey(_) => ApiAuthMode::BedrockApiKey,
|
||||
Self::ApiKey(_) => AuthMode::ApiKey,
|
||||
Self::Chatgpt(_) => AuthMode::Chatgpt,
|
||||
Self::ChatgptAuthTokens(_) => AuthMode::ChatgptAuthTokens,
|
||||
Self::AgentIdentity(_) => AuthMode::AgentIdentity,
|
||||
Self::PersonalAccessToken(_) => AuthMode::PersonalAccessToken,
|
||||
Self::BedrockApiKey(_) => AuthMode::BedrockApiKey,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -660,7 +661,7 @@ impl CodexAuth {
|
||||
/// Consider this private to integration tests.
|
||||
pub fn create_dummy_chatgpt_auth_for_testing() -> Self {
|
||||
let auth_dot_json = AuthDotJson {
|
||||
auth_mode: Some(ApiAuthMode::Chatgpt),
|
||||
auth_mode: Some(AuthMode::Chatgpt),
|
||||
openai_api_key: None,
|
||||
tokens: Some(TokenData {
|
||||
id_token: Default::default(),
|
||||
@@ -851,7 +852,7 @@ pub fn login_with_api_key(
|
||||
keyring_backend_kind: AuthKeyringBackendKind,
|
||||
) -> std::io::Result<()> {
|
||||
let auth_dot_json = AuthDotJson {
|
||||
auth_mode: Some(ApiAuthMode::ApiKey),
|
||||
auth_mode: Some(AuthMode::ApiKey),
|
||||
openai_api_key: Some(api_key.to_string()),
|
||||
tokens: None,
|
||||
last_refresh: None,
|
||||
@@ -900,7 +901,7 @@ pub async fn login_with_access_token(
|
||||
.to_string();
|
||||
verified_record_from_jwt(jwt, &base_url, auth_route_config).await?;
|
||||
AuthDotJson {
|
||||
auth_mode: Some(ApiAuthMode::AgentIdentity),
|
||||
auth_mode: Some(AuthMode::AgentIdentity),
|
||||
openai_api_key: None,
|
||||
tokens: None,
|
||||
last_refresh: None,
|
||||
@@ -1419,7 +1420,7 @@ impl AuthDotJson {
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
auth_mode: Some(ApiAuthMode::ChatgptAuthTokens),
|
||||
auth_mode: Some(AuthMode::ChatgptAuthTokens),
|
||||
openai_api_key: None,
|
||||
tokens: Some(tokens),
|
||||
last_refresh: Some(Utc::now()),
|
||||
@@ -1442,27 +1443,27 @@ impl AuthDotJson {
|
||||
Self::from_external_tokens(&external)
|
||||
}
|
||||
|
||||
pub(super) fn resolved_mode(&self) -> ApiAuthMode {
|
||||
pub(super) fn resolved_mode(&self) -> AuthMode {
|
||||
if let Some(mode) = self.auth_mode {
|
||||
return mode;
|
||||
}
|
||||
if self.personal_access_token.is_some() {
|
||||
return ApiAuthMode::PersonalAccessToken;
|
||||
return AuthMode::PersonalAccessToken;
|
||||
}
|
||||
if self.bedrock_api_key.is_some() {
|
||||
return ApiAuthMode::BedrockApiKey;
|
||||
return AuthMode::BedrockApiKey;
|
||||
}
|
||||
if self.openai_api_key.is_some() {
|
||||
return ApiAuthMode::ApiKey;
|
||||
return AuthMode::ApiKey;
|
||||
}
|
||||
ApiAuthMode::Chatgpt
|
||||
AuthMode::Chatgpt
|
||||
}
|
||||
|
||||
fn storage_mode(
|
||||
&self,
|
||||
auth_credentials_store_mode: AuthCredentialsStoreMode,
|
||||
) -> AuthCredentialsStoreMode {
|
||||
if self.resolved_mode() == ApiAuthMode::ChatgptAuthTokens {
|
||||
if self.resolved_mode() == AuthMode::ChatgptAuthTokens {
|
||||
AuthCredentialsStoreMode::Ephemeral
|
||||
} else {
|
||||
auth_credentials_store_mode
|
||||
@@ -2072,19 +2073,19 @@ impl AuthManager {
|
||||
match (a, b) {
|
||||
(None, None) => true,
|
||||
(Some(a), Some(b)) => match (a.api_auth_mode(), b.api_auth_mode()) {
|
||||
(ApiAuthMode::ApiKey, ApiAuthMode::ApiKey) => a.api_key() == b.api_key(),
|
||||
(ApiAuthMode::Chatgpt, ApiAuthMode::Chatgpt)
|
||||
| (ApiAuthMode::ChatgptAuthTokens, ApiAuthMode::ChatgptAuthTokens) => {
|
||||
(AuthMode::ApiKey, AuthMode::ApiKey) => a.api_key() == b.api_key(),
|
||||
(AuthMode::Chatgpt, AuthMode::Chatgpt)
|
||||
| (AuthMode::ChatgptAuthTokens, AuthMode::ChatgptAuthTokens) => {
|
||||
a.get_current_auth_json() == b.get_current_auth_json()
|
||||
}
|
||||
(ApiAuthMode::AgentIdentity, ApiAuthMode::AgentIdentity) => match (a, b) {
|
||||
(AuthMode::AgentIdentity, AuthMode::AgentIdentity) => match (a, b) {
|
||||
(CodexAuth::AgentIdentity(a), CodexAuth::AgentIdentity(b)) => {
|
||||
a.record() == b.record()
|
||||
}
|
||||
_ => false,
|
||||
},
|
||||
(ApiAuthMode::PersonalAccessToken, ApiAuthMode::PersonalAccessToken) => a == b,
|
||||
(ApiAuthMode::BedrockApiKey, ApiAuthMode::BedrockApiKey) => a == b,
|
||||
(AuthMode::PersonalAccessToken, AuthMode::PersonalAccessToken) => a == b,
|
||||
(AuthMode::BedrockApiKey, AuthMode::BedrockApiKey) => a == b,
|
||||
_ => false,
|
||||
},
|
||||
_ => false,
|
||||
@@ -2401,13 +2402,15 @@ impl AuthManager {
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub fn get_api_auth_mode(&self) -> Option<ApiAuthMode> {
|
||||
/// Returns the precise kind of credentials backing the current authentication.
|
||||
pub fn get_api_auth_mode(&self) -> Option<AuthMode> {
|
||||
if self.has_external_api_key_auth() {
|
||||
return Some(ApiAuthMode::ApiKey);
|
||||
return Some(AuthMode::ApiKey);
|
||||
}
|
||||
self.auth_cached().as_ref().map(CodexAuth::api_auth_mode)
|
||||
}
|
||||
|
||||
/// Returns the effective backend auth mode for the current authentication.
|
||||
pub fn auth_mode(&self) -> Option<AuthMode> {
|
||||
if self.has_external_api_key_auth() {
|
||||
return Some(AuthMode::ApiKey);
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
use serde::Serialize;
|
||||
use std::time::Duration;
|
||||
|
||||
use codex_app_server_protocol::AuthMode as ApiAuthMode;
|
||||
use codex_client::CodexHttpClient;
|
||||
use codex_protocol::auth::AuthMode;
|
||||
|
||||
use super::manager::REFRESH_TOKEN_URL_OVERRIDE_ENV_VAR;
|
||||
use super::manager::REVOKE_TOKEN_URL;
|
||||
@@ -77,21 +77,21 @@ fn revocable_token(auth_dot_json: &AuthDotJson) -> Option<(&str, RevokeTokenKind
|
||||
}
|
||||
|
||||
fn managed_chatgpt_tokens(auth_dot_json: &AuthDotJson) -> Option<&TokenData> {
|
||||
if resolved_auth_mode(auth_dot_json) == ApiAuthMode::Chatgpt {
|
||||
if resolved_auth_mode(auth_dot_json) == AuthMode::Chatgpt {
|
||||
auth_dot_json.tokens.as_ref()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn resolved_auth_mode(auth_dot_json: &AuthDotJson) -> ApiAuthMode {
|
||||
fn resolved_auth_mode(auth_dot_json: &AuthDotJson) -> AuthMode {
|
||||
if let Some(mode) = auth_dot_json.auth_mode {
|
||||
return mode;
|
||||
}
|
||||
if auth_dot_json.openai_api_key.is_some() {
|
||||
return ApiAuthMode::ApiKey;
|
||||
return AuthMode::ApiKey;
|
||||
}
|
||||
ApiAuthMode::Chatgpt
|
||||
AuthMode::Chatgpt
|
||||
}
|
||||
|
||||
async fn revoke_oauth_token(
|
||||
|
||||
@@ -22,12 +22,12 @@ use super::BedrockApiKeyAuth;
|
||||
use crate::token_data::TokenData;
|
||||
use codex_agent_identity::AgentIdentityJwtClaims;
|
||||
use codex_agent_identity::decode_agent_identity_jwt;
|
||||
use codex_app_server_protocol::AuthMode;
|
||||
use codex_config::types::AuthCredentialsStoreMode;
|
||||
pub use codex_config::types::AuthKeyringBackendKind;
|
||||
use codex_keyring_store::DefaultKeyringStore;
|
||||
use codex_keyring_store::KeyringStore;
|
||||
use codex_protocol::account::PlanType as AccountPlanType;
|
||||
use codex_protocol::auth::AuthMode;
|
||||
use codex_secrets::LocalSecretsNamespace;
|
||||
use codex_secrets::SecretName;
|
||||
use codex_secrets::SecretScope;
|
||||
|
||||
@@ -36,8 +36,8 @@ use crate::token_data::TokenData;
|
||||
use crate::token_data::parse_chatgpt_jwt_claims;
|
||||
use base64::Engine;
|
||||
use chrono::Utc;
|
||||
use codex_app_server_protocol::AuthMode;
|
||||
use codex_config::types::AuthCredentialsStoreMode;
|
||||
use codex_protocol::auth::AuthMode;
|
||||
use codex_utils_template::Template;
|
||||
use rand::RngCore;
|
||||
use serde_json::Value as JsonValue;
|
||||
|
||||
@@ -3,7 +3,6 @@ use anyhow::Result;
|
||||
use base64::Engine;
|
||||
use chrono::Duration;
|
||||
use chrono::Utc;
|
||||
use codex_app_server_protocol::AuthMode;
|
||||
use codex_config::types::AuthCredentialsStoreMode;
|
||||
use codex_login::AuthDotJson;
|
||||
use codex_login::AuthKeyringBackendKind;
|
||||
@@ -15,6 +14,7 @@ use codex_login::load_auth_dot_json;
|
||||
use codex_login::save_auth;
|
||||
use codex_login::token_data::IdTokenInfo;
|
||||
use codex_login::token_data::TokenData;
|
||||
use codex_protocol::auth::AuthMode;
|
||||
use codex_protocol::auth::RefreshTokenFailedReason;
|
||||
use core_test_support::skip_if_no_network;
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use anyhow::Context;
|
||||
use anyhow::Result;
|
||||
use base64::Engine;
|
||||
use codex_app_server_protocol::AuthMode;
|
||||
use codex_config::types::AuthCredentialsStoreMode;
|
||||
use codex_login::AuthDotJson;
|
||||
use codex_login::AuthKeyringBackendKind;
|
||||
@@ -14,6 +13,7 @@ use codex_login::logout_with_revoke;
|
||||
use codex_login::save_auth;
|
||||
use codex_login::token_data::IdTokenInfo;
|
||||
use codex_login::token_data::TokenData;
|
||||
use codex_protocol::auth::AuthMode;
|
||||
use core_test_support::skip_if_no_network;
|
||||
use pretty_assertions::assert_eq;
|
||||
use serde_json::Value;
|
||||
|
||||
@@ -14,7 +14,6 @@ workspace = true
|
||||
|
||||
[dependencies]
|
||||
codex-api = { workspace = true }
|
||||
codex-app-server-protocol = { workspace = true }
|
||||
codex-protocol = { workspace = true }
|
||||
http = { workspace = true }
|
||||
schemars = { workspace = true }
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
use codex_api::Provider as ApiProvider;
|
||||
use codex_api::RetryConfig as ApiRetryConfig;
|
||||
use codex_api::is_azure_responses_provider;
|
||||
use codex_app_server_protocol::AuthMode;
|
||||
use codex_protocol::auth::AuthMode;
|
||||
use codex_protocol::config_types::ModelProviderAuthInfo;
|
||||
use codex_protocol::error::CodexErr;
|
||||
use codex_protocol::error::EnvVarError;
|
||||
|
||||
@@ -14,7 +14,6 @@ workspace = true
|
||||
|
||||
[dependencies]
|
||||
chrono = { workspace = true, features = ["serde"] }
|
||||
codex-app-server-protocol = { workspace = true }
|
||||
codex-collaboration-mode-templates = { workspace = true }
|
||||
codex-login = { workspace = true }
|
||||
codex-otel = { workspace = true }
|
||||
|
||||
@@ -6,7 +6,7 @@ pub mod model_info;
|
||||
pub mod model_presets;
|
||||
pub mod test_support;
|
||||
|
||||
pub use codex_app_server_protocol::AuthMode;
|
||||
pub use codex_protocol::auth::AuthMode;
|
||||
pub use config::ModelsManagerConfig;
|
||||
|
||||
/// Load the bundled model catalog shipped with `codex-models-manager`.
|
||||
|
||||
@@ -2,8 +2,8 @@ use super::cache::ModelsCacheManager;
|
||||
use crate::collaboration_mode_presets::builtin_collaboration_mode_presets;
|
||||
use crate::config::ModelsManagerConfig;
|
||||
use crate::model_info;
|
||||
use codex_app_server_protocol::AuthMode;
|
||||
use codex_login::AuthManager;
|
||||
use codex_protocol::auth::AuthMode;
|
||||
use codex_protocol::config_types::CollaborationModeMask;
|
||||
use codex_protocol::error::Result as CoreResult;
|
||||
use codex_protocol::openai_models::ModelInfo;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use super::*;
|
||||
use crate::ModelsManagerConfig;
|
||||
use chrono::Utc;
|
||||
use codex_app_server_protocol::AuthMode;
|
||||
use codex_login::AuthCredentialsStoreMode;
|
||||
use codex_login::AuthKeyringBackendKind;
|
||||
use codex_login::AuthManager;
|
||||
@@ -10,6 +9,7 @@ use codex_login::ExternalAuth;
|
||||
use codex_login::ExternalAuthRefreshContext;
|
||||
use codex_login::ExternalAuthTokens;
|
||||
use codex_login::TokenData;
|
||||
use codex_protocol::auth::AuthMode;
|
||||
use codex_protocol::openai_models::ModelsResponse;
|
||||
use pretty_assertions::assert_eq;
|
||||
use serde_json::json;
|
||||
|
||||
@@ -17,7 +17,6 @@ chrono = { workspace = true }
|
||||
codex-utils-absolute-path = { workspace = true }
|
||||
codex-utils-string = { workspace = true }
|
||||
codex-api = { workspace = true }
|
||||
codex-app-server-protocol = { workspace = true }
|
||||
codex-protocol = { workspace = true }
|
||||
eventsource-stream = { workspace = true }
|
||||
gethostname = { workspace = true }
|
||||
|
||||
@@ -8,6 +8,7 @@ mod otlp;
|
||||
mod targets;
|
||||
|
||||
use crate::metrics::Result as MetricsResult;
|
||||
use codex_protocol::auth::AuthMode;
|
||||
use serde::Serialize;
|
||||
use strum_macros::Display;
|
||||
|
||||
@@ -44,22 +45,21 @@ pub enum ToolDecisionSource {
|
||||
User,
|
||||
}
|
||||
|
||||
/// Maps to API/auth `AuthMode` to avoid a circular dependency on codex-core.
|
||||
/// Coarsens the authentication domain into the dimensions used by telemetry.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Display)]
|
||||
pub enum TelemetryAuthMode {
|
||||
ApiKey,
|
||||
Chatgpt,
|
||||
}
|
||||
|
||||
impl From<codex_app_server_protocol::AuthMode> for TelemetryAuthMode {
|
||||
fn from(mode: codex_app_server_protocol::AuthMode) -> Self {
|
||||
impl From<AuthMode> for TelemetryAuthMode {
|
||||
fn from(mode: AuthMode) -> Self {
|
||||
match mode {
|
||||
codex_app_server_protocol::AuthMode::ApiKey
|
||||
| codex_app_server_protocol::AuthMode::BedrockApiKey => Self::ApiKey,
|
||||
codex_app_server_protocol::AuthMode::Chatgpt
|
||||
| codex_app_server_protocol::AuthMode::ChatgptAuthTokens
|
||||
| codex_app_server_protocol::AuthMode::AgentIdentity
|
||||
| codex_app_server_protocol::AuthMode::PersonalAccessToken => Self::Chatgpt,
|
||||
AuthMode::ApiKey | AuthMode::BedrockApiKey => Self::ApiKey,
|
||||
AuthMode::Chatgpt
|
||||
| AuthMode::ChatgptAuthTokens
|
||||
| AuthMode::AgentIdentity
|
||||
| AuthMode::PersonalAccessToken => Self::Chatgpt,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,55 @@
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use strum_macros::Display;
|
||||
use thiserror::Error;
|
||||
|
||||
/// Authentication mode for OpenAI-backed providers.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Display, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum AuthMode {
|
||||
/// OpenAI API key provided by the caller and stored by Codex.
|
||||
ApiKey,
|
||||
/// ChatGPT OAuth managed by Codex (tokens persisted and refreshed by Codex).
|
||||
Chatgpt,
|
||||
/// ChatGPT auth tokens supplied by an external host application.
|
||||
#[serde(rename = "chatgptAuthTokens")]
|
||||
#[strum(serialize = "chatgptAuthTokens")]
|
||||
ChatgptAuthTokens,
|
||||
/// Programmatic Codex auth backed by a registered Agent Identity.
|
||||
#[serde(rename = "agentIdentity")]
|
||||
#[strum(serialize = "agentIdentity")]
|
||||
AgentIdentity,
|
||||
/// Programmatic Codex auth backed by a personal access token.
|
||||
#[serde(rename = "personalAccessToken")]
|
||||
#[strum(serialize = "personalAccessToken")]
|
||||
PersonalAccessToken,
|
||||
/// Amazon Bedrock bearer token managed by Codex.
|
||||
#[serde(rename = "bedrockApiKey")]
|
||||
#[strum(serialize = "bedrockApiKey")]
|
||||
BedrockApiKey,
|
||||
}
|
||||
|
||||
impl AuthMode {
|
||||
/// Returns whether this mode represents an authenticated human ChatGPT account.
|
||||
pub fn has_chatgpt_account(self) -> bool {
|
||||
match self {
|
||||
Self::Chatgpt | Self::ChatgptAuthTokens | Self::PersonalAccessToken => true,
|
||||
Self::ApiKey | Self::AgentIdentity | Self::BedrockApiKey => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns whether this mode is backed by Codex services rather than a direct model API.
|
||||
pub fn uses_codex_backend(self) -> bool {
|
||||
match self {
|
||||
Self::Chatgpt
|
||||
| Self::ChatgptAuthTokens
|
||||
| Self::AgentIdentity
|
||||
| Self::PersonalAccessToken => true,
|
||||
Self::ApiKey | Self::BedrockApiKey => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum PlanType {
|
||||
|
||||
@@ -32,7 +32,6 @@ use codex_app_server_client::RemoteAppServerConnectArgs;
|
||||
pub use codex_app_server_client::RemoteAppServerEndpoint;
|
||||
use codex_app_server_protocol::Account as AppServerAccount;
|
||||
use codex_app_server_protocol::AskForApproval;
|
||||
use codex_app_server_protocol::AuthMode as AppServerAuthMode;
|
||||
use codex_app_server_protocol::ConfigWarningNotification;
|
||||
use codex_app_server_protocol::Thread as AppServerThread;
|
||||
use codex_app_server_protocol::ThreadListCwdFilter;
|
||||
@@ -51,6 +50,7 @@ use codex_login::default_client::originator;
|
||||
use codex_login::default_client::set_default_client_residency_requirement;
|
||||
use codex_login::enforce_login_restrictions;
|
||||
use codex_protocol::ThreadId;
|
||||
use codex_protocol::auth::AuthMode;
|
||||
use codex_protocol::config_types::AltScreenMode;
|
||||
use codex_protocol::config_types::SandboxMode;
|
||||
#[cfg(target_os = "windows")]
|
||||
@@ -1869,7 +1869,7 @@ fn determine_alt_screen_mode(no_alt_screen: bool, tui_alternate_screen: AltScree
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum LoginStatus {
|
||||
AuthMode(AppServerAuthMode),
|
||||
AuthMode(AuthMode),
|
||||
NotAuthenticated,
|
||||
}
|
||||
|
||||
@@ -1886,8 +1886,8 @@ async fn get_login_status(
|
||||
|
||||
let account = app_server.read_account().await?;
|
||||
Ok(match account.account {
|
||||
Some(AppServerAccount::ApiKey {}) => LoginStatus::AuthMode(AppServerAuthMode::ApiKey),
|
||||
Some(AppServerAccount::Chatgpt { .. }) => LoginStatus::AuthMode(AppServerAuthMode::Chatgpt),
|
||||
Some(AppServerAccount::ApiKey {}) => LoginStatus::AuthMode(AuthMode::ApiKey),
|
||||
Some(AppServerAccount::Chatgpt { .. }) => LoginStatus::AuthMode(AuthMode::Chatgpt),
|
||||
Some(AppServerAccount::AmazonBedrock { .. }) => LoginStatus::NotAuthenticated,
|
||||
None => LoginStatus::NotAuthenticated,
|
||||
})
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
|
||||
use std::path::Path;
|
||||
|
||||
use codex_app_server_protocol::AuthMode;
|
||||
use codex_config::types::AuthCredentialsStoreMode;
|
||||
use codex_login::AuthKeyringBackendKind;
|
||||
use codex_login::load_auth_dot_json;
|
||||
use codex_protocol::auth::AuthMode;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub(crate) struct LocalChatgptAuth {
|
||||
@@ -64,11 +64,11 @@ mod tests {
|
||||
|
||||
use base64::Engine;
|
||||
use chrono::Utc;
|
||||
use codex_app_server_protocol::AuthMode;
|
||||
use codex_login::AuthDotJson;
|
||||
use codex_login::auth::login_with_chatgpt_auth_tokens;
|
||||
use codex_login::save_auth;
|
||||
use codex_login::token_data::TokenData;
|
||||
use codex_protocol::auth::AuthMode;
|
||||
use pretty_assertions::assert_eq;
|
||||
use serde::Serialize;
|
||||
use serde_json::json;
|
||||
|
||||
@@ -10,13 +10,13 @@
|
||||
use codex_app_server_client::AppServerRequestHandle;
|
||||
use codex_app_server_protocol::AccountLoginCompletedNotification;
|
||||
use codex_app_server_protocol::AccountUpdatedNotification;
|
||||
#[cfg(test)]
|
||||
use codex_app_server_protocol::AuthMode as AppServerAuthMode;
|
||||
use codex_app_server_protocol::AuthMode as ApiAuthMode;
|
||||
use codex_app_server_protocol::CancelLoginAccountParams;
|
||||
use codex_app_server_protocol::ClientRequest;
|
||||
use codex_app_server_protocol::LoginAccountParams;
|
||||
use codex_app_server_protocol::LoginAccountResponse;
|
||||
use codex_login::read_openai_api_key_from_env;
|
||||
use codex_protocol::auth::AuthMode;
|
||||
use crossterm::event::KeyCode;
|
||||
use crossterm::event::KeyEvent;
|
||||
use crossterm::event::KeyEventKind;
|
||||
@@ -945,7 +945,16 @@ impl AuthModeWidget {
|
||||
pub(crate) fn on_account_updated(&mut self, notification: AccountUpdatedNotification) {
|
||||
self.login_status = notification
|
||||
.auth_mode
|
||||
.map(LoginStatus::AuthMode)
|
||||
.map(|auth_mode| {
|
||||
LoginStatus::AuthMode(match auth_mode {
|
||||
ApiAuthMode::ApiKey => AuthMode::ApiKey,
|
||||
ApiAuthMode::Chatgpt => AuthMode::Chatgpt,
|
||||
ApiAuthMode::ChatgptAuthTokens => AuthMode::ChatgptAuthTokens,
|
||||
ApiAuthMode::AgentIdentity => AuthMode::AgentIdentity,
|
||||
ApiAuthMode::PersonalAccessToken => AuthMode::PersonalAccessToken,
|
||||
ApiAuthMode::BedrockApiKey => AuthMode::BedrockApiKey,
|
||||
})
|
||||
})
|
||||
.unwrap_or(LoginStatus::NotAuthenticated);
|
||||
}
|
||||
}
|
||||
@@ -1111,10 +1120,7 @@ mod tests {
|
||||
|
||||
#[tokio::test]
|
||||
async fn existing_non_oauth_chatgpt_login_counts_as_signed_in() {
|
||||
for auth_mode in [
|
||||
AppServerAuthMode::ChatgptAuthTokens,
|
||||
AppServerAuthMode::PersonalAccessToken,
|
||||
] {
|
||||
for auth_mode in [AuthMode::ChatgptAuthTokens, AuthMode::PersonalAccessToken] {
|
||||
let (mut widget, _tmp) = widget_forced_chatgpt().await;
|
||||
widget.login_status = LoginStatus::AuthMode(auth_mode);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user