From c77af1892ff121736ecb103b32d504d6f1b31805 Mon Sep 17 00:00:00 2001 From: Can Celik Date: Mon, 14 Sep 2026 03:55:53 +0300 Subject: fix: clean up idle ssh bridges and back off flapping connections (#4083) * fix: clean up idle ssh bridges and back off flapping connections * chore: keep ssh liveness smoke tooling local --- src/remote/attach.rs | 52 +++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 47 insertions(+), 5 deletions(-) (limited to 'src/remote/attach.rs') diff --git a/src/remote/attach.rs b/src/remote/attach.rs index ace72f84..6a1ee6f9 100644 --- a/src/remote/attach.rs +++ b/src/remote/attach.rs @@ -258,7 +258,16 @@ impl RemoteExecutable { } fn bridge_command(&self, session_name: &str) -> String { - let args = Self::session_args(session_name, &["remote-client-bridge"]); + self.bridge_command_with_idle_timeout(session_name, false) + } + + fn bridge_command_with_idle_timeout(&self, session_name: &str, idle_timeout: bool) -> String { + let command = if idle_timeout { + &["remote-client-bridge", "--idle-timeout-v1"][..] + } else { + &["remote-client-bridge"][..] + }; + let args = Self::session_args(session_name, command); match self { Self::PosixShellPath(_) => { posix_remote_output_command(&format!("exec {}", self.command(&args))) @@ -310,6 +319,7 @@ pub(super) struct RemoteHerdr { install_suffix: String, executable: RemoteExecutable, platform: RemotePlatform, + bridge_idle_timeout: bool, } impl RemoteHerdr { @@ -328,6 +338,7 @@ impl RemoteHerdr { install_suffix, executable, platform, + bridge_idle_timeout: false, } } @@ -1150,9 +1161,12 @@ pub(super) fn find_installed_remote_herdr(ssh: &RemoteSsh) -> io::Result, #[serde(default)] remote_host_bridge: bool, + #[serde(default)] + remote_bridge_idle_timeout: bool, } impl RemoteClientStatusJson { @@ -2438,7 +2454,13 @@ impl SshStdioBridge { ) -> io::Result { Self::start_command( target, - remote_herdr.executable.bridge_command(&session_name), + if noninteractive && remote_herdr.bridge_idle_timeout { + remote_herdr + .executable + .bridge_command_with_idle_timeout(&session_name, true) + } else { + remote_herdr.executable.bridge_command(&session_name) + }, local_socket, ssh_options, noninteractive, @@ -3669,6 +3691,7 @@ mod tests { crate::protocol::endpoint::HEALTH_CHECK_CAPABILITY.into(), ], remote_host_bridge: false, + remote_bridge_idle_timeout: false, }; assert!(status.supports_endpoint_requirement(&linux, true)); for index in 0..status.endpoint_capabilities.len() { @@ -4300,6 +4323,25 @@ mod tests { } } + #[test] + fn remote_bridge_idle_timeout_requires_explicit_support_and_opt_in() { + let legacy = parse_client_status_json(r#"{"endpoint_protocol_generation":1}"#).unwrap(); + assert!(!legacy.remote_bridge_idle_timeout); + let current = parse_client_status_json( + r#"{"endpoint_protocol_generation":1,"remote_bridge_idle_timeout":true}"#, + ) + .unwrap(); + assert!(current.remote_bridge_idle_timeout); + let remote = RemoteHerdr::for_platform(RemotePlatform { + os: "linux", + arch: "x86_64", + }); + assert!(remote + .executable + .bridge_command_with_idle_timeout("agents", true) + .ends_with(" --session agents remote-client-bridge --idle-timeout-v1")); + } + #[test] fn remote_bridge_command_uses_installed_binary() { let remote_herdr = RemoteHerdr::for_platform(RemotePlatform { -- cgit v1.2.3