remote: Accept remotes with other refs ending in HEAD
What does this MR do?
FindRemoteRepository now reads every line of git ls-remote <remote> HEAD and reports the remote as existing when the line for HEAD itself carries an object ID of a known length. Until now it required the whole output to be that single line.
Why
git ls-remote matches its pattern against the tail of each reference name, so asking for HEAD also lists every reference whose last component is HEAD. The repository from the issue answers like this today:
$ git ls-remote https://github.com/cee-dubb/test-head.git HEAD
001da7c96918d5fcd7fcc8ae2bcfe4fec441b77a HEAD
001da7c96918d5fcd7fcc8ae2bcfe4fec441b77a refs/remotes/origin/HEADbytes.Cut on the first tab leaves everything after it as the reference name, which is not HEAD\n, so the RPC answers exists: false. Rails calls this RPC through Gitlab::GitalyClient::RemoteService.exists? from Import::ValidateRemoteGitEndpointService, which validates the URL of the import-by-URL page, of project creation and POST /projects/:id/import/git when they are given an import_url (and of PUT /projects/:id on EE), and of pull mirror settings behind the validate_pull_mirror_url feature flag, which is off by default. Those repositories are therefore refused as not being valid Git repositories, although they are public and valid. The GitHub importer uses the same call to decide whether to import a wiki.
The RPC has required a single line since it was added in 7cb29b42, and be3e1464 kept that when it added SHA256 support.
I did not use bytes.Contains as the issue suggests: a remote whose HEAD is unborn lists no line for HEAD, and it would then be accepted because of a reference such as refs/remotes/origin/HEAD. The behavior for that case does not change, and a test pins it.
The MR has two commits: the first moves the parsing into remoteHeadExists() without changing it and adds a table test of what it accepts today, and the second is the fix.
Closes gitlab#596393 (closed)
How was this tested?
TestFindRemoteRepositorygains two cases against a real HTTP remote served bygittest.HTTPServer, both withrefs/heads/feature/HEADandrefs/remotes/origin/HEAD: one where they sit next to a bornHEAD(expectsexists: true), and one whereHEADis unborn and they are the only references (expectsexists: false).TestRemoteHeadExistscovers SHA1 and SHA256 object IDs,HEADbefore and after other references ending inHEAD, only such references, an object ID of unknown length and empty output.- With the new tests run against the code of the first commit, they fail as expected:
other references ending in HEADreturnsexists: false, and the two table cases with aHEADline next to other references returnfalse. The unborn case passes on both commits. - With the check changed to the
bytes.Containsthe issue suggests, the unborn case and the table case with only other references ending inHEADfail, because both are then accepted. - Through the RPC itself against the three repositories from the issue: before the fix, cee-dubb/test-head and lttng/lttng-tools answer
exists: falseand lttng/lttng-ust answersexists: true; with the fix, all three answerexists: true. - With the fix,
TEST_PACKAGES=./internal/gitaly/service/remotepasses undermake test-go,make test-with-sha256andmake test-with-reftable(57 tests each), with Go 1.26 and Go 1.27.make formatleaves both files unchanged, andmake lintrestricted to the package reports no issues.
Failures with the new tests against the code of the first commit
=== FAIL: internal/gitaly/service/remote TestRemoteHeadExists/HEAD_after_other_references_ending_in_HEAD
expected: true
actual : false
=== FAIL: internal/gitaly/service/remote TestRemoteHeadExists/HEAD_followed_by_other_references_ending_in_HEAD
expected: true
actual : false
=== FAIL: internal/gitaly/service/remote TestFindRemoteRepository/other_references_ending_in_HEAD
Protobufs not equal
- "exists": bool(true),What the test HTTP remote lists for HEAD
A throwaway test printed git ls-remote <url> HEAD against the two remotes the new RPC cases set up:
born:
549090fbeacc6607bc70648d3ba554c355e670c5 HEAD
549090fbeacc6607bc70648d3ba554c355e670c5 refs/heads/feature/HEAD
549090fbeacc6607bc70648d3ba554c355e670c5 refs/remotes/origin/HEAD
unborn:
549090fbeacc6607bc70648d3ba554c355e670c5 refs/heads/feature/HEAD
549090fbeacc6607bc70648d3ba554c355e670c5 refs/remotes/origin/HEAD