diff --git a/codex-rs/login/src/entrypoints.rs b/codex-rs/login/src/entrypoints.rs index f9d57bf82c..544a227d19 100644 --- a/codex-rs/login/src/entrypoints.rs +++ b/codex-rs/login/src/entrypoints.rs @@ -79,9 +79,7 @@ pub fn spawn_login_with_chatgpt(codex_home: &Path) -> std::io::Result std::io::Result<()> { +pub async fn login_with_chatgpt(codex_home: &Path) -> std::io::Result<()> { let client_id = std::env::var("CODEX_CLIENT_ID") .ok() .filter(|s| !s.is_empty()) diff --git a/codex-rs/login/src/lib_tests.rs b/codex-rs/login/src/lib_tests.rs index 1ea680f9c1..989c50ce9d 100644 --- a/codex-rs/login/src/lib_tests.rs +++ b/codex-rs/login/src/lib_tests.rs @@ -267,8 +267,14 @@ fn update_tokens_preserves_id_token_as_string() { // Build a valid-looking JWT (URL-safe base64 header.payload.signature) #[derive(Serialize)] - struct Header { alg: &'static str, typ: &'static str } - let header = Header { alg: "none", typ: "JWT" }; + struct Header { + alg: &'static str, + typ: &'static str, + } + let header = Header { + alg: "none", + typ: "JWT", + }; let payload = serde_json::json!({}); let b64 = |b: &[u8]| base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(b); let header_b64 = b64(&serde_json::to_vec(&header).unwrap()); diff --git a/codex-rs/login/src/server.rs b/codex-rs/login/src/server.rs index 0f24103c8b..346c297bf8 100644 --- a/codex-rs/login/src/server.rs +++ b/codex-rs/login/src/server.rs @@ -18,7 +18,8 @@ use crate::auth_store::write_new_auth_json; use crate::pkce::generate_pkce; use crate::success_url::build_success_url; use crate::token_data::extract_login_context_from_tokens; -use tracing::{error, trace}; +use tracing::error; +use tracing::trace; pub const DEFAULT_PORT: u16 = 1455; pub const DEFAULT_ISSUER: &str = "https://auth.openai.com"; @@ -29,7 +30,7 @@ pub const LOGIN_ERROR_HTML: &str = include_str!("./error_page.html"); fn render_error_html(message: &str) -> String { LOGIN_ERROR_HTML.replace( "%%MESSAGE%%", - &html_escape::encode_text(message).to_string(), + html_escape::encode_text(message).as_ref(), ) } @@ -188,8 +189,12 @@ pub fn run_local_login_server_with_options(mut opts: LoginServerOptions) -> std: // Preserve explicit error messages for tests if params.get("state").map(|s| s.as_str()) != Some(state.as_str()) { - let mut resp = Response::from_string(render_error_html("State parameter mismatch")).with_status_code(400); - if let Ok(h) = Header::from_bytes(&b"Content-Type"[..], &b"text/html; charset=utf-8"[..]) { + let mut resp = + Response::from_string(render_error_html("State parameter mismatch")) + .with_status_code(400); + if let Ok(h) = + Header::from_bytes(&b"Content-Type"[..], &b"text/html; charset=utf-8"[..]) + { resp.add_header(h); } if let Err(e) = request.respond(resp) { @@ -199,8 +204,12 @@ pub fn run_local_login_server_with_options(mut opts: LoginServerOptions) -> std: } let code_opt = params.get("code").map(|s| s.as_str()); if code_opt.map(|s| s.is_empty()).unwrap_or(true) { - let mut resp = Response::from_string(render_error_html("Missing authorization code")).with_status_code(400); - if let Ok(h) = Header::from_bytes(&b"Content-Type"[..], &b"text/html; charset=utf-8"[..]) { + let mut resp = + Response::from_string(render_error_html("Missing authorization code")) + .with_status_code(400); + if let Ok(h) = + Header::from_bytes(&b"Content-Type"[..], &b"text/html; charset=utf-8"[..]) + { resp.add_header(h); } if let Err(e) = request.respond(resp) { @@ -231,8 +240,13 @@ pub fn run_local_login_server_with_options(mut opts: LoginServerOptions) -> std: } } Err(_) => { - let mut resp = Response::from_string(render_error_html("Token exchange failed")).with_status_code(500); - if let Ok(h) = Header::from_bytes(&b"Content-Type"[..], &b"text/html; charset=utf-8"[..]) { + let mut resp = + Response::from_string(render_error_html("Token exchange failed")) + .with_status_code(500); + if let Ok(h) = Header::from_bytes( + &b"Content-Type"[..], + &b"text/html; charset=utf-8"[..], + ) { resp.add_header(h); } if let Err(e) = request.respond(resp) { @@ -242,9 +256,9 @@ pub fn run_local_login_server_with_options(mut opts: LoginServerOptions) -> std: } } _ => { - if let Err(e) = request.respond( - Response::from_string("Endpoint not supported").with_status_code(404), - ) { + if let Err(e) = request + .respond(Response::from_string("Endpoint not supported").with_status_code(404)) + { error!("failed to respond 404: {e}"); } } diff --git a/codex-rs/login/tests/api_key_login.rs b/codex-rs/login/tests/api_key_login.rs index e9e457e7e7..88686e6bb2 100644 --- a/codex-rs/login/tests/api_key_login.rs +++ b/codex-rs/login/tests/api_key_login.rs @@ -1,12 +1,12 @@ use tempfile::tempdir; #[tokio::test] -async fn writes_api_key_and_loads_auth() { - let dir = tempdir().unwrap(); - codex_login::login_with_api_key(dir.path(), "sk-test-key").unwrap(); - let auth = codex_login::CodexAuth::from_codex_home(dir.path()) - .unwrap() - .unwrap(); +async fn writes_api_key_and_loads_auth() -> Result<(), Box> { + let dir = tempdir()?; + codex_login::login_with_api_key(dir.path(), "sk-test-key")?; + let auth = codex_login::CodexAuth::from_codex_home(dir.path())? + .ok_or_else(|| std::io::Error::other("expected Some(auth)"))?; assert_eq!(auth.mode, codex_login::AuthMode::ApiKey); - assert_eq!(auth.get_token().await.unwrap().as_str(), "sk-test-key"); + assert_eq!(auth.get_token().await?.as_str(), "sk-test-key"); + Ok(()) } diff --git a/codex-rs/login/tests/server.rs b/codex-rs/login/tests/server.rs index abfc669e1e..0ed1216a3c 100644 --- a/codex-rs/login/tests/server.rs +++ b/codex-rs/login/tests/server.rs @@ -384,7 +384,12 @@ async fn login_server_state_mismatch() { let (status, body, content_type) = http_get_with_ct(&cb_url); assert_eq!(status, 400); assert!(body.contains("State parameter mismatch")); - assert!(content_type.unwrap_or_default().to_ascii_lowercase().starts_with("text/html")); + assert!( + content_type + .unwrap_or_default() + .to_ascii_lowercase() + .starts_with("text/html") + ); // Stop server let _ = ureq::get(&format!("http://127.0.0.1:{port}/success")).call(); @@ -410,7 +415,12 @@ async fn login_server_missing_code() { let (status, body, content_type) = http_get_with_ct(&cb_url); assert_eq!(status, 400); assert!(body.contains("Missing authorization code")); - assert!(content_type.unwrap_or_default().to_ascii_lowercase().starts_with("text/html")); + assert!( + content_type + .unwrap_or_default() + .to_ascii_lowercase() + .starts_with("text/html") + ); let _ = ureq::get(&format!("http://127.0.0.1:{port}/success")).call(); handle.join().unwrap().unwrap(); } @@ -431,7 +441,12 @@ async fn login_server_token_exchange_error() { let (status, body, content_type) = http_get_with_ct(&cb_url); assert_eq!(status, 500); assert!(body.contains("Token exchange failed")); - assert!(content_type.unwrap_or_default().to_ascii_lowercase().starts_with("text/html")); + assert!( + content_type + .unwrap_or_default() + .to_ascii_lowercase() + .starts_with("text/html") + ); let _ = ureq::get(&format!("http://127.0.0.1:{port}/success")).call(); handle.join().unwrap().unwrap(); }