From 13095a317d5cfe22c30bcda4e117759cfcc407c2 Mon Sep 17 00:00:00 2001 From: Mahmoud Abdelwahab Date: Fri, 5 Jun 2026 22:50:48 +0300 Subject: [PATCH] fix railway token auth preflight --- src/commands/up.rs | 2 +- src/config.rs | 40 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/src/commands/up.rs b/src/commands/up.rs index 43983bd2f..b44050a2d 100644 --- a/src/commands/up.rs +++ b/src/commands/up.rs @@ -117,7 +117,7 @@ pub async fn command(args: Args) -> Result<()> { // login flow, then reload configs and continue with `up`. This // turns the previously cryptic "no token" error path into the // canonical first-run experience. - let came_from_unauth_prompt = configs.get_railway_auth_token().is_none(); + let came_from_unauth_prompt = !configs.has_auth_credentials(); if came_from_unauth_prompt { prompt_unauth_and_login(&args).await?; configs = Configs::new()?; diff --git a/src/config.rs b/src/config.rs index de0a85cc0..426facb36 100644 --- a/src/config.rs +++ b/src/config.rs @@ -219,6 +219,13 @@ impl Configs { .filter(|t| !t.is_empty())) } + /// True when any CLI-supported credential is present. This includes + /// project tokens, so use this for auth preflight checks only; commands + /// that need user/workspace auth should call `get_railway_auth_token`. + pub fn has_auth_credentials(&self) -> bool { + Self::get_railway_token().is_some() || self.get_railway_auth_token().is_some() + } + pub fn has_oauth_token(&self) -> bool { self.root_config.user.access_token.is_some() } @@ -736,6 +743,11 @@ mod tests { F: FnOnce() -> R, { let _guard = ENV_LOCK.lock().unwrap(); + let previous: Vec<(&str, Option)> = vars + .iter() + .map(|(key, _)| (*key, std::env::var(key).ok())) + .collect(); + // SAFETY: tests run sequentially under ENV_LOCK, so no concurrent mutation. unsafe { for (key, val) in vars { @@ -747,13 +759,23 @@ mod tests { } let result = f(); unsafe { - for (key, _) in vars { - std::env::remove_var(key); + for (key, val) in previous { + match val { + Some(v) => std::env::set_var(key, v), + None => std::env::remove_var(key), + } } } result } + fn empty_configs() -> Configs { + Configs { + root_config_path: std::path::PathBuf::new(), + root_config: RailwayConfig::default(), + } + } + #[test] fn env_var_project_id_only_returns_none_environment() { let result = with_env_vars( @@ -784,4 +806,18 @@ mod tests { "unexpected error: {err}" ); } + + #[test] + fn auth_credentials_accept_project_token() { + let configs = empty_configs(); + let has_credentials = with_env_vars( + &[ + ("RAILWAY_TOKEN", Some("project-token")), + ("RAILWAY_API_TOKEN", None), + ], + || configs.has_auth_credentials(), + ); + + assert!(has_credentials); + } }