1616import shlex
1717import shutil
1818import subprocess
19- import time
2019import textwrap
20+ import time
2121import uuid
2222from dataclasses import dataclass
2323from difflib import get_close_matches
@@ -60,6 +60,7 @@ def resolve_command(self, ctx, args):
6060@dataclass
6161class SSHMITMCommandRunResult :
6262 """Result of executing a command via SSH MITM."""
63+
6364 return_code : int
6465 stdout : str
6566 stderr : str
@@ -69,15 +70,15 @@ class SSHMITMCommandRunResult:
6970class SSHMITMClient (DriverClient ):
7071 """
7172 Client for SSH MITM proxy driver.
72-
73+
7374 Provides secure SSH access where the private key never leaves the exporter.
7475 Commands are executed via gRPC - the driver runs SSH on behalf of the client.
7576 """
7677
77- def cli (self ):
78+ def cli (self ): # noqa: C901
7879 """Create CLI command for 'j ssh_mitm'."""
7980 client = self
80-
81+
8182 @click .group (
8283 "ssh" ,
8384 cls = DefaultCommandGroup ,
@@ -119,7 +120,7 @@ def run(ctx, args):
119120
120121 if result .return_code != 0 :
121122 ctx .exit (result .return_code )
122-
123+
123124 @ssh_cmd .command ("shell" )
124125 @click .option (
125126 "--repl" ,
@@ -131,7 +132,7 @@ def run(ctx, args):
131132 def shell (ctx , repl , ssh_args ):
132133 """
133134 Launch an SSH session through the MITM proxy.
134-
135+
135136 By default, spawns the system 'ssh' binary via port forwarding.
136137 Use --repl for the lightweight gRPC REPL shell.
137138 """
@@ -141,7 +142,7 @@ def shell(ctx, repl, ssh_args):
141142 exit_code = client ._launch_native_ssh (ssh_args )
142143 if exit_code != 0 :
143144 ctx .exit (exit_code )
144-
145+
145146 @ssh_cmd .command ("forward" )
146147 @click .option (
147148 "--host" ,
@@ -162,15 +163,15 @@ def shell(ctx, repl, ssh_args):
162163 def forward (local_host , local_port ):
163164 """
164165 Expose the MITM proxy as a local TCP port for native SSH/scp/rsync.
165-
166+
166167 Example:
167168 j ssh_mitm forward -p 2222
168169 ssh -p 2222 localhost
169170 """
170171 client ._start_forward (local_host , local_port )
171-
172+
172173 return ssh_cmd
173-
174+
174175 def _ensure_ssh_binary (self ) -> str :
175176 ssh_path = shutil .which ("ssh" )
176177 if not ssh_path :
@@ -198,59 +199,59 @@ def _launch_native_ssh(self, ssh_args: tuple[str, ...]) -> int:
198199 self .logger .debug ("Launching native SSH: %s" , shlex .join (ssh_command ))
199200 return subprocess .call (ssh_command )
200201
201- def _run_shell (self ):
202+ def _run_shell (self ): # noqa: C901
202203 """Run interactive shell via gRPC commands."""
203204 username = self .call ("get_default_username" ) or "user"
204205 hostname = "dut"
205-
206+
206207 try :
207208 result = self .execute (["hostname" , "-s" ])
208209 if result .return_code == 0 and result .stdout .strip ():
209210 hostname = result .stdout .strip ()
210211 except Exception as e :
211212 self .logger .debug ("Failed to get hostname: %s" , e )
212-
213+
213214 click .echo (f"Connected to { hostname } via SSH MITM proxy" )
214215 click .echo ("Type 'exit' or Ctrl+D to exit" )
215216 click .echo ()
216-
217+
217218 cwd = "~"
218-
219+
219220 while True :
220221 try :
221222 prompt = click .style (f"{ username } @{ hostname } " , fg = "green" , bold = True )
222223 prompt += click .style (":" , fg = "white" )
223224 prompt += click .style (cwd , fg = "blue" , bold = True )
224225 prompt += click .style ("$ " , fg = "white" )
225-
226+
226227 cmd = input (prompt )
227-
228+
228229 if not cmd .strip ():
229230 continue
230-
231+
231232 if cmd .strip () == "exit" :
232233 click .echo ("Connection closed." )
233234 break
234-
235+
235236 if cmd .strip ().startswith ("cd " ):
236237 new_dir = cmd .strip ()[3 :].strip ()
237238 result = self .execute (
238239 [
239240 "bash" ,
240241 "-c" ,
241- f' cd { shlex .quote (cwd )} 2>/dev/null; cd { shlex .quote (new_dir )} && pwd' ,
242+ f" cd { shlex .quote (cwd )} 2>/dev/null; cd { shlex .quote (new_dir )} && pwd" ,
242243 ]
243244 )
244245 if result .return_code == 0 and result .stdout .strip ():
245246 cwd = result .stdout .strip ()
246247 else :
247248 click .echo (f"cd: { new_dir } : No such file or directory" , err = True )
248249 continue
249-
250+
250251 if cmd .strip () == "cd" :
251252 cwd = "~"
252253 continue
253-
254+
254255 # Execute command in current directory using newline-delimited heredoc to avoid interpolation
255256 token = f"JSSHMITM_{ uuid .uuid4 ().hex } "
256257 script = (
@@ -265,20 +266,20 @@ def _run_shell(self):
265266 + "\n "
266267 )
267268 result = self .execute (["bash" , "-lc" , script ])
268-
269+
269270 if result .stdout :
270271 click .echo (result .stdout , nl = False )
271272 if result .stderr :
272273 click .echo (result .stderr , nl = False , err = True )
273-
274+
274275 except EOFError :
275276 click .echo ()
276277 click .echo ("Connection closed." )
277278 break
278279 except KeyboardInterrupt :
279280 click .echo ("^C" )
280281 continue
281-
282+
282283 def _start_forward (self , local_host : str , local_port : int ):
283284 """Expose the SSH MITM server on a local TCP port."""
284285 click .echo ("Starting local forward (Ctrl+C to stop)..." )
@@ -300,18 +301,18 @@ def _start_forward(self, local_host: str, local_port: int):
300301 def execute (self , args ) -> SSHMITMCommandRunResult :
301302 """
302303 Execute command on DUT via gRPC.
303-
304+
304305 The command is run on the exporter using the stored SSH key,
305306 then results are returned.
306307 """
307308 return_code , stdout , stderr = self .call ("execute_command" , * args )
308-
309+
309310 return SSHMITMCommandRunResult (
310311 return_code = return_code ,
311312 stdout = stdout ,
312313 stderr = stderr ,
313314 )
314-
315+
315316 def run (self , args ) -> SSHMITMCommandRunResult :
316317 """Alias for execute()."""
317318 return self .execute (args )
0 commit comments