diff --git a/codex-rs/app-server/src/message_processor.rs b/codex-rs/app-server/src/message_processor.rs index f950661180..f45f9d554e 100644 --- a/codex-rs/app-server/src/message_processor.rs +++ b/codex-rs/app-server/src/message_processor.rs @@ -38,6 +38,7 @@ use crate::thread_state::ThreadStateManager; use crate::transport::AppServerTransport; use crate::transport::RemoteControlHandle; use async_trait::async_trait; +use axum::http::HeaderValue; use codex_analytics::AnalyticsEventsClient; use codex_analytics::AppServerRpcTransport; use codex_app_server_protocol::AttestationGenerateParams; @@ -181,7 +182,7 @@ impl std::fmt::Debug for AppServerAttestationProvider { } impl AttestationProvider for AppServerAttestationProvider { - fn generate_header_value(&self, context: AttestationContext) -> GenerateAttestationFuture<'_> { + fn header_for_request(&self, context: AttestationContext) -> GenerateAttestationFuture<'_> { let outgoing = self.outgoing.clone(); let attestation_connection_ids = self.attestation_connection_ids.clone(); Box::pin(async move { @@ -195,6 +196,7 @@ impl AttestationProvider for AppServerAttestationProvider { ATTESTATION_GENERATE_TIMEOUT, ) .await + .and_then(|value| HeaderValue::from_bytes(value.as_bytes()).ok()) }) } } diff --git a/codex-rs/core/src/attestation.rs b/codex-rs/core/src/attestation.rs index 8e5bdcf538..01d4e72e4e 100644 --- a/codex-rs/core/src/attestation.rs +++ b/codex-rs/core/src/attestation.rs @@ -1,9 +1,12 @@ use std::future::Future; use std::pin::Pin; +use http::HeaderValue; + pub(crate) const X_OAI_ATTESTATION_HEADER: &str = "x-oai-attestation"; -pub type GenerateAttestationFuture<'a> = Pin> + Send + 'a>>; +pub type GenerateAttestationFuture<'a> = + Pin> + Send + 'a>>; /// Request context that host integrations can use when deciding whether to /// generate an attestation header value. @@ -15,8 +18,7 @@ pub struct AttestationContext { /// Host integration boundary for just-in-time attestation header values. /// /// Implementations own the policy for when attestation should be attempted and -/// return the opaque string expected by the upstream `x-oai-attestation` -/// header. Core only forwards valid HTTP header values returned by the host. +/// return the upstream `x-oai-attestation` header value when one should be sent. pub trait AttestationProvider: std::fmt::Debug + Send + Sync { - fn generate_header_value(&self, context: AttestationContext) -> GenerateAttestationFuture<'_>; + fn header_for_request(&self, context: AttestationContext) -> GenerateAttestationFuture<'_>; } diff --git a/codex-rs/core/src/client.rs b/codex-rs/core/src/client.rs index 21b69064a7..ab850770ca 100644 --- a/codex-rs/core/src/client.rs +++ b/codex-rs/core/src/client.rs @@ -657,11 +657,10 @@ impl ModelClient { self.state .attestation_provider .as_ref()? - .generate_header_value(AttestationContext { + .header_for_request(AttestationContext { uses_chatgpt_auth: provider.uses_chatgpt_auth, }) .await - .and_then(|value| HeaderValue::from_str(&value).ok()) } /// Builds request telemetry for unary API calls (e.g., Compact endpoint). diff --git a/codex-rs/core/src/client_tests.rs b/codex-rs/core/src/client_tests.rs index 38058e2baa..55b0c227c6 100644 --- a/codex-rs/core/src/client_tests.rs +++ b/codex-rs/core/src/client_tests.rs @@ -502,10 +502,7 @@ fn model_client_with_counting_attestation() -> (ModelClient, Arc) { } impl AttestationProvider for CountingAttestationProvider { - fn generate_header_value( - &self, - context: AttestationContext, - ) -> GenerateAttestationFuture<'_> { + fn header_for_request(&self, context: AttestationContext) -> GenerateAttestationFuture<'_> { let calls = self.calls.clone(); Box::pin(async move { if !context.uses_chatgpt_auth { @@ -513,7 +510,7 @@ fn model_client_with_counting_attestation() -> (ModelClient, Arc) { } let call = calls.fetch_add(1, Ordering::Relaxed) + 1; - Some(format!("v1.header-{call}")) + Some(http::HeaderValue::from_bytes(format!("v1.header-{call}").as_bytes()).unwrap()) }) } }