Merge pull request #1521 from stsewd/block-insecure-options · gitpython-developers/GitPython@678a8fe

@@ -539,6 +539,23 @@ class Remote(LazyMixin, IterableObj):

539539

__slots__ = ("repo", "name", "_config_reader")

540540

_id_attribute_ = "name"

541541542+

unsafe_git_fetch_options = [

543+

# This option allows users to execute arbitrary commands.

544+

# https://git-scm.com/docs/git-fetch#Documentation/git-fetch.txt---upload-packltupload-packgt

545+

"--upload-pack",

546+

]

547+

unsafe_git_pull_options = [

548+

# This option allows users to execute arbitrary commands.

549+

# https://git-scm.com/docs/git-pull#Documentation/git-pull.txt---upload-packltupload-packgt

550+

"--upload-pack"

551+

]

552+

unsafe_git_push_options = [

553+

# This option allows users to execute arbitrary commands.

554+

# https://git-scm.com/docs/git-push#Documentation/git-push.txt---execltgit-receive-packgt

555+

"--receive-pack",

556+

"--exec",

557+

]

558+542559

def __init__(self, repo: "Repo", name: str) -> None:

543560

"""Initialize a remote instance

544561

@@ -615,7 +632,9 @@ def iter_items(cls, repo: "Repo", *args: Any, **kwargs: Any) -> Iterator["Remote

615632

yield Remote(repo, section[lbound + 1 : rbound])

616633

# END for each configuration section

617634618-

def set_url(self, new_url: str, old_url: Optional[str] = None, **kwargs: Any) -> "Remote":

635+

def set_url(

636+

self, new_url: str, old_url: Optional[str] = None, allow_unsafe_protocols: bool = False, **kwargs: Any

637+

) -> "Remote":

619638

"""Configure URLs on current remote (cf command git remote set_url)

620639621640

This command manages URLs on the remote.

@@ -624,15 +643,17 @@ def set_url(self, new_url: str, old_url: Optional[str] = None, **kwargs: Any) ->

624643

:param old_url: when set, replaces this URL with new_url for the remote

625644

:return: self

626645

"""

646+

if not allow_unsafe_protocols:

647+

Git.check_unsafe_protocols(new_url)

627648

scmd = "set-url"

628649

kwargs["insert_kwargs_after"] = scmd

629650

if old_url:

630-

self.repo.git.remote(scmd, self.name, new_url, old_url, **kwargs)

651+

self.repo.git.remote(scmd, "--", self.name, new_url, old_url, **kwargs)

631652

else:

632-

self.repo.git.remote(scmd, self.name, new_url, **kwargs)

653+

self.repo.git.remote(scmd, "--", self.name, new_url, **kwargs)

633654

return self

634655635-

def add_url(self, url: str, **kwargs: Any) -> "Remote":

656+

def add_url(self, url: str, allow_unsafe_protocols: bool = False, **kwargs: Any) -> "Remote":

636657

"""Adds a new url on current remote (special case of git remote set_url)

637658638659

This command adds new URLs to a given remote, making it possible to have

@@ -641,7 +662,7 @@ def add_url(self, url: str, **kwargs: Any) -> "Remote":

641662

:param url: string being the URL to add as an extra remote URL

642663

:return: self

643664

"""

644-

return self.set_url(url, add=True)

665+

return self.set_url(url, add=True, allow_unsafe_protocols=allow_unsafe_protocols)

645666646667

def delete_url(self, url: str, **kwargs: Any) -> "Remote":

647668

"""Deletes a new url on current remote (special case of git remote set_url)

@@ -733,7 +754,7 @@ def stale_refs(self) -> IterableList[Reference]:

733754

return out_refs

734755735756

@classmethod

736-

def create(cls, repo: "Repo", name: str, url: str, **kwargs: Any) -> "Remote":

757+

def create(cls, repo: "Repo", name: str, url: str, allow_unsafe_protocols: bool = False, **kwargs: Any) -> "Remote":

737758

"""Create a new remote to the given repository

738759

:param repo: Repository instance that is to receive the new remote

739760

:param name: Desired name of the remote

@@ -743,7 +764,10 @@ def create(cls, repo: "Repo", name: str, url: str, **kwargs: Any) -> "Remote":

743764

:raise GitCommandError: in case an origin with that name already exists"""

744765

scmd = "add"

745766

kwargs["insert_kwargs_after"] = scmd

746-

repo.git.remote(scmd, name, Git.polish_url(url), **kwargs)

767+

url = Git.polish_url(url)

768+

if not allow_unsafe_protocols:

769+

Git.check_unsafe_protocols(url)

770+

repo.git.remote(scmd, "--", name, url, **kwargs)

747771

return cls(repo, name)

748772749773

# add is an alias

@@ -925,6 +949,8 @@ def fetch(

925949

progress: Union[RemoteProgress, None, "UpdateProgress"] = None,

926950

verbose: bool = True,

927951

kill_after_timeout: Union[None, float] = None,

952+

allow_unsafe_protocols: bool = False,

953+

allow_unsafe_options: bool = False,

928954

**kwargs: Any,

929955

) -> IterableList[FetchInfo]:

930956

"""Fetch the latest changes for this remote

@@ -967,6 +993,14 @@ def fetch(

967993

else:

968994

args = [refspec]

969995996+

if not allow_unsafe_protocols:

997+

for ref in args:

998+

if ref:

999+

Git.check_unsafe_protocols(ref)

1000+1001+

if not allow_unsafe_options:

1002+

Git.check_unsafe_options(options=list(kwargs.keys()), unsafe_options=self.unsafe_git_fetch_options)

1003+9701004

proc = self.repo.git.fetch(

9711005

"--", self, *args, as_process=True, with_stdout=False, universal_newlines=True, v=verbose, **kwargs

9721006

)

@@ -980,6 +1014,8 @@ def pull(

9801014

refspec: Union[str, List[str], None] = None,

9811015

progress: Union[RemoteProgress, "UpdateProgress", None] = None,

9821016

kill_after_timeout: Union[None, float] = None,

1017+

allow_unsafe_protocols: bool = False,

1018+

allow_unsafe_options: bool = False,

9831019

**kwargs: Any,

9841020

) -> IterableList[FetchInfo]:

9851021

"""Pull changes from the given branch, being the same as a fetch followed

@@ -994,6 +1030,15 @@ def pull(

9941030

# No argument refspec, then ensure the repo's config has a fetch refspec.

9951031

self._assert_refspec()

9961032

kwargs = add_progress(kwargs, self.repo.git, progress)

1033+1034+

refspec = Git._unpack_args(refspec or [])

1035+

if not allow_unsafe_protocols:

1036+

for ref in refspec:

1037+

Git.check_unsafe_protocols(ref)

1038+1039+

if not allow_unsafe_options:

1040+

Git.check_unsafe_options(options=list(kwargs.keys()), unsafe_options=self.unsafe_git_pull_options)

1041+9971042

proc = self.repo.git.pull(

9981043

"--", self, refspec, with_stdout=False, as_process=True, universal_newlines=True, v=True, **kwargs

9991044

)

@@ -1007,6 +1052,8 @@ def push(

10071052

refspec: Union[str, List[str], None] = None,

10081053

progress: Union[RemoteProgress, "UpdateProgress", Callable[..., RemoteProgress], None] = None,

10091054

kill_after_timeout: Union[None, float] = None,

1055+

allow_unsafe_protocols: bool = False,

1056+

allow_unsafe_options: bool = False,

10101057

**kwargs: Any,

10111058

) -> PushInfoList:

10121059

"""Push changes from source branch in refspec to target branch in refspec.

@@ -1037,6 +1084,15 @@ def push(

10371084

be 0.

10381085

Call ``.raise_if_error()`` on the returned object to raise on any failure."""

10391086

kwargs = add_progress(kwargs, self.repo.git, progress)

1087+1088+

refspec = Git._unpack_args(refspec or [])

1089+

if not allow_unsafe_protocols:

1090+

for ref in refspec:

1091+

Git.check_unsafe_protocols(ref)

1092+1093+

if not allow_unsafe_options:

1094+

Git.check_unsafe_options(options=list(kwargs.keys()), unsafe_options=self.unsafe_git_push_options)

1095+10401096

proc = self.repo.git.push(

10411097

"--",

10421098

self,