summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGavin Mak <gavinmak@google.com>2026-08-25 09:04:41 -0700
committergerrit-scoped@luci-project-accounts.iam.gserviceaccount.com <gerrit-scoped@luci-project-accounts.iam.gserviceaccount.com>2026-09-02 17:41:05 -0700
commit948abc85bcfd3f73d6cec4160506af325f721b71 (patch)
treeeac286d41867ca68089f940191ae2b8c19e81e61
parentc63a2f92fa9c01b1a58608a35f968da827b9ac3e (diff)
downloadgit-repo-948abc85bcfd3f73d6cec4160506af325f721b71.tar.gz
git-repo-948abc85bcfd3f73d6cec4160506af325f721b71.zip
git_config: recognize only complete object IDs
Full Git object IDs are exactly 40 hexadecimal digits for SHA-1 or 64 for SHA-256. Stop treating every intermediate length as immutable, which could bypass normal ref resolution for invalid revision strings. Bug: 553599402 Change-Id: I41b4ce6b2bfe2a2d8b351c7f040ec0cf469b474b Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/623901 Reviewed-by: Brian Gan <brgan@google.com> Tested-by: Gavin Mak <gavinmak@google.com> Commit-Queue: Gavin Mak <gavinmak@google.com>
-rw-r--r--git_config.py2
-rw-r--r--tests/test_git_config.py4
-rw-r--r--tests/test_project.py52
3 files changed, 55 insertions, 3 deletions
diff --git a/git_config.py b/git_config.py
index 888ae888c..84d347b1a 100644
--- a/git_config.py
+++ b/git_config.py
@@ -40,7 +40,7 @@ from repo_trace import Trace
# that is saved in the config.
SYNC_STATE_PREFIX = "repo.syncstate."
-ID_RE = re.compile(r"^[0-9a-f]{40,64}$")
+ID_RE = re.compile(r"^(?:[0-9a-f]{40}|[0-9a-f]{64})$")
REVIEW_CACHE = {}
diff --git a/tests/test_git_config.py b/tests/test_git_config.py
index 9583f3e9f..4b4e4cabb 100644
--- a/tests/test_git_config.py
+++ b/tests/test_git_config.py
@@ -256,8 +256,8 @@ def test_remote_save_with_push_url_without_projectname(
("0" * 64, True),
("f" * 64, True),
("a" * 39, False),
- ("a" * 41, True),
- ("a" * 63, True),
+ ("a" * 41, False),
+ ("a" * 63, False),
("a" * 65, False),
("g" * 40, False),
("g" * 64, False),
diff --git a/tests/test_project.py b/tests/test_project.py
index 57bb8c10c..3be80c5c2 100644
--- a/tests/test_project.py
+++ b/tests/test_project.py
@@ -1039,6 +1039,58 @@ class ProjectTests(unittest.TestCase):
self._get_derived_subproject_url(submodule_url),
)
+ def test_set_revision_object_id_lengths(self) -> None:
+ """SetRevision only treats exact 40- or 64-char hex as immutable IDs."""
+ with utils_for_test.TempGitTree() as tempdir:
+ proj = _create_mock_project(tempdir)
+
+ # SHA-1 (40 hex chars) is recorded as revisionId directly.
+ sha1 = "a" * 40
+ proj.SetRevision(sha1)
+ self.assertEqual(proj.revisionId, sha1)
+
+ # SHA-256 (64 hex chars) is recorded as revisionId directly.
+ sha256 = "b" * 64
+ proj.SetRevision(sha256)
+ self.assertEqual(proj.revisionId, sha256)
+
+ # Intermediate hex strings (41-63 chars) must not be treated
+ # as commit IDs.
+ for length in (41, 48, 63):
+ proj.SetRevision("c" * length)
+ self.assertIsNone(proj.revisionId)
+
+ def test_remote_fetch_intermediate_hex_not_fetched_as_commit_id(
+ self,
+ ) -> None:
+ """41-char hex revisions are not fetched as raw commit IDs on shallow
+ fetch."""
+ with utils_for_test.TempGitTree() as tempdir:
+ proj = _create_mock_project(tempdir)
+ proj.config.GetRemote("origin").ResetFetch()
+ hex41 = "a" * 41
+ proj.SetRevision(hex41)
+
+ with mock.patch("project.GitCommand") as mock_git:
+ mock_cmd = mock.MagicMock()
+ mock_cmd.Wait.return_value = 0
+ mock_git.return_value = mock_cmd
+
+ proj._RemoteFetch(depth=1, current_branch_only=True)
+
+ fetch_args = mock_git.call_args[0][1]
+ # When depth is set, commit IDs are passed directly to
+ # git fetch.
+ # Since 41 hex chars is not an ID, it must not appear as a
+ # standalone argument.
+ self.assertNotIn(hex41, fetch_args)
+ # Instead, it is treated as a branch ref and formatted
+ # as a refspec.
+ self.assertIn(
+ f"+refs/heads/{hex41}:refs/remotes/origin/{hex41}",
+ fetch_args,
+ )
+
class CopyLinkTestCase(unittest.TestCase):
"""TestCase for stub repo client checkouts.