mirror of
https://github.com/openai/codex.git
synced 2026-10-23 18:08:45 +00:00
feat(core): send attestation for ChatGPT compaction and realtime setup
This commit is contained in:
@@ -118,6 +118,7 @@ use codex_login::auth_env_telemetry::AuthEnvTelemetry;
|
||||
use codex_login::auth_env_telemetry::collect_auth_env_telemetry;
|
||||
use codex_model_provider::SharedModelProvider;
|
||||
use codex_model_provider::create_model_provider;
|
||||
use codex_model_provider_info::CHATGPT_CODEX_BASE_URL;
|
||||
#[cfg(test)]
|
||||
use codex_model_provider_info::DEFAULT_WEBSOCKET_CONNECT_TIMEOUT_MS;
|
||||
use codex_model_provider_info::ModelProviderInfo;
|
||||
@@ -424,6 +425,8 @@ impl ModelClient {
|
||||
return Ok(Vec::new());
|
||||
}
|
||||
let client_setup = self.current_client_setup().await?;
|
||||
let should_send_attestation =
|
||||
should_send_attestation(&client_setup.api_provider, AttestationPurpose::Compaction);
|
||||
let transport = ReqwestTransport::new(build_reqwest_client());
|
||||
let request_telemetry = Self::build_request_telemetry(
|
||||
session_telemetry,
|
||||
@@ -477,6 +480,9 @@ impl ModelClient {
|
||||
extra_headers.extend(build_conversation_headers(Some(
|
||||
self.state.conversation_id.to_string(),
|
||||
)));
|
||||
if should_send_attestation && let Some(header_value) = macos_devicecheck_header() {
|
||||
extra_headers.insert(X_OAI_ATTESTATION_HEADER, header_value);
|
||||
}
|
||||
let trace_attempt = compaction_trace.start_attempt(&payload);
|
||||
let result = client
|
||||
.compact_input(&payload, extra_headers)
|
||||
@@ -495,10 +501,18 @@ impl ModelClient {
|
||||
// Create the media call over HTTP first, then retain matching auth so realtime can attach
|
||||
// the server-side control WebSocket to the call id from that HTTP response.
|
||||
let client_setup = self.current_client_setup().await?;
|
||||
let should_send_attestation = should_send_attestation(
|
||||
&client_setup.api_provider,
|
||||
AttestationPurpose::RealtimeWebrtcCallSetup,
|
||||
);
|
||||
let mut sideband_headers = extra_headers.clone();
|
||||
sideband_headers.extend(sideband_websocket_auth_headers(
|
||||
client_setup.api_auth.as_ref(),
|
||||
));
|
||||
let mut extra_headers = extra_headers;
|
||||
if should_send_attestation && let Some(header_value) = macos_devicecheck_header() {
|
||||
extra_headers.insert(X_OAI_ATTESTATION_HEADER, header_value);
|
||||
}
|
||||
let transport = ReqwestTransport::new(build_reqwest_client());
|
||||
let response =
|
||||
ApiRealtimeCallClient::new(transport, client_setup.api_provider, client_setup.api_auth)
|
||||
@@ -1627,18 +1641,32 @@ fn build_responses_headers(
|
||||
headers
|
||||
}
|
||||
|
||||
fn provider_base_url_is_chatgpt_codex(provider: &codex_api::Provider) -> bool {
|
||||
provider
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
enum AttestationPurpose {
|
||||
Response,
|
||||
Compaction,
|
||||
RealtimeWebrtcCallSetup,
|
||||
}
|
||||
|
||||
fn should_send_attestation(provider: &codex_api::Provider, purpose: AttestationPurpose) -> bool {
|
||||
let provider_is_chatgpt_codex = provider
|
||||
.base_url
|
||||
.trim_end_matches('/')
|
||||
.eq_ignore_ascii_case("https://chatgpt.com/backend-api/codex")
|
||||
.eq_ignore_ascii_case(CHATGPT_CODEX_BASE_URL);
|
||||
provider_is_chatgpt_codex
|
||||
&& matches!(
|
||||
purpose,
|
||||
AttestationPurpose::Response
|
||||
| AttestationPurpose::Compaction
|
||||
| AttestationPurpose::RealtimeWebrtcCallSetup
|
||||
)
|
||||
}
|
||||
|
||||
fn extend_devicecheck_header_for_responses_endpoint(
|
||||
headers: &mut ApiHeaderMap,
|
||||
provider: &codex_api::Provider,
|
||||
) {
|
||||
if provider_base_url_is_chatgpt_codex(provider)
|
||||
if should_send_attestation(provider, AttestationPurpose::Response)
|
||||
&& let Some(header_value) = macos_devicecheck_header()
|
||||
{
|
||||
headers.insert(X_OAI_ATTESTATION_HEADER, header_value);
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
use super::AttestationPurpose;
|
||||
use super::AttestationPurpose;
|
||||
use super::AuthRequestTelemetryContext;
|
||||
use super::ModelClient;
|
||||
use super::PendingUnauthorizedRetry;
|
||||
@@ -8,7 +10,9 @@ use super::X_CODEX_TURN_METADATA_HEADER;
|
||||
use super::X_CODEX_WINDOW_ID_HEADER;
|
||||
use super::X_OPENAI_SUBAGENT_HEADER;
|
||||
use codex_api::ApiError;
|
||||
use codex_api::Provider as ApiProvider;
|
||||
use codex_api::ResponseEvent;
|
||||
use codex_api::RetryConfig as ApiRetryConfig;
|
||||
use codex_app_server_protocol::AuthMode;
|
||||
use codex_model_provider::BearerAuthProvider;
|
||||
use codex_model_provider_info::WireApi;
|
||||
@@ -383,3 +387,43 @@ fn auth_request_telemetry_context_tracks_attached_auth_and_retry_phase() {
|
||||
assert_eq!(auth_context.recovery_mode, Some("managed"));
|
||||
assert_eq!(auth_context.recovery_phase, Some("refresh_token"));
|
||||
}
|
||||
|
||||
fn api_provider(base_url: &str) -> ApiProvider {
|
||||
ApiProvider {
|
||||
name: "test".to_string(),
|
||||
base_url: base_url.to_string(),
|
||||
query_params: None,
|
||||
headers: http::HeaderMap::new(),
|
||||
retry: ApiRetryConfig {
|
||||
max_attempts: 1,
|
||||
base_delay: Duration::from_millis(1),
|
||||
retry_429: false,
|
||||
retry_5xx: true,
|
||||
retry_transport: true,
|
||||
},
|
||||
stream_idle_timeout: Duration::from_secs(1),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_send_attestation_for_allowed_chatgpt_codex_purposes() {
|
||||
let provider = api_provider("https://chatgpt.com/backend-api/codex/");
|
||||
|
||||
for purpose in [
|
||||
AttestationPurpose::Response,
|
||||
AttestationPurpose::Compaction,
|
||||
AttestationPurpose::RealtimeWebrtcCallSetup,
|
||||
] {
|
||||
assert!(super::should_send_attestation(&provider, purpose));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_not_send_attestation_for_non_chatgpt_codex_provider() {
|
||||
let provider = api_provider("https://api.openai.com/v1");
|
||||
|
||||
assert!(!super::should_send_attestation(
|
||||
&provider,
|
||||
AttestationPurpose::Response,
|
||||
));
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ const MAX_REQUEST_MAX_RETRIES: u64 = 100;
|
||||
|
||||
const OPENAI_PROVIDER_NAME: &str = "OpenAI";
|
||||
pub const OPENAI_PROVIDER_ID: &str = "openai";
|
||||
pub const CHATGPT_CODEX_BASE_URL: &str = "https://chatgpt.com/backend-api/codex";
|
||||
const AMAZON_BEDROCK_PROVIDER_NAME: &str = "Amazon Bedrock";
|
||||
pub const AMAZON_BEDROCK_PROVIDER_ID: &str = "amazon-bedrock";
|
||||
pub const AMAZON_BEDROCK_DEFAULT_BASE_URL: &str =
|
||||
@@ -234,7 +235,7 @@ impl ModelProviderInfo {
|
||||
auth_mode,
|
||||
Some(AuthMode::Chatgpt | AuthMode::ChatgptAuthTokens | AuthMode::AgentIdentity)
|
||||
) {
|
||||
"https://chatgpt.com/backend-api/codex"
|
||||
CHATGPT_CODEX_BASE_URL
|
||||
} else {
|
||||
"https://api.openai.com/v1"
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user