diff --git a/crates/cli/src/cli.rs b/crates/cli/src/cli.rs index 10a5b87b..0e916192 100644 --- a/crates/cli/src/cli.rs +++ b/crates/cli/src/cli.rs @@ -429,7 +429,8 @@ pub enum Command { long_about = "Open the terminal UI in the browser\n\n\ Opens the browser on the local yas server, with that server's named\n\ remotes reachable through its Relay. Manage remotes with\n\ - `yas remote add/remove` or through the Remotes dialog in the browser.\n\n\ + `yas remote add/remove` or through the Remotes dialog in the browser.\n\ + `--on` and `--hub` are refused: the UI always starts from the local server.\n\n\ Examples:\n\ yas open # local + all configured remotes\n\ yas remote add rabbit ssh:rabbit\n\ diff --git a/crates/cli/src/interactive.rs b/crates/cli/src/interactive.rs index 16501426..e9d0b57d 100644 --- a/crates/cli/src/interactive.rs +++ b/crates/cli/src/interactive.rs @@ -27,7 +27,7 @@ struct BrowserState { } /// Open the local browser UI backed by one native YAS server. -pub async fn run_browser(port: Option, _hub: &str) { +pub async fn run_browser(port: Option) { let token: String = { use rand::RngExt as _; rand::rng() diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs index cec2b09d..3a2a3f87 100644 --- a/crates/cli/src/main.rs +++ b/crates/cli/src/main.rs @@ -1008,8 +1008,14 @@ async fn async_main() { } } Command::Open { port } => { - let hub = yas_webrtc_forwarder::normalize_hub(&cli.connect.hub); - interactive::run_browser(port, &hub).await; + let hub_env = std::env::var_os("YAS_HUB").is_some(); + if let Err(error) = + open_target_flags(cli.connect.on.as_deref(), &cli.connect.hub, hub_env) + { + eprintln!("yas: {error}"); + std::process::exit(2); + } + interactive::run_browser(port).await; } Command::Edge => { yas_edge::run().await; @@ -1089,6 +1095,22 @@ async fn async_main() { /// Read a `usize` limit from the environment. Unset, unparseable or 0 all /// mean "no limit", which is what the server's `> 0` guards already expect. +/// `yas open` always serves the local server's UI and reaches other targets +/// through its Remotes dialog, so a command-line target would be ignored. +fn open_target_flags(on: Option<&str>, hub: &str, hub_env: bool) -> Result<(), String> { + if let Some(on) = on { + let on = mask_remote_credentials(on); + return Err(format!( + "yas open does not take --on ({on}); it opens the local server's UI, which \ + lists configured remotes (add one with `yas remote add NAME {on}`)" + )); + } + if !hub_env && hub != yas_webrtc_forwarder::DEFAULT_HUB_URL { + return Err("yas open does not take --hub; it opens the local server's UI".into()); + } + Ok(()) +} + fn env_usize(key: &str) -> usize { std::env::var(key) .ok() @@ -1467,7 +1489,18 @@ async fn cmd_upgrade() -> Result<(), Box> { #[cfg(test)] mod tests { - use super::{mask_remote_credentials, proxy_daemon_requested}; + use super::{mask_remote_credentials, open_target_flags, proxy_daemon_requested}; + + #[test] + fn open_refuses_targets_it_would_ignore() { + let default_hub = yas_webrtc_forwarder::DEFAULT_HUB_URL; + assert!(open_target_flags(None, default_hub, false).is_ok()); + let error = open_target_flags(Some("share:secret"), default_hub, false).unwrap_err(); + assert!(error.contains("--on"), "{error}"); + assert!(!error.contains("secret"), "{error}"); + assert!(open_target_flags(None, "hub.example", false).is_err()); + assert!(open_target_flags(None, "hub.example", true).is_ok()); + } #[test] fn test_mask_remote_credentials() {