From 9dcf884ad083a35fa4cc3b7889a0eae2e437470d Mon Sep 17 00:00:00 2001 From: Felix Zwettler Date: Tue, 3 Feb 2026 14:48:48 +0100 Subject: [PATCH] fix: handling of empty password in SSHDriver and NetworkService Signed-off-by: Felix Zwettler --- doc/configuration.rst | 2 +- labgrid/driver/sshdriver.py | 15 +++++++++------ labgrid/resource/networkservice.py | 2 +- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/doc/configuration.rst b/doc/configuration.rst index c1fb58187..6b9d11760 100644 --- a/doc/configuration.rst +++ b/doc/configuration.rst @@ -675,7 +675,7 @@ These and the sudo configuration needs to be prepared by the administrator. Arguments: - address (str): hostname of the remote system - username (str): username used by SSH - - password (str, default=""): password used by SSH + - password (str, default=None): optional, password used by SSH - port (int, default=22): port used by SSH Used by: diff --git a/labgrid/driver/sshdriver.py b/labgrid/driver/sshdriver.py index fdee16b72..110a4f707 100644 --- a/labgrid/driver/sshdriver.py +++ b/labgrid/driver/sshdriver.py @@ -36,7 +36,7 @@ class SSHDriver(CommandMixin, Driver, CommandProtocol, FileTransferProtocol): explicit_sftp_mode = attr.ib(default=False, validator=attr.validators.instance_of(bool)) explicit_scp_mode = attr.ib(default=False, validator=attr.validators.instance_of(bool)) username = attr.ib(default="", validator=attr.validators.instance_of(str)) - password = attr.ib(default="", validator=attr.validators.instance_of(str)) + password = attr.ib(default=None, validator=attr.validators.optional(attr.validators.instance_of(str))) def __attrs_post_init__(self): super().__attrs_post_init__() @@ -57,7 +57,9 @@ def _get_username(self): def _get_password(self): """Get the password from this class or from NetworkService""" - return self.password or self.networkservice.password + if self.password is not None: + return self.password + return self.networkservice.password def on_activate(self): self.ssh_prefix = ["-o", "LogLevel=ERROR"] @@ -66,7 +68,7 @@ def on_activate(self): if self.target.env: keyfile_path = self.target.env.config.resolve_path(self.keyfile) self.ssh_prefix += ["-i", keyfile_path ] - if not self._get_password(): + if self._get_password() is None: self.ssh_prefix += ["-o", "PasswordAuthentication=no"] self.control = self._start_own_master() @@ -136,14 +138,15 @@ def _start_own_master_once(self, timeout): env = os.environ.copy() pass_file = '' - if self._get_password(): + password = self._get_password() + if password is not None: fd, pass_file = tempfile.mkstemp() os.fchmod(fd, stat.S_IRWXU) #with openssh>=8.4 SSH_ASKPASS_REQUIRE can be used to force SSH_ASK_PASS #openssh<8.4 requires the DISPLAY var and a detached process with start_new_session=True env = {'SSH_ASKPASS': pass_file, 'DISPLAY':'', 'SSH_ASKPASS_REQUIRE':'force'} with open(fd, 'w') as f: - f.write("#!/bin/sh\necho " + shlex.quote(self._get_password())) + f.write("#!/bin/sh\necho " + shlex.quote(password)) self.process = subprocess.Popen(args, env=env, stdout=subprocess.PIPE, @@ -180,7 +183,7 @@ def _start_own_master_once(self, timeout): f"Subprocess timed out [{subprocess_timeout}s] while executing {args}", ) finally: - if self._get_password() and os.path.exists(pass_file): + if self._get_password() is not None and os.path.exists(pass_file): os.remove(pass_file) if not os.path.exists(control): diff --git a/labgrid/resource/networkservice.py b/labgrid/resource/networkservice.py index a00668598..832cfd707 100644 --- a/labgrid/resource/networkservice.py +++ b/labgrid/resource/networkservice.py @@ -9,5 +9,5 @@ class NetworkService(Resource): address = attr.ib(validator=attr.validators.instance_of(str)) username = attr.ib(validator=attr.validators.instance_of(str)) - password = attr.ib(default='', validator=attr.validators.instance_of(str)) + password = attr.ib(default=None, validator=attr.validators.optional(attr.validators.instance_of(str))) port = attr.ib(default=22, validator=attr.validators.instance_of(int))