From 1062309d7e0473160d95890868f33bb4bbcfd3e5 Mon Sep 17 00:00:00 2001 From: kunaldevxxx Date: Thu, 17 Sep 2026 19:20:59 +0530 Subject: [PATCH 1/4] feat(server): warn when listener binds loopback inside a container (#4209) --- core/configs/src/server_config/validators.rs | 161 +++++++++++++++++-- 1 file changed, 151 insertions(+), 10 deletions(-) diff --git a/core/configs/src/server_config/validators.rs b/core/configs/src/server_config/validators.rs index 1ce11aa902..c8046abba5 100644 --- a/core/configs/src/server_config/validators.rs +++ b/core/configs/src/server_config/validators.rs @@ -32,6 +32,8 @@ use crate::common::validators::SEGMENT_MAX_SIZE_BYTES; use err_trail::ErrContext; use iggy_common::{IggyExpiry, MAX_MESSAGE_SIZE_UPPER_BYTES, Validatable}; use std::net::SocketAddr; +use std::path::Path; +use tracing::warn; /// compio-ws (tungstenite 0.29) `write_buffer_size` default. Used to /// evaluate the `max_write_buffer_size > write_buffer_size` invariant @@ -407,8 +409,18 @@ impl ServerConfig { /// The listener the client-facing address is derived from must not bind a /// wildcard unless that address is declared outright. + /// + /// When running inside a container, a loopback listener means the server + /// is unreachable from outside the container, which is warned. fn validate_client_facing_address(&self) -> Result<(), ConfigurationError> { - if self.cluster.enabled || self.node.advertised_address.is_some() { + self.validate_client_facing_address_in_env(is_container()) + } + + fn validate_client_facing_address_in_env( + &self, + is_container: bool, + ) -> Result<(), ConfigurationError> { + if self.cluster.enabled { return Ok(()); } // No client-facing listener runs, so no client dials this node and @@ -417,21 +429,92 @@ impl ServerConfig { return Ok(()); }; let bind = parse_bind_address(listener.key, listener.address)?; - if !bind.ip().to_canonical().is_unspecified() { + let ip = bind.ip().to_canonical(); + if ip.is_unspecified() { + if self.node.advertised_address.is_none() { + eprintln!( + "{COMPONENT} - {} binds the wildcard {bind}, which says which interfaces this node \ + accepts on rather than where a client reaches it, so cluster metadata would carry no \ + address for this node. Set node.advertised_address to the address clients dial, or \ + bind a concrete address.", + listener.key + ); + return Err(ConfigurationError::InvalidConfigurationValue); + } return Ok(()); } - eprintln!( - "{COMPONENT} - {} binds the wildcard {bind}, which says which interfaces this node \ - accepts on rather than where a client reaches it, so cluster metadata would carry no \ - address for this node. Set node.advertised_address to the address clients dial, or \ - bind a concrete address.", - listener.key - ); - Err(ConfigurationError::InvalidConfigurationValue) + if ip.is_loopback() && is_container { + let env_var = format!("IGGY_{}", listener.key.replace('.', "_").to_uppercase()); + let port = bind.port(); + if self.node.advertised_address.is_none() { + warn!( + "{COMPONENT} - {} binds the loopback address {bind} inside a container; the \ + server will not be reachable from outside the container. Set {env_var}=0.0.0.0:{port} \ + together with IGGY_NODE_ADVERTISED_ADDRESS, or bind a concrete address.", + listener.key + ); + } else { + warn!( + "{COMPONENT} - {} binds the loopback address {bind} inside a container; the \ + server will not be reachable from outside the container. Set {env_var}=0.0.0.0:{port} \ + or bind a concrete address.", + listener.key + ); + } + } + + Ok(()) } } +/// Returns true when the process is executing inside a container. +fn is_container() -> bool { + is_container_indicators( + Path::new("/.dockerenv"), + Path::new("/run/.containerenv"), + "/proc/self/cgroup", + ) +} + +fn is_container_indicators( + dockerenv_path: &Path, + containerenv_path: &Path, + cgroup_path: &str, +) -> bool { + if dockerenv_path.exists() || containerenv_path.exists() { + return true; + } + + if std::env::var_os("container").is_some() + || std::env::var_os("KUBERNETES_SERVICE_HOST").is_some() + { + return true; + } + + #[cfg(target_os = "linux")] + { + if let Ok(cgroup) = std::fs::read_to_string(cgroup_path) + && cgroup.lines().any(|line| { + line.contains("/docker/") + || line.contains("/docker-") + || line.contains("/libpod-") + || line.contains("/podman/") + || line.contains("/kubepods/") + || line.contains("/kubepods-") + || line.contains("/containerd/") + || line.contains("/lxc/") + }) + { + return true; + } + } + + let _ = cgroup_path; + + false +} + /// A listener's bind address, which is a literal IP and a port and nothing /// else. `context` names the config key so the operator reads back the one /// they wrote. @@ -534,6 +617,64 @@ mod tests { assert!(config.validate().is_ok()); } + #[test] + fn given_loopback_bind_in_container_when_validating_should_pass() { + let config = config_with_override( + "[tcp]\naddress = \"127.0.0.1:8090\"\n[cluster]\nenabled = false\n", + ); + assert!(config.validate_client_facing_address_in_env(true).is_ok()); + } + + #[test] + fn given_loopback_bind_outside_container_when_validating_should_pass() { + let config = config_with_override( + "[tcp]\naddress = \"127.0.0.1:8090\"\n[cluster]\nenabled = false\n", + ); + assert!(config.validate_client_facing_address_in_env(false).is_ok()); + } + + #[test] + fn given_loopback_bind_in_container_with_advertised_address_when_validating_should_pass() { + let config = config_with_override( + "[tcp]\naddress = \"127.0.0.1:8090\"\n[cluster]\nenabled = false\n\ + [node]\nadvertised_address = \"broker-1.example.com\"\n", + ); + assert!(config.validate_client_facing_address_in_env(true).is_ok()); + } + + #[test] + fn given_dockerenv_file_when_checking_container_should_return_true() { + let temp_dir = std::env::temp_dir(); + let marker = temp_dir.join(format!("test_dockerenv_{}", std::process::id())); + std::fs::write(&marker, "").unwrap(); + let non_existent = temp_dir.join("non_existent_indicator"); + let result = is_container_indicators(&marker, &non_existent, "/non/existent/cgroup"); + let _ = std::fs::remove_file(&marker); + assert!(result); + } + + #[test] + fn given_containerenv_file_when_checking_container_should_return_true() { + let temp_dir = std::env::temp_dir(); + let marker = temp_dir.join(format!("test_containerenv_{}", std::process::id())); + std::fs::write(&marker, "").unwrap(); + let non_existent = temp_dir.join("non_existent_indicator"); + let result = is_container_indicators(&non_existent, &marker, "/non/existent/cgroup"); + let _ = std::fs::remove_file(&marker); + assert!(result); + } + + #[test] + fn given_missing_container_indicators_when_checking_container_should_return_false() { + let non_existent = Path::new("/non/existent/path/to/indicator"); + // Safe check without environment variables + assert!(!is_container_indicators( + non_existent, + non_existent, + "/non/existent/cgroup" + )); + } + #[test] fn given_wildcard_bind_on_a_disabled_listener_when_validating_should_pass() { let config = config_with_override( From 43db8481c3d8c792986142802142443fc0997553 Mon Sep 17 00:00:00 2001 From: kunaldevxxx Date: Fri, 18 Sep 2026 10:26:19 +0530 Subject: [PATCH 2/4] feat(server): enhance loopback address validation in container environments --- core/configs/src/server_config/validators.rs | 106 ++++++++++++++----- 1 file changed, 82 insertions(+), 24 deletions(-) diff --git a/core/configs/src/server_config/validators.rs b/core/configs/src/server_config/validators.rs index c8046abba5..6feb200617 100644 --- a/core/configs/src/server_config/validators.rs +++ b/core/configs/src/server_config/validators.rs @@ -31,6 +31,7 @@ use crate::common::http::HMAC_JWT_ALGORITHMS; use crate::common::validators::SEGMENT_MAX_SIZE_BYTES; use err_trail::ErrContext; use iggy_common::{IggyExpiry, MAX_MESSAGE_SIZE_UPPER_BYTES, Validatable}; +use std::ffi::OsStr; use std::net::SocketAddr; use std::path::Path; use tracing::warn; @@ -413,20 +414,21 @@ impl ServerConfig { /// When running inside a container, a loopback listener means the server /// is unreachable from outside the container, which is warned. fn validate_client_facing_address(&self) -> Result<(), ConfigurationError> { - self.validate_client_facing_address_in_env(is_container()) + self.validate_client_facing_address_in_env(is_container())?; + Ok(()) } fn validate_client_facing_address_in_env( &self, is_container: bool, - ) -> Result<(), ConfigurationError> { + ) -> Result, ConfigurationError> { if self.cluster.enabled { - return Ok(()); + return Ok(None); } // No client-facing listener runs, so no client dials this node and // there is no address to demand. let Some(listener) = self.derived_address_listener() else { - return Ok(()); + return Ok(None); }; let bind = parse_bind_address(listener.key, listener.address)?; let ip = bind.ip().to_canonical(); @@ -441,30 +443,32 @@ impl ServerConfig { ); return Err(ConfigurationError::InvalidConfigurationValue); } - return Ok(()); + return Ok(None); } if ip.is_loopback() && is_container { let env_var = format!("IGGY_{}", listener.key.replace('.', "_").to_uppercase()); let port = bind.port(); - if self.node.advertised_address.is_none() { - warn!( + let msg = if self.node.advertised_address.is_none() { + format!( "{COMPONENT} - {} binds the loopback address {bind} inside a container; the \ server will not be reachable from outside the container. Set {env_var}=0.0.0.0:{port} \ together with IGGY_NODE_ADVERTISED_ADDRESS, or bind a concrete address.", listener.key - ); + ) } else { - warn!( + format!( "{COMPONENT} - {} binds the loopback address {bind} inside a container; the \ server will not be reachable from outside the container. Set {env_var}=0.0.0.0:{port} \ or bind a concrete address.", listener.key - ); - } + ) + }; + warn!("{msg}"); + return Ok(Some(msg)); } - Ok(()) + Ok(None) } } @@ -473,6 +477,8 @@ fn is_container() -> bool { is_container_indicators( Path::new("/.dockerenv"), Path::new("/run/.containerenv"), + std::env::var_os("container").as_deref(), + std::env::var_os("KUBERNETES_SERVICE_HOST").as_deref(), "/proc/self/cgroup", ) } @@ -480,15 +486,15 @@ fn is_container() -> bool { fn is_container_indicators( dockerenv_path: &Path, containerenv_path: &Path, + container_env: Option<&OsStr>, + k8s_env: Option<&OsStr>, cgroup_path: &str, ) -> bool { if dockerenv_path.exists() || containerenv_path.exists() { return true; } - if std::env::var_os("container").is_some() - || std::env::var_os("KUBERNETES_SERVICE_HOST").is_some() - { + if container_env.is_some() || k8s_env.is_some() { return true; } @@ -618,28 +624,53 @@ mod tests { } #[test] - fn given_loopback_bind_in_container_when_validating_should_pass() { + fn given_loopback_bind_in_container_when_validating_should_warn_and_pass() { let config = config_with_override( "[tcp]\naddress = \"127.0.0.1:8090\"\n[cluster]\nenabled = false\n", ); - assert!(config.validate_client_facing_address_in_env(true).is_ok()); + let warning = config + .validate_client_facing_address_in_env(true) + .expect("validation should pass"); + assert!( + warning.is_some(), + "loopback inside container must produce a warning" + ); + let message = warning.unwrap(); + assert!(message.contains("IGGY_TCP_ADDRESS=0.0.0.0:8090")); + assert!(message.contains("together with IGGY_NODE_ADVERTISED_ADDRESS")); } #[test] - fn given_loopback_bind_outside_container_when_validating_should_pass() { + fn given_loopback_bind_outside_container_when_validating_should_pass_without_warning() { let config = config_with_override( "[tcp]\naddress = \"127.0.0.1:8090\"\n[cluster]\nenabled = false\n", ); - assert!(config.validate_client_facing_address_in_env(false).is_ok()); + let warning = config + .validate_client_facing_address_in_env(false) + .expect("validation should pass"); + assert!( + warning.is_none(), + "loopback outside container must not produce a warning" + ); } #[test] - fn given_loopback_bind_in_container_with_advertised_address_when_validating_should_pass() { + fn given_loopback_bind_in_container_with_advertised_address_when_validating_should_warn_and_pass() + { let config = config_with_override( "[tcp]\naddress = \"127.0.0.1:8090\"\n[cluster]\nenabled = false\n\ [node]\nadvertised_address = \"broker-1.example.com\"\n", ); - assert!(config.validate_client_facing_address_in_env(true).is_ok()); + let warning = config + .validate_client_facing_address_in_env(true) + .expect("validation should pass"); + assert!( + warning.is_some(), + "loopback inside container must produce a warning" + ); + let message = warning.unwrap(); + assert!(message.contains("IGGY_TCP_ADDRESS=0.0.0.0:8090")); + assert!(!message.contains("together with IGGY_NODE_ADVERTISED_ADDRESS")); } #[test] @@ -648,7 +679,8 @@ mod tests { let marker = temp_dir.join(format!("test_dockerenv_{}", std::process::id())); std::fs::write(&marker, "").unwrap(); let non_existent = temp_dir.join("non_existent_indicator"); - let result = is_container_indicators(&marker, &non_existent, "/non/existent/cgroup"); + let result = + is_container_indicators(&marker, &non_existent, None, None, "/non/existent/cgroup"); let _ = std::fs::remove_file(&marker); assert!(result); } @@ -659,18 +691,44 @@ mod tests { let marker = temp_dir.join(format!("test_containerenv_{}", std::process::id())); std::fs::write(&marker, "").unwrap(); let non_existent = temp_dir.join("non_existent_indicator"); - let result = is_container_indicators(&non_existent, &marker, "/non/existent/cgroup"); + let result = + is_container_indicators(&non_existent, &marker, None, None, "/non/existent/cgroup"); let _ = std::fs::remove_file(&marker); assert!(result); } + #[test] + fn given_container_env_var_when_checking_container_should_return_true() { + let non_existent = Path::new("/non/existent/path/to/indicator"); + assert!(is_container_indicators( + non_existent, + non_existent, + Some(OsStr::new("docker")), + None, + "/non/existent/cgroup" + )); + } + + #[test] + fn given_kubernetes_env_var_when_checking_container_should_return_true() { + let non_existent = Path::new("/non/existent/path/to/indicator"); + assert!(is_container_indicators( + non_existent, + non_existent, + None, + Some(OsStr::new("10.0.0.1")), + "/non/existent/cgroup" + )); + } + #[test] fn given_missing_container_indicators_when_checking_container_should_return_false() { let non_existent = Path::new("/non/existent/path/to/indicator"); - // Safe check without environment variables assert!(!is_container_indicators( non_existent, non_existent, + None, + None, "/non/existent/cgroup" )); } From 2a2945c2fb0634b0d44b37949bf6e124bbad1602 Mon Sep 17 00:00:00 2001 From: kunaldevxxx Date: Fri, 18 Sep 2026 17:03:52 +0530 Subject: [PATCH 3/4] fix(server): improve loopback validation --- core/configs/src/server_config/validators.rs | 179 ++++++++++++------- 1 file changed, 117 insertions(+), 62 deletions(-) diff --git a/core/configs/src/server_config/validators.rs b/core/configs/src/server_config/validators.rs index 6feb200617..77dc2ab28c 100644 --- a/core/configs/src/server_config/validators.rs +++ b/core/configs/src/server_config/validators.rs @@ -26,15 +26,14 @@ use super::COMPONENT; use super::cluster::STATE_CHUNK_HEADER_LEN; use super::partition::{CONCURRENT_SERVED_SEGMENTS, SEGMENT_SIZE_OVERSHOOT_BYTES}; use super::server::ServerConfig; -use crate::ConfigurationError; use crate::common::http::HMAC_JWT_ALGORITHMS; use crate::common::validators::SEGMENT_MAX_SIZE_BYTES; +use crate::{ConfigEnvMappings, ConfigurationError}; use err_trail::ErrContext; use iggy_common::{IggyExpiry, MAX_MESSAGE_SIZE_UPPER_BYTES, Validatable}; use std::ffi::OsStr; use std::net::SocketAddr; use std::path::Path; -use tracing::warn; /// compio-ws (tungstenite 0.29) `write_buffer_size` default. Used to /// evaluate the `max_write_buffer_size > write_buffer_size` invariant @@ -411,8 +410,8 @@ impl ServerConfig { /// The listener the client-facing address is derived from must not bind a /// wildcard unless that address is declared outright. /// - /// When running inside a container, a loopback listener means the server - /// is unreachable from outside the container, which is warned. + /// When running inside a container, any client listener binding loopback + /// is unreachable from outside that network namespace, which is warned. fn validate_client_facing_address(&self) -> Result<(), ConfigurationError> { self.validate_client_facing_address_in_env(is_container())?; Ok(()) @@ -421,19 +420,14 @@ impl ServerConfig { fn validate_client_facing_address_in_env( &self, is_container: bool, - ) -> Result, ConfigurationError> { + ) -> Result, ConfigurationError> { if self.cluster.enabled { - return Ok(None); + return Ok(Vec::new()); } - // No client-facing listener runs, so no client dials this node and - // there is no address to demand. - let Some(listener) = self.derived_address_listener() else { - return Ok(None); - }; - let bind = parse_bind_address(listener.key, listener.address)?; - let ip = bind.ip().to_canonical(); - if ip.is_unspecified() { - if self.node.advertised_address.is_none() { + + if let Some(listener) = self.derived_address_listener() { + let bind = parse_bind_address(listener.key, listener.address)?; + if bind.ip().to_canonical().is_unspecified() && self.node.advertised_address.is_none() { eprintln!( "{COMPONENT} - {} binds the wildcard {bind}, which says which interfaces this node \ accepts on rather than where a client reaches it, so cluster metadata would carry no \ @@ -443,35 +437,52 @@ impl ServerConfig { ); return Err(ConfigurationError::InvalidConfigurationValue); } - return Ok(None); } - if ip.is_loopback() && is_container { - let env_var = format!("IGGY_{}", listener.key.replace('.', "_").to_uppercase()); - let port = bind.port(); - let msg = if self.node.advertised_address.is_none() { - format!( - "{COMPONENT} - {} binds the loopback address {bind} inside a container; the \ - server will not be reachable from outside the container. Set {env_var}=0.0.0.0:{port} \ - together with IGGY_NODE_ADVERTISED_ADDRESS, or bind a concrete address.", - listener.key - ) - } else { - format!( + let mut warnings = Vec::new(); + for listener in self.client_listeners() { + if !listener.enabled { + continue; + } + let bind = parse_bind_address(listener.key, listener.address)?; + let ip = bind.ip().to_canonical(); + + if ip.is_loopback() && is_container { + let env_var = ServerConfig::find_by_config_path(listener.key) + .map_or(listener.key, |m| m.env_name); + let port = bind.port(); + let hint = if self.node.advertised_address.is_none() { + format!( + " Set {env_var}=0.0.0.0:{port} together with IGGY_NODE_ADVERTISED_ADDRESS, or bind a concrete address." + ) + } else { + format!(" Set {env_var} or bind a concrete address.") + }; + let msg = format!( "{COMPONENT} - {} binds the loopback address {bind} inside a container; the \ - server will not be reachable from outside the container. Set {env_var}=0.0.0.0:{port} \ - or bind a concrete address.", + server will not be reachable from outside this network namespace.{hint}", listener.key - ) - }; - warn!("{msg}"); - return Ok(Some(msg)); + ); + eprintln!("{msg}"); + warnings.push(msg); + } } - Ok(None) + Ok(warnings) } } +const CONTAINER_CGROUP_MARKERS: &[&str] = &[ + "/docker/", + "/docker-", + "/libpod-", + "/podman/", + "/kubepods/", + "/kubepods-", + "/containerd/", + "/lxc/", +]; + /// Returns true when the process is executing inside a container. fn is_container() -> bool { is_container_indicators( @@ -502,20 +513,16 @@ fn is_container_indicators( { if let Ok(cgroup) = std::fs::read_to_string(cgroup_path) && cgroup.lines().any(|line| { - line.contains("/docker/") - || line.contains("/docker-") - || line.contains("/libpod-") - || line.contains("/podman/") - || line.contains("/kubepods/") - || line.contains("/kubepods-") - || line.contains("/containerd/") - || line.contains("/lxc/") + CONTAINER_CGROUP_MARKERS + .iter() + .any(|marker| line.contains(marker)) }) { return true; } } + #[cfg(not(target_os = "linux"))] let _ = cgroup_path; false @@ -628,16 +635,18 @@ mod tests { let config = config_with_override( "[tcp]\naddress = \"127.0.0.1:8090\"\n[cluster]\nenabled = false\n", ); - let warning = config + let warnings = config .validate_client_facing_address_in_env(true) .expect("validation should pass"); - assert!( - warning.is_some(), - "loopback inside container must produce a warning" - ); - let message = warning.unwrap(); - assert!(message.contains("IGGY_TCP_ADDRESS=0.0.0.0:8090")); - assert!(message.contains("together with IGGY_NODE_ADVERTISED_ADDRESS")); + assert_eq!(warnings.len(), 4); + for warning in &warnings { + assert!(warning.contains("outside this network namespace")); + assert!(warning.contains("together with IGGY_NODE_ADVERTISED_ADDRESS")); + } + assert!(warnings[0].contains("IGGY_TCP_ADDRESS=0.0.0.0:8090")); + assert!(warnings[1].contains("IGGY_WEBSOCKET_ADDRESS=0.0.0.0:8092")); + assert!(warnings[2].contains("IGGY_QUIC_ADDRESS=0.0.0.0:8080")); + assert!(warnings[3].contains("IGGY_HTTP_ADDRESS=0.0.0.0:3000")); } #[test] @@ -645,11 +654,11 @@ mod tests { let config = config_with_override( "[tcp]\naddress = \"127.0.0.1:8090\"\n[cluster]\nenabled = false\n", ); - let warning = config + let warnings = config .validate_client_facing_address_in_env(false) .expect("validation should pass"); assert!( - warning.is_none(), + warnings.is_empty(), "loopback outside container must not produce a warning" ); } @@ -658,19 +667,21 @@ mod tests { fn given_loopback_bind_in_container_with_advertised_address_when_validating_should_warn_and_pass() { let config = config_with_override( - "[tcp]\naddress = \"127.0.0.1:8090\"\n[cluster]\nenabled = false\n\ + "[tcp]\naddress = \"0.0.0.0:8090\"\n[cluster]\nenabled = false\n\ [node]\nadvertised_address = \"broker-1.example.com\"\n", ); - let warning = config + let warnings = config .validate_client_facing_address_in_env(true) .expect("validation should pass"); - assert!( - warning.is_some(), - "loopback inside container must produce a warning" - ); - let message = warning.unwrap(); - assert!(message.contains("IGGY_TCP_ADDRESS=0.0.0.0:8090")); - assert!(!message.contains("together with IGGY_NODE_ADVERTISED_ADDRESS")); + assert_eq!(warnings.len(), 3); + for warning in &warnings { + assert!(warning.contains("outside this network namespace")); + assert!(!warning.contains("0.0.0.0")); + assert!(!warning.contains("together with IGGY_NODE_ADVERTISED_ADDRESS")); + } + assert!(warnings[0].contains("Set IGGY_WEBSOCKET_ADDRESS or bind a concrete address.")); + assert!(warnings[1].contains("Set IGGY_QUIC_ADDRESS or bind a concrete address.")); + assert!(warnings[2].contains("Set IGGY_HTTP_ADDRESS or bind a concrete address.")); } #[test] @@ -721,6 +732,50 @@ mod tests { )); } + #[cfg(target_os = "linux")] + #[test] + fn given_cgroup_with_docker_marker_when_checking_container_should_return_true() { + let temp_dir = std::env::temp_dir(); + let cgroup_file = temp_dir.join(format!("test_docker_cgroup_{}", std::process::id())); + std::fs::write( + &cgroup_file, + "0::/system.slice/docker-e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855.scope\n", + ) + .unwrap(); + let non_existent = temp_dir.join("non_existent_indicator"); + let result = is_container_indicators( + &non_existent, + &non_existent, + None, + None, + cgroup_file.to_str().unwrap(), + ); + let _ = std::fs::remove_file(&cgroup_file); + assert!(result); + } + + #[cfg(target_os = "linux")] + #[test] + fn given_host_cgroup_without_markers_when_checking_container_should_return_false() { + let temp_dir = std::env::temp_dir(); + let cgroup_file = temp_dir.join(format!("test_host_cgroup_{}", std::process::id())); + std::fs::write( + &cgroup_file, + "0::/user.slice/user-1000.slice/session-1.scope\n", + ) + .unwrap(); + let non_existent = temp_dir.join("non_existent_indicator"); + let result = is_container_indicators( + &non_existent, + &non_existent, + None, + None, + cgroup_file.to_str().unwrap(), + ); + let _ = std::fs::remove_file(&cgroup_file); + assert!(!result); + } + #[test] fn given_missing_container_indicators_when_checking_container_should_return_false() { let non_existent = Path::new("/non/existent/path/to/indicator"); From c4177a25f7c6501c60dbcc50c5dadbf682904369 Mon Sep 17 00:00:00 2001 From: kunaldevxxx Date: Fri, 18 Sep 2026 20:47:35 +0530 Subject: [PATCH 4/4] feat(server): add container cgroup markers for Linux and test environments --- core/configs/src/server_config/validators.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/core/configs/src/server_config/validators.rs b/core/configs/src/server_config/validators.rs index 77dc2ab28c..6e5b815677 100644 --- a/core/configs/src/server_config/validators.rs +++ b/core/configs/src/server_config/validators.rs @@ -472,6 +472,7 @@ impl ServerConfig { } } +#[cfg(any(target_os = "linux", test))] const CONTAINER_CGROUP_MARKERS: &[&str] = &[ "/docker/", "/docker-",