From b668ee796e8401f10524357530ae3b178a42a39c Mon Sep 17 00:00:00 2001 From: olmanqj Date: Thu, 9 Oct 2025 09:56:13 +0200 Subject: [PATCH 1/3] Added support for legacy SCP protocol. --- tbot/machine/linux/copy.py | 12 +++++++++++- tbot_contrib/utils.py | 10 ++++++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/tbot/machine/linux/copy.py b/tbot/machine/linux/copy.py index 229e0eb2..b08917b0 100644 --- a/tbot/machine/linux/copy.py +++ b/tbot/machine/linux/copy.py @@ -19,6 +19,7 @@ def _scp_copy( ssh_config: typing.List[str], authenticator: auth.Authenticator, use_multiplexing: bool, + use_legacy_protocol: bool ) -> None: local_host = local_path.host @@ -39,6 +40,9 @@ def _scp_copy( "-o", f"ControlPath={multiplexing_dir.at_host(local_host)}/%C", ] + + if use_legacy_protocol: + scp_command += ["-O"] if isinstance(authenticator, auth.NoneAuthenticator): scp_command += ["-o", "BatchMode=yes"] @@ -70,7 +74,7 @@ def _scp_copy( ) -def copy(p1: linux.Path[H1], p2: linux.Path[H2]) -> None: +def copy(p1: linux.Path[H1], p2: linux.Path[H2], use_legacy_protocol: bool=False) -> None: """ Copy a file, possibly from one host to another. @@ -93,6 +97,8 @@ def copy(p1: linux.Path[H1], p2: linux.Path[H2]) -> None: :param linux.Path p1: Exisiting path to be copied :param linux.Path p2: Target where ``p1`` should be copied + :param bool use_legacy_protocol: Use the legacy SCP protocol for file transfers + instead of the SFTP protocol (use -O option) .. note:: @@ -129,6 +135,7 @@ def copy(p1: linux.Path[H1], p2: linux.Path[H2]) -> None: ssh_config=p1.host.ssh_config, authenticator=p1.host.authenticator, use_multiplexing=p1.host.use_multiplexing, + use_legacy_protocol=use_legacy_protocol, ) elif isinstance(p2.host, connector.SSHConnector) and p2.host.host is p1.host: # Copy to an SSH machine @@ -143,6 +150,7 @@ def copy(p1: linux.Path[H1], p2: linux.Path[H2]) -> None: ssh_config=p2.host.ssh_config, authenticator=p2.host.authenticator, use_multiplexing=p2.host.use_multiplexing, + use_legacy_protocol=use_legacy_protocol, ) elif isinstance(p1.host, connector.SubprocessConnector) and ( isinstance(p2.host, connector.ParamikoConnector) @@ -160,6 +168,7 @@ def copy(p1: linux.Path[H1], p2: linux.Path[H2]) -> None: ssh_config=getattr(p2.host, "ssh_config", []), authenticator=p2.host.authenticator, use_multiplexing=p2.host.use_multiplexing, + use_legacy_protocol=use_legacy_protocol, ) elif isinstance(p2.host, connector.SubprocessConnector) and ( isinstance(p1.host, connector.ParamikoConnector) @@ -177,6 +186,7 @@ def copy(p1: linux.Path[H1], p2: linux.Path[H2]) -> None: ssh_config=getattr(p2.host, "ssh_config", []), authenticator=p1.host.authenticator, use_multiplexing=p1.host.use_multiplexing, + use_legacy_protocol=use_legacy_protocol, ) else: raise NotImplementedError(f"Can't copy from {p1.host} to {p2.host}!") diff --git a/tbot_contrib/utils.py b/tbot_contrib/utils.py index 739b23b4..f8f32400 100644 --- a/tbot_contrib/utils.py +++ b/tbot_contrib/utils.py @@ -189,6 +189,7 @@ def copy_to_dir( dest_dir: linux.Path[H2], *, hashcmp: bool = False, + use_legacy_protocol: bool=False, ) -> linux.Path[H2]: pass @@ -199,6 +200,7 @@ def copy_to_dir( dest_dir: linux.Path[H2], *, hashcmp: bool = False, + use_legacy_protocol: bool=False, ) -> typing.List[linux.Path[H2]]: pass @@ -208,6 +210,7 @@ def copy_to_dir( dest_dir: linux.Path[H2], *, hashcmp: bool = False, + use_legacy_protocol: bool=False, ) -> typing.Union[linux.Path[H2], typing.List[linux.Path[H2]]]: """ Copy one or more files to a directory @@ -230,6 +233,9 @@ def copy_to_dir( make the function verify checksums of each file before performing the copy. This is very useful to skip superfluous copying operations. + :param bool use_legacy_protocol: Use the legacy SCP protocol for file transfers + instead of the SFTP protocol (use -O option) + :returns: If a single ``sources`` path was passed, a single path is returned which points to the newly created copy. If multiple ``sources`` were passed (as an iterable), a list of paths for each @@ -306,9 +312,9 @@ def copy_to_dir( if hashcmp: if not _hashcmp(source, dest): - linux.copy(source, dest) + linux.copy(source, dest, use_legacy_protocol) else: - linux.copy(source, dest) + linux.copy(source, dest, use_legacy_protocol) if isinstance(sources, linux.Path): return dest_list[0] From 9a65cb4c2ee5bb0bddfb1b2821b66b96bc0d03d7 Mon Sep 17 00:00:00 2001 From: olmanqj Date: Tue, 14 Oct 2025 10:12:54 +0200 Subject: [PATCH 2/3] Revert "Added support for legacy SCP protocol." This reverts commit b668ee796e8401f10524357530ae3b178a42a39c. --- tbot/machine/linux/copy.py | 12 +----------- tbot_contrib/utils.py | 10 ++-------- 2 files changed, 3 insertions(+), 19 deletions(-) diff --git a/tbot/machine/linux/copy.py b/tbot/machine/linux/copy.py index b08917b0..229e0eb2 100644 --- a/tbot/machine/linux/copy.py +++ b/tbot/machine/linux/copy.py @@ -19,7 +19,6 @@ def _scp_copy( ssh_config: typing.List[str], authenticator: auth.Authenticator, use_multiplexing: bool, - use_legacy_protocol: bool ) -> None: local_host = local_path.host @@ -40,9 +39,6 @@ def _scp_copy( "-o", f"ControlPath={multiplexing_dir.at_host(local_host)}/%C", ] - - if use_legacy_protocol: - scp_command += ["-O"] if isinstance(authenticator, auth.NoneAuthenticator): scp_command += ["-o", "BatchMode=yes"] @@ -74,7 +70,7 @@ def _scp_copy( ) -def copy(p1: linux.Path[H1], p2: linux.Path[H2], use_legacy_protocol: bool=False) -> None: +def copy(p1: linux.Path[H1], p2: linux.Path[H2]) -> None: """ Copy a file, possibly from one host to another. @@ -97,8 +93,6 @@ def copy(p1: linux.Path[H1], p2: linux.Path[H2], use_legacy_protocol: bool=False :param linux.Path p1: Exisiting path to be copied :param linux.Path p2: Target where ``p1`` should be copied - :param bool use_legacy_protocol: Use the legacy SCP protocol for file transfers - instead of the SFTP protocol (use -O option) .. note:: @@ -135,7 +129,6 @@ def copy(p1: linux.Path[H1], p2: linux.Path[H2], use_legacy_protocol: bool=False ssh_config=p1.host.ssh_config, authenticator=p1.host.authenticator, use_multiplexing=p1.host.use_multiplexing, - use_legacy_protocol=use_legacy_protocol, ) elif isinstance(p2.host, connector.SSHConnector) and p2.host.host is p1.host: # Copy to an SSH machine @@ -150,7 +143,6 @@ def copy(p1: linux.Path[H1], p2: linux.Path[H2], use_legacy_protocol: bool=False ssh_config=p2.host.ssh_config, authenticator=p2.host.authenticator, use_multiplexing=p2.host.use_multiplexing, - use_legacy_protocol=use_legacy_protocol, ) elif isinstance(p1.host, connector.SubprocessConnector) and ( isinstance(p2.host, connector.ParamikoConnector) @@ -168,7 +160,6 @@ def copy(p1: linux.Path[H1], p2: linux.Path[H2], use_legacy_protocol: bool=False ssh_config=getattr(p2.host, "ssh_config", []), authenticator=p2.host.authenticator, use_multiplexing=p2.host.use_multiplexing, - use_legacy_protocol=use_legacy_protocol, ) elif isinstance(p2.host, connector.SubprocessConnector) and ( isinstance(p1.host, connector.ParamikoConnector) @@ -186,7 +177,6 @@ def copy(p1: linux.Path[H1], p2: linux.Path[H2], use_legacy_protocol: bool=False ssh_config=getattr(p2.host, "ssh_config", []), authenticator=p1.host.authenticator, use_multiplexing=p1.host.use_multiplexing, - use_legacy_protocol=use_legacy_protocol, ) else: raise NotImplementedError(f"Can't copy from {p1.host} to {p2.host}!") diff --git a/tbot_contrib/utils.py b/tbot_contrib/utils.py index f8f32400..739b23b4 100644 --- a/tbot_contrib/utils.py +++ b/tbot_contrib/utils.py @@ -189,7 +189,6 @@ def copy_to_dir( dest_dir: linux.Path[H2], *, hashcmp: bool = False, - use_legacy_protocol: bool=False, ) -> linux.Path[H2]: pass @@ -200,7 +199,6 @@ def copy_to_dir( dest_dir: linux.Path[H2], *, hashcmp: bool = False, - use_legacy_protocol: bool=False, ) -> typing.List[linux.Path[H2]]: pass @@ -210,7 +208,6 @@ def copy_to_dir( dest_dir: linux.Path[H2], *, hashcmp: bool = False, - use_legacy_protocol: bool=False, ) -> typing.Union[linux.Path[H2], typing.List[linux.Path[H2]]]: """ Copy one or more files to a directory @@ -233,9 +230,6 @@ def copy_to_dir( make the function verify checksums of each file before performing the copy. This is very useful to skip superfluous copying operations. - :param bool use_legacy_protocol: Use the legacy SCP protocol for file transfers - instead of the SFTP protocol (use -O option) - :returns: If a single ``sources`` path was passed, a single path is returned which points to the newly created copy. If multiple ``sources`` were passed (as an iterable), a list of paths for each @@ -312,9 +306,9 @@ def copy_to_dir( if hashcmp: if not _hashcmp(source, dest): - linux.copy(source, dest, use_legacy_protocol) + linux.copy(source, dest) else: - linux.copy(source, dest, use_legacy_protocol) + linux.copy(source, dest) if isinstance(sources, linux.Path): return dest_list[0] From ac644457b73bb2107e63f735cd742906ab7a031d Mon Sep 17 00:00:00 2001 From: olmanqj Date: Tue, 14 Oct 2025 17:26:22 +0200 Subject: [PATCH 3/3] Added support for legacy SCP protocol. --- tbot/machine/connector/ssh.py | 10 ++++++++++ tbot/machine/linux/copy.py | 4 ++++ 2 files changed, 14 insertions(+) diff --git a/tbot/machine/connector/ssh.py b/tbot/machine/connector/ssh.py index 7273c14f..db6cb07d 100644 --- a/tbot/machine/connector/ssh.py +++ b/tbot/machine/connector/ssh.py @@ -65,6 +65,16 @@ def ignore_hostkey(self) -> bool: """ return False + @property + def requires_legacy_scp(self) -> bool: + """ + Use the legacy SCP protocol for file transfers instead of the SFTP protocol. + + Forcing the use of the SCP protocol may be necessary for servers that do not + implement SFTP, for backwards compatibility. + """ + return False + @property def use_multiplexing(self) -> bool: """ diff --git a/tbot/machine/linux/copy.py b/tbot/machine/linux/copy.py index 229e0eb2..7e0f2a21 100644 --- a/tbot/machine/linux/copy.py +++ b/tbot/machine/linux/copy.py @@ -31,6 +31,10 @@ def _scp_copy( *[arg for opt in ssh_config for arg in ["-o", opt]], ] + use_legacy_protocol = getattr(remote_path.host, "requires_legacy_scp", False) + if use_legacy_protocol: + scp_command += ["-O"] + if use_multiplexing: multiplexing_dir = local_host.workdir / ".ssh-multi" scp_command += ["-o", "ControlMaster=auto"]