From 38553b6fddc7f6a667cdb45a6762343a08fc72b2 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Sat, 25 Jul 2026 06:27:01 +0200 Subject: [PATCH] fix: reject unsafe output options in Commit.count Commit.count forwards keyword arguments to git rev-list but did not apply the unsafe-option validation used by the sibling revision APIs. Validate forwarded options with the existing Git.check_unsafe_options helper and retain the explicit allow_unsafe_options escape hatch. This covers GHSA-p538-c434-8v24 without adding another option parser. Git baseline: git.git a23bace963 defines --output as a shared diff option consumed by setup_revisions; t/t6000-rev-list-misc.sh exercises that option with rev-list. Co-authored-by: GPT 5.6 --- git/objects/commit.py | 15 ++++++++++++++- test/test_commit.py | 5 +++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/git/objects/commit.py b/git/objects/commit.py index 1d8e8f071..3e435453d 100644 --- a/git/objects/commit.py +++ b/git/objects/commit.py @@ -269,13 +269,21 @@ def summary(self) -> Union[str, bytes]: else: return self.message.split(b"\n", 1)[0] - def count(self, paths: Union[PathLike, Sequence[PathLike]] = "", **kwargs: Any) -> int: + def count( + self, + paths: Union[PathLike, Sequence[PathLike]] = "", + allow_unsafe_options: bool = False, + **kwargs: Any, + ) -> int: """Count the number of commits reachable from this commit. :param paths: An optional path or a list of paths restricting the return value to commits actually containing the paths. + :param allow_unsafe_options: + Allow unsafe options, like ``--output``. + :param kwargs: Additional options to be passed to :manpage:`git-rev-list(1)`. They must not alter the output style of the command, or parsing will yield incorrect @@ -284,6 +292,11 @@ def count(self, paths: Union[PathLike, Sequence[PathLike]] = "", **kwargs: Any) :return: An int defining the number of reachable commits """ + if not allow_unsafe_options: + Git.check_unsafe_options( + options=Git._option_candidates([], kwargs), unsafe_options=self.unsafe_git_rev_options + ) + # Yes, it makes a difference whether empty paths are given or not in our case as # the empty paths version will ignore merge commits for some reason. if paths: diff --git a/test/test_commit.py b/test/test_commit.py index 74b7078f5..cb0427740 100644 --- a/test/test_commit.py +++ b/test/test_commit.py @@ -301,6 +301,11 @@ def test_iter_items_rejects_unsafe_options(self): with self.assertRaises(UnsafeOptionError): list(Commit.iter_items(self.rorepo, "HEAD", output=marker)) + def test_count_rejects_unsafe_options(self): + with tempfile.NamedTemporaryFile() as marker: + with self.assertRaises(UnsafeOptionError): + self.rorepo.head.commit.count(output=marker.name) + def test_rev_list_bisect_all(self): """ 'git rev-list --bisect-all' returns additional information