@@ -48,6 +48,116 @@ impl DockerClient {
4848 } )
4949 }
5050
51+ /// Connect and auto-detect the network from the validator container
52+ /// This ensures challenge containers are on the same network as the validator
53+ pub async fn connect_auto_detect ( ) -> anyhow:: Result < Self > {
54+ let docker = Docker :: connect_with_local_defaults ( ) ?;
55+ docker. ping ( ) . await ?;
56+ info ! ( "Connected to Docker daemon" ) ;
57+
58+ // Try to detect the network from the current container
59+ let network_name = Self :: detect_validator_network_static ( & docker) . await
60+ . unwrap_or_else ( |e| {
61+ warn ! ( "Could not detect validator network: {}. Using default 'platform-network'" , e) ;
62+ "platform-network" . to_string ( )
63+ } ) ;
64+
65+ info ! ( network = %network_name, "Using network for challenge containers" ) ;
66+
67+ Ok ( Self {
68+ docker,
69+ network_name,
70+ } )
71+ }
72+
73+ /// Detect the network the validator container is running on
74+ async fn detect_validator_network_static ( docker : & Docker ) -> anyhow:: Result < String > {
75+ // Get our container ID
76+ let container_id = Self :: get_container_id_static ( ) ?;
77+
78+ // Inspect our container to find its networks
79+ let inspect = docker. inspect_container ( & container_id, None ) . await ?;
80+
81+ let networks = inspect
82+ . network_settings
83+ . as_ref ( )
84+ . and_then ( |ns| ns. networks . as_ref ( ) )
85+ . ok_or_else ( || anyhow:: anyhow!( "No network settings found" ) ) ?;
86+
87+ // Find a suitable network (prefer non-default networks)
88+ // Priority: user-defined bridge > any bridge > host
89+ let mut best_network: Option < String > = None ;
90+
91+ for ( name, _settings) in networks {
92+ // Skip host and none networks
93+ if name == "host" || name == "none" {
94+ continue ;
95+ }
96+ // Skip the default bridge network (containers can't communicate by name on it)
97+ if name == "bridge" {
98+ if best_network. is_none ( ) {
99+ best_network = Some ( name. clone ( ) ) ;
100+ }
101+ continue ;
102+ }
103+ // Any other network is preferred (user-defined bridge)
104+ best_network = Some ( name. clone ( ) ) ;
105+ break ;
106+ }
107+
108+ best_network. ok_or_else ( || anyhow:: anyhow!( "No suitable network found for validator container" ) )
109+ }
110+
111+ /// Static version of get_self_container_id for use before Self is constructed
112+ fn get_container_id_static ( ) -> anyhow:: Result < String > {
113+ // Method 1: Check hostname (Docker sets hostname to container ID by default)
114+ if let Ok ( hostname) = std:: env:: var ( "HOSTNAME" ) {
115+ // Docker container IDs are 12+ hex characters
116+ if hostname. len ( ) >= 12 && hostname. chars ( ) . all ( |c| c. is_ascii_hexdigit ( ) ) {
117+ return Ok ( hostname) ;
118+ }
119+ }
120+
121+ // Method 2: Parse from cgroup (works on Linux)
122+ if let Ok ( cgroup) = std:: fs:: read_to_string ( "/proc/self/cgroup" ) {
123+ for line in cgroup. lines ( ) {
124+ if let Some ( docker_pos) = line. rfind ( "/docker/" ) {
125+ let id = & line[ docker_pos + 8 ..] ;
126+ if id. len ( ) >= 12 {
127+ return Ok ( id[ ..12 ] . to_string ( ) ) ;
128+ }
129+ }
130+ if let Some ( containerd_pos) = line. rfind ( "cri-containerd-" ) {
131+ let id = & line[ containerd_pos + 15 ..] ;
132+ if id. len ( ) >= 12 {
133+ return Ok ( id[ ..12 ] . to_string ( ) ) ;
134+ }
135+ }
136+ }
137+ }
138+
139+ // Method 3: Check mountinfo
140+ if std:: path:: Path :: new ( "/.dockerenv" ) . exists ( ) {
141+ if let Ok ( mountinfo) = std:: fs:: read_to_string ( "/proc/self/mountinfo" ) {
142+ for line in mountinfo. lines ( ) {
143+ if line. contains ( "/docker/containers/" ) {
144+ if let Some ( start) = line. find ( "/docker/containers/" ) {
145+ let rest = & line[ start + 19 ..] ;
146+ if let Some ( end) = rest. find ( '/' ) {
147+ let id = & rest[ ..end] ;
148+ if id. len ( ) >= 12 {
149+ return Ok ( id[ ..12 ] . to_string ( ) ) ;
150+ }
151+ }
152+ }
153+ }
154+ }
155+ }
156+ }
157+
158+ anyhow:: bail!( "Not running in a Docker container or unable to determine container ID" )
159+ }
160+
51161 /// Ensure the Docker network exists
52162 pub async fn ensure_network ( & self ) -> anyhow:: Result < ( ) > {
53163 let networks = self . docker . list_networks :: < String > ( None ) . await ?;
0 commit comments