mirror of
https://github.com/openai/codex.git
synced 2026-11-06 20:20:34 +00:00
Propagate authentication header failures before sending requests (#55607)
## Why Synchronous auth header construction could silently return no credentials when managed authentication became unavailable. Callers need an error to avoid sending requests with missing or partial authentication. ## What changed - Make `AuthProvider::add_auth_headers`, `to_auth_headers`, and auth header telemetry fallible, and propagate failures through request and WebSocket setup. - Return a transient error when managed authentication is unavailable, and preserve network policy denials through auth error conversion. - Retry transient MCP authentication errors while treating build errors and policy denials as terminal. - Cancel local MCP event streams before resolving authentication so cleanup still works when credentials become unavailable. ## Testing Add regression coverage for rejected partial authentication, async header resolution, terminal auth errors without sending requests, managed account changes, MCP retry classification, and local stream cancellation after authentication becomes unavailable. GitOrigin-RevId: 39d981e232cba1e302de502a2fa6239101114ed1
This commit is contained in:
@@ -139,7 +139,9 @@ mod tests {
|
||||
struct DummyAuth;
|
||||
|
||||
impl AuthProvider for DummyAuth {
|
||||
fn add_auth_headers(&self, _headers: &mut HeaderMap) {}
|
||||
fn add_auth_headers(&self, _headers: &mut HeaderMap) -> Result<(), crate::AuthError> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
||||
@@ -102,7 +102,9 @@ mod tests {
|
||||
struct DummyAuth;
|
||||
|
||||
impl AuthProvider for DummyAuth {
|
||||
fn add_auth_headers(&self, _headers: &mut HeaderMap) {}
|
||||
fn add_auth_headers(&self, _headers: &mut HeaderMap) -> Result<(), crate::AuthError> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
||||
@@ -184,7 +184,9 @@ mod tests {
|
||||
struct DummyAuth;
|
||||
|
||||
impl AuthProvider for DummyAuth {
|
||||
fn add_auth_headers(&self, _headers: &mut HeaderMap) {}
|
||||
fn add_auth_headers(&self, _headers: &mut HeaderMap) -> Result<(), crate::AuthError> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
@@ -193,8 +195,9 @@ mod tests {
|
||||
}
|
||||
|
||||
impl AuthProvider for RetryAuth {
|
||||
fn add_auth_headers(&self, headers: &mut HeaderMap) {
|
||||
fn add_auth_headers(&self, headers: &mut HeaderMap) -> Result<(), AuthError> {
|
||||
headers.insert(http::header::AUTHORIZATION, "Bearer test".parse().unwrap());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn apply_auth(&self, mut request: Request) -> AuthProviderFuture<'_> {
|
||||
@@ -204,7 +207,7 @@ mod tests {
|
||||
if limits.len() == 1 {
|
||||
return Err(AuthError::Transient("retry authentication".to_string()));
|
||||
}
|
||||
self.add_auth_headers(&mut request.headers);
|
||||
self.add_auth_headers(&mut request.headers)?;
|
||||
Ok(request)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -360,11 +360,12 @@ mod tests {
|
||||
struct DummyAuth;
|
||||
|
||||
impl AuthProvider for DummyAuth {
|
||||
fn add_auth_headers(&self, headers: &mut HeaderMap) {
|
||||
fn add_auth_headers(&self, headers: &mut HeaderMap) -> Result<(), crate::AuthError> {
|
||||
headers.insert(
|
||||
http::header::AUTHORIZATION,
|
||||
HeaderValue::from_static("Bearer test-token"),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -466,7 +466,7 @@ impl ResponsesWebsocketClient {
|
||||
|
||||
let mut headers =
|
||||
merge_request_headers(&self.provider.headers, extra_headers, default_headers);
|
||||
self.auth.add_auth_headers(&mut headers);
|
||||
self.auth.add_auth_headers(&mut headers)?;
|
||||
|
||||
let connector = WebSocketConnector::new(http_client_factory)
|
||||
.map_err(|err| ApiError::Stream(format!("failed to configure websocket TLS: {err}")))?;
|
||||
|
||||
@@ -35,7 +35,7 @@ impl ResponsesWebsocketClient {
|
||||
.map_err(|err| ApiError::Stream(format!("failed to build websocket URL: {err}")))?;
|
||||
let mut headers =
|
||||
merge_request_headers(&self.provider.headers, extra_headers, default_headers);
|
||||
self.auth.add_auth_headers(&mut headers);
|
||||
self.auth.add_auth_headers(&mut headers)?;
|
||||
let (stream, _status, server_reasoning_included, server_model) =
|
||||
connect_websocket(ws_url, headers, connector, turn_state).await?;
|
||||
Ok(ResponsesWebsocketConnection::new(
|
||||
|
||||
@@ -83,7 +83,9 @@ mod tests {
|
||||
struct DummyAuth;
|
||||
|
||||
impl AuthProvider for DummyAuth {
|
||||
fn add_auth_headers(&self, _headers: &mut HeaderMap) {}
|
||||
fn add_auth_headers(&self, _headers: &mut HeaderMap) -> Result<(), crate::AuthError> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
||||
Reference in New Issue
Block a user