Block unsafe options and protocols by default · gitpython-developers/GitPython@e6108c7

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

535535

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

536536

_id_attribute_ = "name"

537537538+

unsafe_git_fetch_options = [

539+

# This option allows users to execute arbitrary commands.

540+

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

541+

"--upload-pack",

542+

]

543+

unsafe_git_pull_options = [

544+

# This option allows users to execute arbitrary commands.

545+

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

546+

"--upload-pack"

547+

]

548+

unsafe_git_push_options = [

549+

# This option allows users to execute arbitrary commands.

550+

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

551+

"--receive-pack",

552+

"--exec",

553+

]

554+538555

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

539556

"""Initialize a remote instance

540557

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

611628

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

612629

# END for each configuration section

613630614-

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

631+

def set_url(

632+

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

633+

) -> "Remote":

615634

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

616635617636

This command manages URLs on the remote.

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

620639

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

621640

:return: self

622641

"""

642+

if not allow_unsafe_protocols:

643+

Git.check_unsafe_protocols(new_url)

623644

scmd = "set-url"

624645

kwargs["insert_kwargs_after"] = scmd

625646

if old_url:

626-

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

647+

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

627648

else:

628-

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

649+

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

629650

return self

630651631-

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

652+

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

632653

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

633654634655

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

@@ -637,6 +658,8 @@ def add_url(self, url: str, **kwargs: Any) -> "Remote":

637658

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

638659

:return: self

639660

"""

661+

if not allow_unsafe_protocols:

662+

Git.check_unsafe_protocols(url)

640663

return self.set_url(url, add=True)

641664642665

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

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

729752

return out_refs

730753731754

@classmethod

732-

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

755+

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

733756

"""Create a new remote to the given repository

734757

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

735758

:param name: Desired name of the remote

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

739762

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

740763

scmd = "add"

741764

kwargs["insert_kwargs_after"] = scmd

742-

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

765+

url = Git.polish_url(url)

766+

if not allow_unsafe_protocols:

767+

Git.check_unsafe_protocols(url)

768+

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

743769

return cls(repo, name)

744770745771

# add is an alias

@@ -921,6 +947,8 @@ def fetch(

921947

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

922948

verbose: bool = True,

923949

kill_after_timeout: Union[None, float] = None,

950+

allow_unsafe_protocols: bool = False,

951+

allow_unsafe_options: bool = False,

924952

**kwargs: Any,

925953

) -> IterableList[FetchInfo]:

926954

"""Fetch the latest changes for this remote

@@ -963,6 +991,14 @@ def fetch(

963991

else:

964992

args = [refspec]

965993994+

if not allow_unsafe_protocols:

995+

for ref in args:

996+

if ref:

997+

Git.check_unsafe_protocols(ref)

998+999+

if not allow_unsafe_options:

1000+

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

1001+9661002

proc = self.repo.git.fetch(

9671003

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

9681004

)

@@ -976,6 +1012,8 @@ def pull(

9761012

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

9771013

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

9781014

kill_after_timeout: Union[None, float] = None,

1015+

allow_unsafe_protocols: bool = False,

1016+

allow_unsafe_options: bool = False,

9791017

**kwargs: Any,

9801018

) -> IterableList[FetchInfo]:

9811019

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

@@ -990,6 +1028,16 @@ def pull(

9901028

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

9911029

self._assert_refspec()

9921030

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

1031+1032+

if not allow_unsafe_protocols and refspec:

1033+

if isinstance(refspec, str):

1034+

Git.check_unsafe_protocols(refspec)

1035+

else:

1036+

for ref in refspec:

1037+

Git.check_unsafe_protocols(ref)

1038+

if not allow_unsafe_options:

1039+

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

1040+9931041

proc = self.repo.git.pull(

9941042

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

9951043

)

@@ -1003,6 +1051,8 @@ def push(

10031051

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

10041052

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

10051053

kill_after_timeout: Union[None, float] = None,

1054+

allow_unsafe_protocols: bool = False,

1055+

allow_unsafe_options: bool = False,

10061056

**kwargs: Any,

10071057

) -> IterableList[PushInfo]:

10081058

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

@@ -1033,6 +1083,17 @@ def push(

10331083

If the operation fails completely, the length of the returned IterableList will

10341084

be 0."""

10351085

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

1086+1087+

if not allow_unsafe_protocols and refspec:

1088+

if isinstance(refspec, str):

1089+

Git.check_unsafe_protocols(refspec)

1090+

else:

1091+

for ref in refspec:

1092+

Git.check_unsafe_protocols(ref)

1093+1094+

if not allow_unsafe_options:

1095+

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

1096+10361097

proc = self.repo.git.push(

10371098

"--",

10381099

self,