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>
This commit is contained in:
Gavin Mak
2026-09-02 17:41:05 -07:00
committed by gerrit-scoped@luci-project-accounts.iam.gserviceaccount.com
parent c63a2f92fa
commit 948abc85bc
3 changed files with 55 additions and 3 deletions
+1 -1
View File
@@ -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 = {}
+2 -2
View File
@@ -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),
+52
View File
@@ -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.