use std::path::Path; use codex_login::login_with_api_key; use codex_protocol::mcp_protocol::AuthMode; use codex_protocol::mcp_protocol::GetAuthStatusParams; use codex_protocol::mcp_protocol::GetAuthStatusResponse; use mcp_test_support::McpProcess; use mcp_test_support::to_response; use mcp_types::JSONRPCResponse; use mcp_types::RequestId; use pretty_assertions::assert_eq; use tempfile::TempDir; use tokio::time::timeout; const DEFAULT_READ_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10); // Helper to create a config.toml; mirrors create_conversation.rs fn create_config_toml(codex_home: &Path) -> std::io::Result<()> { let config_toml = codex_home.join("config.toml"); std::fs::write( config_toml, r#" model = "mock-model" approval_policy = "never" sandbox_mode = "danger-full-access" model_provider = "mock_provider" [model_providers.mock_provider] name = "Mock provider for test" base_url = "http://127.0.0.1:0/v1" wire_api = "chat" request_max_retries = 0 stream_max_retries = 0 "#, ) } #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn get_auth_status_no_auth() { let codex_home = TempDir::new().unwrap_or_else(|e| panic!("create tempdir: {e}")); create_config_toml(codex_home.path()).expect("write config.toml"); let mut mcp = McpProcess::new(codex_home.path()) .await .expect("spawn mcp process"); timeout(DEFAULT_READ_TIMEOUT, mcp.initialize()) .await .expect("init timeout") .expect("init failed"); let request_id = mcp .send_get_auth_status_request(GetAuthStatusParams { include_token: Some(true), refresh_token: Some(false), }) .await .expect("send getAuthStatus"); let resp: JSONRPCResponse = timeout( DEFAULT_READ_TIMEOUT, mcp.read_stream_until_response_message(RequestId::Integer(request_id)), ) .await .expect("getAuthStatus timeout") .expect("getAuthStatus response"); let status: GetAuthStatusResponse = to_response(resp).expect("deserialize status"); assert_eq!(status.auth_method, None, "expected no auth method"); assert_eq!(status.auth_token, None, "expected no token"); } #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn get_auth_status_with_api_key() { let codex_home = TempDir::new().unwrap_or_else(|e| panic!("create tempdir: {e}")); create_config_toml(codex_home.path()).expect("write config.toml"); login_with_api_key(codex_home.path(), "sk-test-key").expect("seed api key"); let mut mcp = McpProcess::new(codex_home.path()) .await .expect("spawn mcp process"); timeout(DEFAULT_READ_TIMEOUT, mcp.initialize()) .await .expect("init timeout") .expect("init failed"); let request_id = mcp .send_get_auth_status_request(GetAuthStatusParams { include_token: Some(true), refresh_token: Some(false), }) .await .expect("send getAuthStatus"); let resp: JSONRPCResponse = timeout( DEFAULT_READ_TIMEOUT, mcp.read_stream_until_response_message(RequestId::Integer(request_id)), ) .await .expect("getAuthStatus timeout") .expect("getAuthStatus response"); let status: GetAuthStatusResponse = to_response(resp).expect("deserialize status"); assert_eq!(status.auth_method, Some(AuthMode::ApiKey)); assert_eq!(status.auth_token, Some("sk-test-key".to_string())); assert_eq!(status.preferred_auth_method, AuthMode::ChatGPT); } #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn get_auth_status_with_api_key_no_include_token() { let codex_home = TempDir::new().unwrap_or_else(|e| panic!("create tempdir: {e}")); create_config_toml(codex_home.path()).expect("write config.toml"); login_with_api_key(codex_home.path(), "sk-test-key").expect("seed api key"); let mut mcp = McpProcess::new(codex_home.path()) .await .expect("spawn mcp process"); timeout(DEFAULT_READ_TIMEOUT, mcp.initialize()) .await .expect("init timeout") .expect("init failed"); // Build params via struct so None field is omitted in wire JSON. let params = GetAuthStatusParams { include_token: None, refresh_token: Some(false), }; let request_id = mcp .send_get_auth_status_request(params) .await .expect("send getAuthStatus"); let resp: JSONRPCResponse = timeout( DEFAULT_READ_TIMEOUT, mcp.read_stream_until_response_message(RequestId::Integer(request_id)), ) .await .expect("getAuthStatus timeout") .expect("getAuthStatus response"); let status: GetAuthStatusResponse = to_response(resp).expect("deserialize status"); assert_eq!(status.auth_method, Some(AuthMode::ApiKey)); assert!(status.auth_token.is_none(), "token must be omitted"); assert_eq!(status.preferred_auth_method, AuthMode::ChatGPT); }