Skip to content

Commit a627ca8

Browse files
authored
Fix git submodule file:// protocol in test fixture (#510)
## Summary - Add `[protocol "file"] allow = always` to gitconfig fixture to fix submodule tests in strict build environments - Add regression test that reproduces the issue ## Root Cause Git submodule operations spawn child processes that don't inherit local repo config. The child `git clone` needs `protocol.file.allow=always` in global config (`$HOME/.gitconfig`), not just local repo config.
2 parents 25dc853 + f2ef0fb commit a627ca8

3 files changed

Lines changed: 92 additions & 0 deletions

File tree

CHANGES

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,14 @@ $ uv add libvcs --prerelease allow
2020
_Notes on the upcoming release will go here._
2121
<!-- END PLACEHOLDER - ADD NEW CHANGELOG ENTRIES BELOW THIS LINE -->
2222

23+
### Tests
24+
25+
- pytest plugin: Add `protocol.file.allow=always` to `gitconfig` fixture (#510)
26+
27+
Fixes #509: "transport 'file' not allowed" errors in strict build
28+
environments (e.g., Arch Linux packaging) where git submodule operations
29+
spawn child processes that don't inherit local repo config.
30+
2331
<!-- Maintainers, insert changes / features for the next release here -->
2432

2533
## libvcs 0.38.2 (2026-01-24)

src/libvcs/pytest_plugin.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,8 @@ def gitconfig(
165165
name = {vcs_name}
166166
[color]
167167
diff = auto
168+
[protocol "file"]
169+
allow = always
168170
""",
169171
),
170172
encoding="utf-8",

tests/test_pytest_plugin.py

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
from __future__ import annotations
44

5+
import os
56
import shutil
7+
import subprocess
68
import textwrap
79
import typing as t
810

@@ -176,3 +178,83 @@ def test_git_bare_repo_sync_and_commit(
176178
# Test
177179
result = pytester.runpytest(str(first_test_filename))
178180
result.assert_outcomes(passed=2)
181+
182+
183+
@pytest.mark.skipif(not shutil.which("git"), reason="git is not available")
184+
def test_gitconfig_submodule_file_protocol(
185+
gitconfig: pathlib.Path,
186+
user_path: pathlib.Path,
187+
tmp_path: pathlib.Path,
188+
monkeypatch: pytest.MonkeyPatch,
189+
) -> None:
190+
"""Test that gitconfig fixture allows file:// protocol for git submodule operations.
191+
192+
Git submodule operations spawn child processes that don't inherit local repo config.
193+
The child `git clone` process needs protocol.file.allow=always in global config.
194+
195+
Without this setting, submodule operations fail with:
196+
fatal: transport 'file' not allowed
197+
198+
This reproduces GitHub issue #509 where tests fail in strict build environments
199+
(like Arch Linux packaging) that don't have protocol.file.allow set globally.
200+
201+
See: https://github.com/vcs-python/libvcs/issues/509
202+
"""
203+
# Isolate git config: use fixture's gitconfig via HOME, block only system config
204+
# Note: We don't block GIT_CONFIG_GLOBAL because git falls back to $HOME/.gitconfig
205+
# when GIT_CONFIG_GLOBAL is unset, which is where our fixture puts the config
206+
monkeypatch.setenv("HOME", str(user_path))
207+
monkeypatch.setenv("GIT_CONFIG_SYSTEM", os.devnull)
208+
monkeypatch.delenv("GIT_CONFIG_GLOBAL", raising=False)
209+
210+
# Create a source repository to use as submodule
211+
submodule_source = tmp_path / "submodule_source"
212+
submodule_source.mkdir()
213+
subprocess.run(
214+
["git", "init"],
215+
cwd=submodule_source,
216+
check=True,
217+
capture_output=True,
218+
)
219+
subprocess.run(
220+
["git", "commit", "--allow-empty", "-m", "initial"],
221+
cwd=submodule_source,
222+
check=True,
223+
capture_output=True,
224+
)
225+
226+
# Create a main repository
227+
main_repo = tmp_path / "main_repo"
228+
main_repo.mkdir()
229+
subprocess.run(
230+
["git", "init"],
231+
cwd=main_repo,
232+
check=True,
233+
capture_output=True,
234+
)
235+
subprocess.run(
236+
["git", "commit", "--allow-empty", "-m", "initial"],
237+
cwd=main_repo,
238+
check=True,
239+
capture_output=True,
240+
)
241+
242+
# Try to add submodule using file:// protocol
243+
# This spawns a child git clone that needs protocol.file.allow=always
244+
result = subprocess.run(
245+
["git", "submodule", "add", str(submodule_source), "vendor/lib"],
246+
cwd=main_repo,
247+
capture_output=True,
248+
text=True,
249+
)
250+
251+
# Assert: submodule add should succeed (no "fatal" errors)
252+
assert "fatal" not in result.stderr.lower(), (
253+
f"git submodule add failed with: {result.stderr}\n"
254+
'This indicates gitconfig fixture is missing [protocol "file"] allow = always'
255+
)
256+
assert result.returncode == 0, f"git submodule add failed: {result.stderr}"
257+
258+
# Verify submodule was actually added
259+
gitmodules = main_repo / ".gitmodules"
260+
assert gitmodules.exists(), "Submodule should create .gitmodules file"

0 commit comments

Comments
 (0)