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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion codex-rs/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions codex-rs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ members = [
"thread-store",
"codex-experimental-api-macros",
"plugin",
"model-provider",
]
resolver = "2"

Expand Down Expand Up @@ -154,6 +155,7 @@ codex-network-proxy = { path = "network-proxy" }
codex-ollama = { path = "ollama" }
codex-otel = { path = "otel" }
codex-plugin = { path = "plugin" }
codex-model-provider = { path = "model-provider" }
codex-process-hardening = { path = "process-hardening" }
codex-protocol = { path = "protocol" }
codex-realtime-webrtc = { path = "realtime-webrtc" }
Expand Down
1 change: 1 addition & 0 deletions codex-rs/cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ codex-features = { workspace = true }
codex-login = { workspace = true }
codex-mcp = { workspace = true }
codex-mcp-server = { workspace = true }
codex-model-provider = { workspace = true }
codex-protocol = { workspace = true }
codex-responses-api-proxy = { workspace = true }
codex-rmcp-client = { workspace = true }
Expand Down
14 changes: 4 additions & 10 deletions codex-rs/cli/src/responses_cmd.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use clap::Parser;
use codex_core::config::Config;
use codex_model_provider::create_model_provider;
use codex_utils_cli::CliConfigOverrides;
use serde_json::json;
use tokio::io::AsyncReadExt;
Expand Down Expand Up @@ -29,16 +30,9 @@ pub(crate) async fn run_responses_command(
let base_auth_manager = codex_login::AuthManager::shared_from_config(
&config, /*enable_codex_api_key_env*/ true,
);
let auth_manager =
codex_login::auth_manager_for_provider(Some(base_auth_manager), &config.model_provider);
let auth = match auth_manager {
Some(auth_manager) => auth_manager.auth().await,
None => None,
};
let api_provider = config
.model_provider
.to_api_provider(auth.as_ref().map(codex_login::CodexAuth::auth_mode))?;
let api_auth = codex_login::auth_provider_from_auth(auth, &config.model_provider)?;
let model_provider = create_model_provider(config.model_provider, Some(base_auth_manager));
let api_provider = model_provider.api_provider().await?;
let api_auth = model_provider.api_auth().await?;
let client = codex_api::ResponsesClient::new(
codex_api::ReqwestTransport::new(codex_login::default_client::build_reqwest_client()),
api_provider,
Expand Down
47 changes: 0 additions & 47 deletions codex-rs/codex-api/src/api_bridge.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use crate::AuthProvider as ApiAuthProvider;
use crate::TransportError;
use crate::error::ApiError;
use crate::rate_limits::parse_promo_message;
Expand All @@ -12,7 +11,6 @@ use codex_protocol::error::RetryLimitReachedError;
use codex_protocol::error::UnexpectedResponseError;
use codex_protocol::error::UsageLimitReachedError;
use http::HeaderMap;
use http::HeaderValue;
use serde::Deserialize;
use serde_json::Value;

Expand Down Expand Up @@ -174,48 +172,3 @@ struct UsageErrorBody {
plan_type: Option<PlanType>,
resets_at: Option<i64>,
}

#[derive(Clone, Default)]
pub struct CoreAuthProvider {
pub token: Option<String>,
pub account_id: Option<String>,
pub is_fedramp_account: bool,
}

impl CoreAuthProvider {
pub fn auth_header_attached(&self) -> bool {
self.token
.as_ref()
.is_some_and(|token| http::HeaderValue::from_str(&format!("Bearer {token}")).is_ok())
}

pub fn auth_header_name(&self) -> Option<&'static str> {
self.auth_header_attached().then_some("authorization")
}

pub fn for_test(token: Option<&str>, account_id: Option<&str>) -> Self {
Self {
token: token.map(str::to_string),
account_id: account_id.map(str::to_string),
is_fedramp_account: false,
}
}
}

impl ApiAuthProvider for CoreAuthProvider {
fn add_auth_headers(&self, headers: &mut HeaderMap) {
if let Some(token) = self.token.as_ref()
&& let Ok(header) = HeaderValue::from_str(&format!("Bearer {token}"))
{
let _ = headers.insert(http::header::AUTHORIZATION, header);
}
if let Some(account_id) = self.account_id.as_ref()
&& let Ok(header) = HeaderValue::from_str(account_id)
{
let _ = headers.insert("ChatGPT-Account-ID", header);
}
if self.is_fedramp_account {
crate::auth::add_fedramp_routing_header(headers);
}
}
}
52 changes: 0 additions & 52 deletions codex-rs/codex-api/src/api_bridge_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,55 +130,3 @@ fn map_api_error_extracts_identity_auth_details_from_headers() {
);
assert_eq!(err.identity_error_code.as_deref(), Some("token_expired"));
}

#[test]
fn core_auth_provider_reports_when_auth_header_will_attach() {
let auth = CoreAuthProvider {
token: Some("access-token".to_string()),
account_id: None,
is_fedramp_account: false,
};

assert!(auth.auth_header_attached());
assert_eq!(auth.auth_header_name(), Some("authorization"));
}

#[test]
fn core_auth_provider_adds_auth_headers() {
let auth = CoreAuthProvider::for_test(Some("access-token"), Some("workspace-123"));
let mut headers = HeaderMap::new();

crate::AuthProvider::add_auth_headers(&auth, &mut headers);

assert_eq!(
headers
.get(http::header::AUTHORIZATION)
.and_then(|value| value.to_str().ok()),
Some("Bearer access-token")
);
assert_eq!(
headers
.get("ChatGPT-Account-ID")
.and_then(|value| value.to_str().ok()),
Some("workspace-123")
);
}

#[test]
fn core_auth_provider_adds_fedramp_routing_header_for_fedramp_accounts() {
let auth = CoreAuthProvider {
token: Some("access-token".to_string()),
account_id: Some("workspace-123".to_string()),
is_fedramp_account: true,
};
let mut headers = HeaderMap::new();

crate::AuthProvider::add_auth_headers(&auth, &mut headers);

assert_eq!(
headers
.get("X-OpenAI-Fedramp")
.and_then(|value| value.to_str().ok()),
Some("true")
);
}
36 changes: 17 additions & 19 deletions codex-rs/codex-api/src/auth.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use http::HeaderMap;
use http::HeaderValue;
use std::sync::Arc;

/// Adds authentication headers to API requests.
///
Expand All @@ -10,25 +10,23 @@ pub trait AuthProvider: Send + Sync {
fn add_auth_headers(&self, headers: &mut HeaderMap);
}

pub(crate) fn add_fedramp_routing_header(headers: &mut HeaderMap) {
headers.insert("X-OpenAI-Fedramp", HeaderValue::from_static("true"));
}

#[cfg(test)]
mod tests {
use super::*;
/// Shared auth handle passed through API clients.
pub type SharedAuthProvider = Arc<dyn AuthProvider>;

#[test]
fn add_fedramp_routing_header_sets_header() {
let mut headers = HeaderMap::new();

add_fedramp_routing_header(&mut headers);
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct AuthHeaderTelemetry {
pub attached: bool,
pub name: Option<&'static str>,
}

assert_eq!(
headers
.get("X-OpenAI-Fedramp")
.and_then(|v| v.to_str().ok()),
Some("true")
);
pub fn auth_header_telemetry(auth: &dyn AuthProvider) -> AuthHeaderTelemetry {
let mut headers = HeaderMap::new();
auth.add_auth_headers(&mut headers);
let name = headers
.contains_key(http::header::AUTHORIZATION)
.then_some("authorization");
AuthHeaderTelemetry {
attached: name.is_some(),
name,
}
}
22 changes: 6 additions & 16 deletions codex-rs/codex-api/src/endpoint/compact.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::auth::AuthProvider;
use crate::auth::SharedAuthProvider;
use crate::common::CompactionInput;
use crate::endpoint::session::EndpointSession;
use crate::error::ApiError;
Expand All @@ -12,12 +12,12 @@ use serde::Deserialize;
use serde_json::to_value;
use std::sync::Arc;

pub struct CompactClient<T: HttpTransport, A: AuthProvider> {
session: EndpointSession<T, A>,
pub struct CompactClient<T: HttpTransport> {
session: EndpointSession<T>,
}

impl<T: HttpTransport, A: AuthProvider> CompactClient<T, A> {
pub fn new(transport: T, provider: Provider, auth: A) -> Self {
impl<T: HttpTransport> CompactClient<T> {
pub fn new(transport: T, provider: Provider, auth: SharedAuthProvider) -> Self {
Self {
session: EndpointSession::new(transport, provider, auth),
}
Expand Down Expand Up @@ -86,18 +86,8 @@ mod tests {
}
}

#[derive(Clone, Default)]
struct DummyAuth;

impl AuthProvider for DummyAuth {
fn add_auth_headers(&self, _headers: &mut HeaderMap) {}
}

#[test]
fn path_is_responses_compact() {
assert_eq!(
CompactClient::<DummyTransport, DummyAuth>::path(),
"responses/compact"
);
assert_eq!(CompactClient::<DummyTransport>::path(), "responses/compact");
}
}
15 changes: 8 additions & 7 deletions codex-rs/codex-api/src/endpoint/memories.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::auth::AuthProvider;
use crate::auth::SharedAuthProvider;
use crate::common::MemorySummarizeInput;
use crate::common::MemorySummarizeOutput;
use crate::endpoint::session::EndpointSession;
Expand All @@ -12,12 +12,12 @@ use serde::Deserialize;
use serde_json::to_value;
use std::sync::Arc;

pub struct MemoriesClient<T: HttpTransport, A: AuthProvider> {
session: EndpointSession<T, A>,
pub struct MemoriesClient<T: HttpTransport> {
session: EndpointSession<T>,
}

impl<T: HttpTransport, A: AuthProvider> MemoriesClient<T, A> {
pub fn new(transport: T, provider: Provider, auth: A) -> Self {
impl<T: HttpTransport> MemoriesClient<T> {
pub fn new(transport: T, provider: Provider, auth: SharedAuthProvider) -> Self {
Self {
session: EndpointSession::new(transport, provider, auth),
}
Expand Down Expand Up @@ -67,6 +67,7 @@ struct SummarizeResponse {
#[cfg(test)]
mod tests {
use super::*;
use crate::auth::AuthProvider;
use crate::common::RawMemory;
use crate::common::RawMemoryMetadata;
use crate::provider::RetryConfig;
Expand Down Expand Up @@ -157,7 +158,7 @@ mod tests {
#[test]
fn path_is_memories_trace_summarize_for_wire_compatibility() {
assert_eq!(
MemoriesClient::<DummyTransport, DummyAuth>::path(),
MemoriesClient::<DummyTransport>::path(),
"memories/trace_summarize"
);
}
Expand All @@ -178,7 +179,7 @@ mod tests {
let client = MemoriesClient::new(
transport.clone(),
provider("https://example.com/api/codex"),
DummyAuth,
Arc::new(DummyAuth),
);

let input = MemorySummarizeInput {
Expand Down
Loading
Loading