@@ -161,6 +161,20 @@ class Repo:
161161 https://git-scm.com/docs/git-clone#Documentation/git-clone.txt---configltkeygtltvaluegt
162162 """
163163
164+ unsafe_git_archive_options = [
165+ # This option allows arbitrary command execution in git-archive.
166+ "--upload-pack" ,
167+ "--exec" ,
168+ ]
169+ """Options to :manpage:`git-archive(1)` that can be dangerous."""
170+
171+ unsafe_git_revision_options = [
172+ # This option allows output to be written to arbitrary files before revision parsing.
173+ "--output" ,
174+ "-o" ,
175+ ]
176+ """Options to :manpage:`git-rev-list(1)` / :manpage:`git-blame(1)` that can overwrite files."""
177+
164178 # Invariants
165179 config_level : ConfigLevels_Tup = ("system" , "user" , "global" , "repository" )
166180 """Represents the configuration level of a configuration file."""
@@ -775,6 +789,7 @@ def iter_commits(
775789 self ,
776790 rev : Union [str , Commit , "SymbolicReference" , None ] = None ,
777791 paths : Union [PathLike , Sequence [PathLike ]] = "" ,
792+ allow_unsafe_options : bool = False ,
778793 ** kwargs : Any ,
779794 ) -> Iterator [Commit ]:
780795 """An iterator of :class:`~git.objects.commit.Commit` objects representing the
@@ -792,6 +807,9 @@ def iter_commits(
792807 Arguments to be passed to :manpage:`git-rev-list(1)`.
793808 Common ones are ``max_count`` and ``skip``.
794809
810+ :param allow_unsafe_options:
811+ Allow unsafe options in the revision argument, like ``--output``.
812+
795813 :note:
796814 To receive only commits between two named revisions, use the
797815 ``"revA...revB"`` revision specifier.
@@ -802,7 +820,16 @@ def iter_commits(
802820 if rev is None :
803821 rev = self .head .commit
804822
805- return Commit .iter_items (self , rev , paths , ** kwargs )
823+ if not allow_unsafe_options :
824+ Git .check_unsafe_options (options = [str (rev )], unsafe_options = self .unsafe_git_revision_options )
825+
826+ return Commit .iter_items (
827+ self ,
828+ rev ,
829+ paths ,
830+ allow_unsafe_options = allow_unsafe_options ,
831+ ** kwargs ,
832+ )
806833
807834 def merge_base (self , * rev : TBD , ** kwargs : Any ) -> List [Commit ]:
808835 R"""Find the closest common ancestor for the given revision
@@ -1079,7 +1106,9 @@ def active_branch(self) -> Head:
10791106 )
10801107 return active_branch
10811108
1082- def blame_incremental (self , rev : str | HEAD | None , file : str , ** kwargs : Any ) -> Iterator ["BlameEntry" ]:
1109+ def blame_incremental (
1110+ self , rev : str | HEAD | None , file : str , allow_unsafe_options : bool = False , ** kwargs : Any
1111+ ) -> Iterator ["BlameEntry" ]:
10831112 """Iterator for blame information for the given file at the given revision.
10841113
10851114 Unlike :meth:`blame`, this does not return the actual file's contents, only a
@@ -1090,6 +1119,9 @@ def blame_incremental(self, rev: str | HEAD | None, file: str, **kwargs: Any) ->
10901119 uncommitted changes. Otherwise, anything successfully parsed by
10911120 :manpage:`git-rev-parse(1)` is a valid option.
10921121
1122+ :param allow_unsafe_options:
1123+ Allow unsafe options in revision argument, like ``--output``.
1124+
10931125 :return:
10941126 Lazy iterator of :class:`BlameEntry` tuples, where the commit indicates the
10951127 commit to blame for the line, and range indicates a span of line numbers in
@@ -1098,6 +1130,8 @@ def blame_incremental(self, rev: str | HEAD | None, file: str, **kwargs: Any) ->
10981130 If you combine all line number ranges outputted by this command, you should get
10991131 a continuous range spanning all line numbers in the file.
11001132 """
1133+ if not allow_unsafe_options :
1134+ Git .check_unsafe_options (options = [str (rev )], unsafe_options = self .unsafe_git_revision_options )
11011135
11021136 data : bytes = self .git .blame (rev , "--" , file , p = True , incremental = True , stdout_as_string = False , ** kwargs )
11031137 commits : Dict [bytes , Commit ] = {}
@@ -1177,6 +1211,7 @@ def blame(
11771211 file : str ,
11781212 incremental : bool = False ,
11791213 rev_opts : Optional [List [str ]] = None ,
1214+ allow_unsafe_options : bool = False ,
11801215 ** kwargs : Any ,
11811216 ) -> List [List [Commit | List [str | bytes ] | None ]] | Iterator [BlameEntry ] | None :
11821217 """The blame information for the given file at the given revision.
@@ -1186,6 +1221,9 @@ def blame(
11861221 uncommitted changes. Otherwise, anything successfully parsed by
11871222 :manpage:`git-rev-parse(1)` is a valid option.
11881223
1224+ :param allow_unsafe_options:
1225+ Allow unsafe options in revision argument, like ``--output``.
1226+
11891227 :return:
11901228 list: [git.Commit, list: [<line>]]
11911229
@@ -1195,7 +1233,9 @@ def blame(
11951233 appearance.
11961234 """
11971235 if incremental :
1198- return self .blame_incremental (rev , file , ** kwargs )
1236+ return self .blame_incremental (rev , file , allow_unsafe_options = allow_unsafe_options , ** kwargs )
1237+ if not allow_unsafe_options :
1238+ Git .check_unsafe_options (options = [str (rev )], unsafe_options = self .unsafe_git_revision_options )
11991239 rev_opts = rev_opts or []
12001240 data : bytes = self .git .blame (rev , * rev_opts , "--" , file , p = True , stdout_as_string = False , ** kwargs )
12011241 commits : Dict [str , Commit ] = {}
@@ -1583,6 +1623,7 @@ def archive(
15831623 ostream : Union [TextIO , BinaryIO ],
15841624 treeish : Optional [str ] = None ,
15851625 prefix : Optional [str ] = None ,
1626+ allow_unsafe_options : bool = False ,
15861627 ** kwargs : Any ,
15871628 ) -> Repo :
15881629 """Archive the tree at the given revision.
@@ -1605,6 +1646,9 @@ def archive(
16051646 repository-relative path to a directory or file to place into the archive,
16061647 or a list or tuple of multiple paths.
16071648
1649+ :param allow_unsafe_options:
1650+ Allow unsafe options in ``kwargs``, like ``--exec`` or ``--upload-pack``.
1651+
16081652 :raise git.exc.GitCommandError:
16091653 If something went wrong.
16101654
@@ -1615,6 +1659,8 @@ def archive(
16151659 treeish = self .head .commit
16161660 if prefix and "prefix" not in kwargs :
16171661 kwargs ["prefix" ] = prefix
1662+ if not allow_unsafe_options :
1663+ Git .check_unsafe_options (options = list (kwargs .keys ()), unsafe_options = self .unsafe_git_archive_options )
16181664 kwargs ["output_stream" ] = ostream
16191665 path = kwargs .pop ("path" , [])
16201666 path = cast (Union [PathLike , List [PathLike ], Tuple [PathLike , ...]], path )
0 commit comments