diff --git a/crates/turborepo-dirs/src/lib.rs b/crates/turborepo-dirs/src/lib.rs index 678adcffb9705..3181bd15c4087 100644 --- a/crates/turborepo-dirs/src/lib.rs +++ b/crates/turborepo-dirs/src/lib.rs @@ -13,7 +13,23 @@ use turbopath::{AbsoluteSystemPathBuf, PathError}; /// is set, it will return that path instead of `dirs_next::config_dir`. pub fn config_dir() -> Result, PathError> { if let Ok(dir) = std::env::var("TURBO_CONFIG_DIR_PATH") { - return AbsoluteSystemPathBuf::new(dir).map(Some); + // Reject empty strings per Unix convention + if dir.is_empty() { + return Err(PathError::InvalidUnicode(dir)); + } + + let raw = std::path::PathBuf::from(&dir); + + // Resolve to absolute path if necessary + let abs = if raw.is_absolute() { + raw + } else { + std::env::current_dir()?.join(raw) + }; + + let abs_str = abs.to_str().ok_or(PathError::InvalidUnicode(dir))?; + + return AbsoluteSystemPathBuf::new(abs_str).map(Some); } dirs_config_dir() @@ -28,6 +44,11 @@ pub fn config_dir() -> Result, PathError> { /// is set, it will return that path instead of `dirs_next::config_dir`. pub fn vercel_config_dir() -> Result, PathError> { if let Ok(dir) = std::env::var("VERCEL_CONFIG_DIR_PATH") { + // Reject empty strings per Unix convention. + if dir.is_empty() { + return Err(PathError::InvalidUnicode(dir)); + } + return AbsoluteSystemPathBuf::new(dir).map(Some); } @@ -73,14 +94,18 @@ mod tests { } #[test] - fn test_config_dir_with_invalid_env_var() { - // Set TURBO_CONFIG_DIR_PATH to a relative path (invalid) + fn test_config_dir_with_relative_path() { + // Set TURBO_CONFIG_DIR_PATH to a relative path (should be resolved to absolute) unsafe { env::set_var("TURBO_CONFIG_DIR_PATH", "relative/path"); } let result = config_dir(); - assert!(result.is_err()); + assert!(result.is_ok()); + let path = result.unwrap(); + assert!(path.is_some()); + // Verify it was resolved to an absolute path + assert!(path.unwrap().as_path().is_absolute()); unsafe { env::remove_var("TURBO_CONFIG_DIR_PATH");