From f5a6f2e7253cee13fa7b60dd5f0398df6954133b Mon Sep 17 00:00:00 2001 From: OnlyYu1996 <1158673577@qq.com> Date: Sun, 17 May 2026 06:40:01 +0800 Subject: [PATCH] fix(auth): ignore blank environment tokens --- src/cortex-cli/src/cli/handlers.rs | 6 +++--- src/cortex-cli/src/login.rs | 8 ++++---- src/cortex-engine/src/auth_token.rs | 16 ++++++++++------ src/cortex-engine/src/client/mod.rs | 6 ++++-- src/cortex-login/src/lib.rs | 2 +- src/cortex-login/src/token.rs | 3 ++- src/cortex-login/src/utils.rs | 13 +++++++++++++ 7 files changed, 37 insertions(+), 17 deletions(-) diff --git a/src/cortex-cli/src/cli/handlers.rs b/src/cortex-cli/src/cli/handlers.rs index e92fa8632..28fe48855 100644 --- a/src/cortex-cli/src/cli/handlers.rs +++ b/src/cortex-cli/src/cli/handlers.rs @@ -530,7 +530,7 @@ fn install_completions(shell: Shell) -> Result<()> { /// Show current logged-in user. pub async fn run_whoami() -> Result<()> { - use cortex_login::{AuthMode, load_auth_with_fallback, safe_format_key}; + use cortex_login::{AuthMode, has_non_blank_token, load_auth_with_fallback, safe_format_key}; let cortex_home = dirs::home_dir() .map(|h| h.join(".cortex")) @@ -538,7 +538,7 @@ pub async fn run_whoami() -> Result<()> { // Check environment variables first if let Ok(token) = std::env::var("CORTEX_AUTH_TOKEN") - && !token.is_empty() + && has_non_blank_token(&token) { println!( "Authenticated via CORTEX_AUTH_TOKEN: {}", @@ -548,7 +548,7 @@ pub async fn run_whoami() -> Result<()> { } if let Ok(token) = std::env::var("CORTEX_API_KEY") - && !token.is_empty() + && has_non_blank_token(&token) { println!( "Authenticated via CORTEX_API_KEY: {}", diff --git a/src/cortex-cli/src/login.rs b/src/cortex-cli/src/login.rs index 138451fc9..b19ec8074 100644 --- a/src/cortex-cli/src/login.rs +++ b/src/cortex-cli/src/login.rs @@ -3,8 +3,8 @@ use crate::styled_output::{print_dim, print_error, print_info, print_success, print_warning}; use cortex_common::CliConfigOverrides; use cortex_login::{ - AuthMode, CredentialsStoreMode, SecureAuthData, load_auth_with_fallback, logout_with_fallback, - safe_format_key, save_auth_with_fallback, + AuthMode, CredentialsStoreMode, SecureAuthData, has_non_blank_token, load_auth_with_fallback, + logout_with_fallback, safe_format_key, save_auth_with_fallback, }; use std::collections::HashSet; use std::io::{IsTerminal, Read}; @@ -132,7 +132,7 @@ pub async fn run_login_status(config_overrides: CliConfigOverrides) -> ! { // Check environment variables first (CORTEX_AUTH_TOKEN and CORTEX_API_KEY) if let Ok(token) = std::env::var("CORTEX_AUTH_TOKEN") - && !token.is_empty() + && has_non_blank_token(&token) { print_success(&format!( "Authenticated via CORTEX_AUTH_TOKEN environment variable: {}", @@ -142,7 +142,7 @@ pub async fn run_login_status(config_overrides: CliConfigOverrides) -> ! { } if let Ok(token) = std::env::var("CORTEX_API_KEY") - && !token.is_empty() + && has_non_blank_token(&token) { print_success(&format!( "Authenticated via CORTEX_API_KEY environment variable: {}", diff --git a/src/cortex-engine/src/auth_token.rs b/src/cortex-engine/src/auth_token.rs index ada5411d1..3f7ad9a83 100755 --- a/src/cortex-engine/src/auth_token.rs +++ b/src/cortex-engine/src/auth_token.rs @@ -44,7 +44,7 @@ use crate::error::{CortexError, Result}; pub fn get_auth_token(instance_token: Option<&str>) -> Result { // Priority 1: Instance token (if provided and non-empty) if let Some(token) = instance_token { - if !token.is_empty() { + if cortex_login::has_non_blank_token(token) { tracing::debug!(source = "instance", "Using auth token from client instance"); return Ok(token.to_string()); } @@ -52,7 +52,7 @@ pub fn get_auth_token(instance_token: Option<&str>) -> Result { // Priority 2: CORTEX_AUTH_TOKEN environment variable if let Ok(token) = std::env::var("CORTEX_AUTH_TOKEN") { - if !token.is_empty() { + if cortex_login::has_non_blank_token(&token) { tracing::debug!( source = "env_var", "Using auth token from CORTEX_AUTH_TOKEN" @@ -63,7 +63,7 @@ pub fn get_auth_token(instance_token: Option<&str>) -> Result { // Priority 3: CORTEX_API_KEY environment variable (alias for GitHub Actions workflow) if let Ok(token) = std::env::var("CORTEX_API_KEY") { - if !token.is_empty() { + if cortex_login::has_non_blank_token(&token) { tracing::debug!(source = "env_var", "Using auth token from CORTEX_API_KEY"); return Ok(token); } @@ -95,17 +95,20 @@ pub fn get_auth_token_optional(instance_token: Option<&str>) -> Option { /// Useful for fast availability checks in UI. pub fn is_authenticated(instance_token: Option<&str>) -> bool { // Check instance token - if instance_token.map_or(false, |t| !t.is_empty()) { + if instance_token.is_some_and(cortex_login::has_non_blank_token) { return true; } // Check CORTEX_AUTH_TOKEN env var - if std::env::var("CORTEX_AUTH_TOKEN").map_or(false, |t| !t.is_empty()) { + if std::env::var("CORTEX_AUTH_TOKEN") + .is_ok_and(|token| cortex_login::has_non_blank_token(&token)) + { return true; } // Check CORTEX_API_KEY env var (alias) - if std::env::var("CORTEX_API_KEY").map_or(false, |t| !t.is_empty()) { + if std::env::var("CORTEX_API_KEY").is_ok_and(|token| cortex_login::has_non_blank_token(&token)) + { return true; } @@ -142,6 +145,7 @@ mod tests { fn test_is_authenticated_with_instance() { assert!(is_authenticated(Some("token"))); assert!(!is_authenticated(Some(""))); + assert!(!is_authenticated(Some(" "))); assert!(!is_authenticated(None)); } diff --git a/src/cortex-engine/src/client/mod.rs b/src/cortex-engine/src/client/mod.rs index cebbb47fc..021ad86de 100644 --- a/src/cortex-engine/src/client/mod.rs +++ b/src/cortex-engine/src/client/mod.rs @@ -50,7 +50,9 @@ pub trait ModelClient: Send + Sync { fn get_auth_token() -> Result { // First check environment variable if let Ok(token) = std::env::var("CORTEX_AUTH_TOKEN") { - return Ok(token); + if cortex_login::has_non_blank_token(&token) { + return Ok(token); + } } // Try to load from cortex-login keyring storage @@ -78,7 +80,7 @@ pub fn create_client( _base_url: Option<&str>, ) -> Result> { // Use provided api_key as auth token, or try to get from environment/keyring - let auth_token = if !api_key.is_empty() { + let auth_token = if cortex_login::has_non_blank_token(api_key) { api_key.to_string() } else { get_auth_token()? diff --git a/src/cortex-login/src/lib.rs b/src/cortex-login/src/lib.rs index 2694981c2..fcbc56176 100644 --- a/src/cortex-login/src/lib.rs +++ b/src/cortex-login/src/lib.rs @@ -53,7 +53,7 @@ pub use keyring::{delete_from_keyring, load_from_keyring, save_to_keyring}; pub use token::get_auth_token; // Re-exports from utils -pub use utils::safe_format_key; +pub use utils::{has_non_blank_token, safe_format_key}; // Re-exports from device_code_auth pub use device_code_auth::run_device_code_login; diff --git a/src/cortex-login/src/token.rs b/src/cortex-login/src/token.rs index 4af1d1bad..08aa89bd4 100644 --- a/src/cortex-login/src/token.rs +++ b/src/cortex-login/src/token.rs @@ -7,6 +7,7 @@ use crate::constants::{API_BASE_URL, USER_AGENT}; use crate::keyring::save_to_keyring; use crate::storage::load_auth_with_fallback; use crate::types::{AuthMode, SecureAuthData}; +use crate::utils::has_non_blank_token; /// Refresh an expired access token using the refresh token. /// @@ -71,7 +72,7 @@ fn refresh_token_sync(refresh_token: &str) -> Option { pub fn get_auth_token() -> Option { // Check environment variable first (highest priority for CI/CD) if let Ok(token) = std::env::var("CORTEX_API_KEY") { - if !token.is_empty() { + if has_non_blank_token(&token) { tracing::debug!("Using API key from CORTEX_API_KEY environment variable"); return Some(token); } diff --git a/src/cortex-login/src/utils.rs b/src/cortex-login/src/utils.rs index d6d9d562a..bc2ff3b32 100644 --- a/src/cortex-login/src/utils.rs +++ b/src/cortex-login/src/utils.rs @@ -13,6 +13,11 @@ pub fn safe_format_key(key: &str) -> String { format!("{prefix}***{suffix}") } +/// Return true when a token contains at least one non-whitespace character. +pub fn has_non_blank_token(token: &str) -> bool { + !token.trim().is_empty() +} + /// Set restrictive file permissions (0600 on Unix). pub fn set_file_permissions(path: &Path) -> Result<()> { #[cfg(unix)] @@ -46,4 +51,12 @@ mod tests { let key = "sk-proj-12345"; assert_eq!(safe_format_key(key), "***"); } + + #[test] + fn test_has_non_blank_token() { + assert!(has_non_blank_token("ctx-token")); + assert!(has_non_blank_token(" ctx-token ")); + assert!(!has_non_blank_token("")); + assert!(!has_non_blank_token(" \t\n")); + } }