Skip to content

Commit b486f06

Browse files
Add generic token auth support for non-GitHub Git repositories
Co-authored-by: nicoragne <nicoragne@hotmail.fr>
1 parent d36198d commit b486f06

File tree

2 files changed

+47
-5
lines changed

2 files changed

+47
-5
lines changed

src/gitingest/utils/git_utils.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,9 +128,19 @@ async def check_repo_exists(url: str, token: str | None = None) -> bool:
128128
"""
129129
cmd = ["git", "ls-remote"]
130130

131-
# Add authentication header if token is provided for GitHub repositories
132-
if token and is_github_host(url):
133-
cmd.extend(["-c", create_git_auth_header(token, url=url)])
131+
# Add authentication header if token is provided
132+
if token:
133+
if is_github_host(url):
134+
# Use GitHub-specific authentication
135+
cmd.extend(["-c", create_git_auth_header(token, url=url)])
136+
else:
137+
# For non-GitHub repositories, use generic HTTP basic auth
138+
# This works for GitLab, Bitbucket, and other Git hosting services
139+
parsed_url = urlparse(url)
140+
if parsed_url.hostname:
141+
basic_auth = base64.b64encode(f"oauth2:{token}".encode()).decode()
142+
auth_header = f"http.https://{parsed_url.hostname}/.extraheader=Authorization: Basic {basic_auth}"
143+
cmd.extend(["-c", auth_header])
134144

135145
cmd.extend(["--exit-code", url, "HEAD"])
136146

tests/test_clone.py

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -210,12 +210,12 @@ async def test_check_repo_exists_with_exception(mocker: MockerFixture) -> None:
210210

211211

212212
@pytest.mark.asyncio
213-
async def test_check_repo_exists_with_token(mocker: MockerFixture) -> None:
213+
async def test_check_repo_exists_with_github_token(mocker: MockerFixture) -> None:
214214
"""Test ``check_repo_exists`` with GitHub token authentication.
215215
216216
Given a GitHub URL and a token:
217217
When ``check_repo_exists`` is called,
218-
Then it should include the authentication header in the git ls-remote command.
218+
Then it should include the GitHub-specific authentication header in the git ls-remote command.
219219
"""
220220
mock_exec = mocker.patch("asyncio.create_subprocess_exec", new_callable=AsyncMock)
221221
mock_process = AsyncMock()
@@ -241,6 +241,38 @@ async def test_check_repo_exists_with_token(mocker: MockerFixture) -> None:
241241
)
242242

243243

244+
@pytest.mark.asyncio
245+
async def test_check_repo_exists_with_non_github_token(mocker: MockerFixture) -> None:
246+
"""Test ``check_repo_exists`` with non-GitHub token authentication.
247+
248+
Given a non-GitHub URL and a token:
249+
When ``check_repo_exists`` is called,
250+
Then it should include the generic HTTP basic auth header in the git ls-remote command.
251+
"""
252+
mock_exec = mocker.patch("asyncio.create_subprocess_exec", new_callable=AsyncMock)
253+
mock_process = AsyncMock()
254+
mock_process.communicate.return_value = (b"", b"")
255+
mock_process.returncode = 0
256+
mock_exec.return_value = mock_process
257+
258+
mock_base64 = mocker.patch("base64.b64encode")
259+
mock_base64.return_value.decode.return_value = "encoded_token"
260+
261+
gitlab_url = "https://gitlab.com/owner/repo"
262+
result = await check_repo_exists(gitlab_url, token="test_token")
263+
264+
assert result is True
265+
# Verify that base64 encoding was called for the token
266+
mock_base64.assert_called_once_with(b"oauth2:test_token")
267+
# Verify that git ls-remote was called with the authentication config
268+
mock_exec.assert_called_once_with(
269+
"git", "ls-remote", "-c", "http.https://gitlab.com/.extraheader=Authorization: Basic encoded_token",
270+
"--exit-code", gitlab_url, "HEAD",
271+
stdout=asyncio.subprocess.PIPE,
272+
stderr=asyncio.subprocess.PIPE,
273+
)
274+
275+
244276
@pytest.mark.asyncio
245277
async def test_clone_with_timeout(run_command_mock: AsyncMock) -> None:
246278
"""Test cloning a repository when a timeout occurs.

0 commit comments

Comments
 (0)