Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add initial support for Git protocol v2 #1244

Merged
merged 12 commits into from
Jun 28, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
make Git protocol v2 work over SSH connections
  • Loading branch information
stspdotname committed Jun 25, 2024
commit 2400933b32d3f966f3bcdbfa2dad3c4e9e712100
24 changes: 23 additions & 1 deletion dulwich/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
* include-tag
"""

import copy
import logging
import os
import select
Expand Down Expand Up @@ -1847,6 +1848,7 @@ def run_command(
password=None,
key_filename=None,
ssh_command=None,
protocol_version: Optional[int] = None,
):
"""Connect to an SSH server.

Expand Down Expand Up @@ -1886,6 +1888,7 @@ def run_command(
password=None,
key_filename=None,
ssh_command=None,
protocol_version=None,
):
if password is not None:
raise NotImplementedError(
Expand All @@ -1905,6 +1908,9 @@ def run_command(
if key_filename:
args.extend(["-i", str(key_filename)])

if protocol_version is None or protocol_version == 2:
args.extend(["-o", "SetEnv GIT_PROTOCOL=version=2"])

if username:
host = f"{username}@{host}"
if host.startswith("-"):
Expand Down Expand Up @@ -1933,6 +1939,7 @@ def run_command(
password=None,
key_filename=None,
ssh_command=None,
protocol_version: Optional[int] = None,
):
if ssh_command:
import shlex
Expand Down Expand Up @@ -1964,12 +1971,22 @@ def run_command(
raise StrangeHostname(hostname=host)
args.append(host)

# plink.exe does not provide a way to pass environment variables
# via the command line. The best we can do is set an environment
# variable and hope that plink will pass it to the server. If this
# does not work then the server should behave as if we had requested
# protocol version 0.
env = copy.deepcopy(os.environ)
if protocol_version is None or protocol_version == 2:
env["GIT_PROTOCOL"] = "version=2"

proc = subprocess.Popen(
[*args, command],
bufsize=0,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
env=env,
)
return SubprocessWrapper(proc)

Expand Down Expand Up @@ -2064,7 +2081,12 @@ def _connect(self, cmd, path, protocol_version=None):
if self.ssh_command is not None:
kwargs["ssh_command"] = self.ssh_command
con = self.ssh_vendor.run_command(
self.host, argv, port=self.port, username=self.username, **kwargs
self.host,
argv,
port=self.port,
username=self.username,
protocol_version=protocol_version,
**kwargs,
)
return (
Protocol(
Expand Down
4 changes: 4 additions & 0 deletions dulwich/contrib/paramiko_vendor.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ def run_command(
password=None,
pkey=None,
key_filename=None,
protocol_version=None,
**kwargs,
):
client = paramiko.SSHClient()
Expand All @@ -110,6 +111,9 @@ def run_command(
# Open SSH session
channel = client.get_transport().open_session()

if protocol_version is None or protocol_version == 2:
channel.set_environment_variable(name="GIT_PROTOCOL", value="version=2")

# Run commands
channel.exec_command(command)

Expand Down
6 changes: 6 additions & 0 deletions tests/compat/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -429,16 +429,22 @@ def run_command(
port=None,
password=None,
key_filename=None,
protocol_version=None,
):
cmd, path = command.split(" ")
cmd = cmd.split("-", 1)
path = path.replace("'", "")
env = copy.deepcopy(os.environ)
jelmer marked this conversation as resolved.
Show resolved Hide resolved
if protocol_version is None or protocol_version == 2:
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we do the inverse here, i.e.

If protocol version is not set, set it to 2.

If protocol version != 0 then set this header.

That prepares us a bit better to future versions.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we can do that. I don't anticipate a new protocol version in the foreseeable future, but it doesn't hurt to handle things that way.

env["GIT_PROTOCOL"] = "version=2"

p = subprocess.Popen(
[*cmd, path],
bufsize=0,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
env=env,
)
return client.SubprocessWrapper(p)

Expand Down
10 changes: 8 additions & 2 deletions tests/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -714,6 +714,7 @@ def run_command(
password=None,
key_filename=None,
ssh_command=None,
protocol_version=None,
):
self.host = host
self.command = command
Expand All @@ -722,6 +723,7 @@ def run_command(
self.password = password
self.key_filename = key_filename
self.ssh_command = ssh_command
self.protocol_version = protocol_version

class Subprocess:
pass
Expand Down Expand Up @@ -1537,6 +1539,8 @@ def test_run_command_with_port_username_and_privkey(self):
"2200",
"-i",
"/tmp/id_rsa",
"-o",
"SetEnv GIT_PROTOCOL=version=2",
"user@host",
"git-clone-url",
]
Expand All @@ -1560,6 +1564,8 @@ def test_run_with_ssh_command(self):
"-o",
"Option=Value",
"-x",
"-o",
"SetEnv GIT_PROTOCOL=version=2",
"host",
"git-clone-url",
]
Expand Down Expand Up @@ -1702,12 +1708,12 @@ def test_run_command_with_port_username_and_privkey(self):
def test_run_with_ssh_command(self):
expected = [
"/path/to/plink",
"-x",
"-ssh",
"host",
"git-clone-url",
]

vendor = SubprocessSSHVendor()
vendor = PLinkSSHVendor()
command = vendor.run_command(
"host",
"git-clone-url",
Expand Down