hex: allow only lowercase object IDs in breaking changes mode

Git has historically allowed either lowercase or uppercase hex for
object IDs, but it has always emitted only lowercase.  This has caused
people to expect only lowercase and not handle uppercase.

As an example, Git's own example hooks look for "[0-9a-f]" in several
places, but there are many other Git-adjacent pieces of software,
including Gitolite, which make the assumption that object IDs are always
lowercase.  This is not to criticize the authors of these projects, but
rather to point out how common this assumption is.  In fact, it's so
common that we have only one test in our codebase that fails when we
reject uppercase object IDs.

More critically, it leads people to make security-based assumptions that
an object ID either does not contain uppercase characters or that an
object ID can be expressed uniquely in hex form, neither of which are
currently true.  Git itself normally uses binary object IDs, which
avoids many of these problems, but most other projects deal primarily in
hex object IDs, so they are more affected.

In preparation for Git 3.0, only allow lowercase hex object IDs in
breaking changes mode and document this as well.  Update the single
failing test and add a new one to verify we reject new uppercase object
IDs.  Note that in t5324, we change the hex character from "A" to "b"
because in SHA-256 mode, "a" is the correct value, so our test_must_fail
assertion will unexpectedly succeed in that case.

Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
brian m. carlson
2026-07-29 23:32:15 +00:00
committed by Junio C Hamano
parent 7233f519c7
commit 4a1cd4a223
4 changed files with 16 additions and 2 deletions

View File

@@ -171,6 +171,11 @@ JGit, libgit2 and Gitoxide need to support it.
matches the default branch name used in new repositories by many of the
big Git forges.
* Git will accept hex object IDs only in lowercase. The fact that Git has
historically allowed uppercase characters in hex object IDs has been the
source of a variety of bugs and security problems in software using Git. We
don't expect most users to notice any change.
* Git will require Rust as a mandatory part of the build process. While Git
already started to adopt Rust in Git 2.49, all parts written in Rust are
optional for the time being. This includes:

View File

@@ -6,7 +6,11 @@ enum hexkind {
HEX_KIND_LOWER = 1,
};
#ifdef WITH_BREAKING_CHANGES
#define HEX_KIND_OID HEX_KIND_LOWER
#else
#define HEX_KIND_OID HEX_KIND_MIXED
#endif
extern const signed char hexval_table[256];
extern const signed char hexval_lc_table[256];

View File

@@ -60,6 +60,11 @@ test_expect_success 'works with one good rev' '
test "$rev_head" = "$HASH4"
'
test_expect_success WITH_BREAKING_CHANGES 'rejects uppercase revs' '
UC_HASH=$(echo "$HASH1" | tr a-f A-F) &&
test_must_fail git rev-parse --verify "$UC_HASH"
'
test_expect_success 'fails with any bad rev or many good revs' '
test_must_fail git rev-parse --verify 2>error &&
test_grep "single revision" error &&

View File

@@ -349,7 +349,7 @@ test_expect_success 'verify after commit-graph-chain corruption (base)' '
test_must_fail git commit-graph verify 2>test_err &&
grep -v "^+" test_err >err &&
test_grep "invalid commit-graph chain" err &&
corrupt_file "$graphdir/commit-graph-chain" 30 "A" &&
corrupt_file "$graphdir/commit-graph-chain" 30 "a" &&
test_must_fail git commit-graph verify 2>test_err &&
grep -v "^+" test_err >err &&
test_grep "unable to find all commit-graph files" err
@@ -364,7 +364,7 @@ test_expect_success 'verify after commit-graph-chain corruption (tip)' '
test_must_fail git commit-graph verify 2>test_err &&
grep -v "^+" test_err >err &&
test_grep "invalid commit-graph chain" err &&
corrupt_file "$graphdir/commit-graph-chain" 70 "A" &&
corrupt_file "$graphdir/commit-graph-chain" 70 "b" &&
test_must_fail git commit-graph verify 2>test_err &&
grep -v "^+" test_err >err &&
test_grep "unable to find all commit-graph files" err