codex_login/
auth_env_telemetry.rs1use codex_model_provider_info::ModelProviderInfo;
2use codex_otel::AuthEnvTelemetryMetadata;
3
4use crate::CODEX_API_KEY_ENV_VAR;
5use crate::OPENAI_API_KEY_ENV_VAR;
6use crate::REFRESH_TOKEN_URL_OVERRIDE_ENV_VAR;
7
8#[derive(Debug, Clone, Default, PartialEq, Eq)]
9pub struct AuthEnvTelemetry {
10 pub openai_api_key_env_present: bool,
11 pub codex_api_key_env_present: bool,
12 pub codex_api_key_env_enabled: bool,
13 pub provider_env_key_name: Option<String>,
14 pub provider_env_key_present: Option<bool>,
15 pub refresh_token_url_override_present: bool,
16}
17
18impl AuthEnvTelemetry {
19 pub fn to_otel_metadata(&self) -> AuthEnvTelemetryMetadata {
20 AuthEnvTelemetryMetadata {
21 openai_api_key_env_present: self.openai_api_key_env_present,
22 codex_api_key_env_present: self.codex_api_key_env_present,
23 codex_api_key_env_enabled: self.codex_api_key_env_enabled,
24 provider_env_key_name: self.provider_env_key_name.clone(),
25 provider_env_key_present: self.provider_env_key_present,
26 refresh_token_url_override_present: self.refresh_token_url_override_present,
27 }
28 }
29}
30
31pub fn collect_auth_env_telemetry(
32 provider: &ModelProviderInfo,
33 codex_api_key_env_enabled: bool,
34) -> AuthEnvTelemetry {
35 AuthEnvTelemetry {
36 openai_api_key_env_present: env_var_present(OPENAI_API_KEY_ENV_VAR),
37 codex_api_key_env_present: env_var_present(CODEX_API_KEY_ENV_VAR),
38 codex_api_key_env_enabled,
39 provider_env_key_name: provider.env_key.as_ref().map(|_| "configured".to_string()),
40 provider_env_key_present: provider.env_key.as_deref().map(env_var_present),
41 refresh_token_url_override_present: env_var_present(REFRESH_TOKEN_URL_OVERRIDE_ENV_VAR),
42 }
43}
44
45fn env_var_present(name: &str) -> bool {
46 match std::env::var(name) {
47 Ok(value) => !value.trim().is_empty(),
48 Err(std::env::VarError::NotUnicode(_)) => true,
49 Err(std::env::VarError::NotPresent) => false,
50 }
51}
52
53#[cfg(test)]
54mod tests {
55 use super::*;
56 use codex_model_provider_info::WireApi;
57 use pretty_assertions::assert_eq;
58
59 #[test]
60 fn collect_auth_env_telemetry_buckets_provider_env_key_name() {
61 let provider = ModelProviderInfo {
62 name: "Custom".to_string(),
63 base_url: None,
64 env_key: Some("sk-should-not-leak".to_string()),
65 env_key_instructions: None,
66 experimental_bearer_token: None,
67 auth: None,
68 aws: None,
69 wire_api: WireApi::Responses,
70 query_params: None,
71 http_headers: None,
72 env_http_headers: None,
73 request_max_retries: None,
74 stream_max_retries: None,
75 stream_idle_timeout_ms: None,
76 websocket_connect_timeout_ms: None,
77 requires_openai_auth: false,
78 supports_websockets: false,
79 };
80
81 let telemetry =
82 collect_auth_env_telemetry(&provider, false);
83
84 assert_eq!(
85 telemetry.provider_env_key_name,
86 Some("configured".to_string())
87 );
88 }
89}