[codex] Remove async_trait from first-party code (#27475)

## Why

First-party async traits should expose their `Send` contracts explicitly
without requiring `async_trait`. This completes the migration pattern
established in #27303 and #27304.

## What changed

- Replaced the remaining first-party `async_trait` traits with native
return-position `impl Future + Send` where statically dispatched and
explicit boxed `Send` futures where object safety is required.
- Kept implementations behavior-preserving, outlining existing async
bodies into inherent methods where that keeps the diff reviewable.
- Removed all direct first-party `async-trait` dependencies and the
workspace dependency declaration.
- Added a cargo-deny policy that permits `async-trait` only through the
remaining transitive wrapper crates.
- Updated `rand` from 0.8.5 to 0.8.6 to resolve RUSTSEC-2026-0097 and
keep the full cargo-deny check passing.

## Validation

- `just test -p codex-exec-server`: 216 passed, 2 skipped.
- `just test -p codex-model-provider`: 39 passed.
- `just test -p codex-core` and `just test`: changed tests passed;
remaining failures are environment-sensitive suites unrelated to this
migration.
- `cargo deny check`
- `just fix`
- `just fmt`
- `cargo shear`
- `just bazel-lock-check`
This commit is contained in:
Adam Perry @ OpenAI authored and GitHub committed 2026-06-11 18:16:39 -07:00
1 parent 1829ed1122
commit 5a56caf18c
98 files changed
+2010 -1050

No files matched your search

-1
View File
@@ -8,7 +8,6 @@ license.workspace = true
workspace = true
[dependencies]
async-trait = { workspace = true }
base64 = { workspace = true }
chrono = { workspace = true, features = ["serde"] }
codex-agent-identity = { workspace = true }
+18 -8
View File
@@ -1,7 +1,7 @@
use super::manager::ExternalAuth;
use super::manager::ExternalAuthFuture;
use super::manager::ExternalAuthRefreshContext;
use super::manager::ExternalAuthTokens;
use async_trait::async_trait;
use codex_app_server_protocol::AuthMode;
use codex_protocol::config_types::ModelProviderAuthInfo;
use std::fmt;
@@ -25,13 +25,6 @@ impl BearerTokenRefresher {
state: Arc::new(ExternalBearerAuthState::new(config)),
}
}
}
#[async_trait]
impl ExternalAuth for BearerTokenRefresher {
fn auth_mode(&self) -> AuthMode {
AuthMode::ApiKey
}
#[expect(
clippy::await_holding_invalid_type,
@@ -76,6 +69,23 @@ impl ExternalAuth for BearerTokenRefresher {
}
}
impl ExternalAuth for BearerTokenRefresher {
fn auth_mode(&self) -> AuthMode {
AuthMode::ApiKey
}
fn resolve(&self) -> ExternalAuthFuture<'_, Option<ExternalAuthTokens>> {
Box::pin(BearerTokenRefresher::resolve(self))
}
fn refresh(
&self,
context: ExternalAuthRefreshContext,
) -> ExternalAuthFuture<'_, ExternalAuthTokens> {
Box::pin(BearerTokenRefresher::refresh(self, context))
}
}
impl fmt::Debug for BearerTokenRefresher {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("BearerTokenRefresher")
+8 -6
View File
@@ -1,4 +1,3 @@
use async_trait::async_trait;
use chrono::Utc;
use reqwest::StatusCode;
use serde::Deserialize;
@@ -7,8 +6,10 @@ use serde::Serialize;
use serial_test::serial;
use std::env;
use std::fmt::Debug;
use std::future::Future;
use std::path::Path;
use std::path::PathBuf;
use std::pin::Pin;
use std::sync::Arc;
use std::sync::Mutex;
use std::sync::RwLock;
@@ -167,7 +168,6 @@ pub struct ExternalAuthRefreshContext {
pub previous_account_id: Option<String>,
}
#[async_trait]
/// Pluggable auth provider used by `AuthManager` for externally managed auth flows.
///
/// Implementations may either resolve auth eagerly via `resolve()` or provide refreshed
@@ -178,17 +178,19 @@ pub trait ExternalAuth: Send + Sync {
/// Returns cached or immediately available auth, if this provider can resolve it synchronously
/// from the caller's perspective.
async fn resolve(&self) -> std::io::Result<Option<ExternalAuthTokens>> {
Ok(None)
fn resolve(&self) -> ExternalAuthFuture<'_, Option<ExternalAuthTokens>> {
Box::pin(async { Ok(None) })
}
/// Refreshes auth in response to a manager-driven refresh attempt.
async fn refresh(
fn refresh(
&self,
context: ExternalAuthRefreshContext,
) -> std::io::Result<ExternalAuthTokens>;
) -> ExternalAuthFuture<'_, ExternalAuthTokens>;
}
pub type ExternalAuthFuture<'a, T> = Pin<Box<dyn Future<Output = std::io::Result<T>> + Send + 'a>>;
impl RefreshTokenError {
pub fn failed_reason(&self) -> Option<RefreshTokenFailedReason> {
match self {
+1
View File
@@ -27,6 +27,7 @@ pub use auth::CODEX_API_KEY_ENV_VAR;
pub use auth::CodexAuth;
pub use auth::ExternalAuth;
pub use auth::ExternalAuthChatgptMetadata;
pub use auth::ExternalAuthFuture;
pub use auth::ExternalAuthRefreshContext;
pub use auth::ExternalAuthRefreshReason;
pub use auth::ExternalAuthTokens;