The test suite spawns git without pinning the global/system config, so a developer's own
~/.gitconfig reaches the fixtures. Measured, not reasoned — with GIT_CONFIG_GLOBAL
naming a file that sets commit.gpgsign = true:
$ GIT_CONFIG_GLOBAL=<hostile> uv run pytest tests/test_install.py \
-k test_shield_keeps_edge_whitespace_in_the_common_dir
gpg: signing failed: No secret key
fatal: failed to write commit object
FAILED tests/test_install.py::test_shield_keeps_edge_whitespace_in_the_common_dir
$ GIT_CONFIG_GLOBAL=<hostile> uv run pytest tests/test_install.py \
-k test_shield_refuses_a_repository_shared_between_os_users
subprocess.CalledProcessError: Command '['git', '-C',
'.../project-template0/sandbox', 'commit', '-q', '-m', 'initial']'
returned non-zero exit status 128
ERROR (raised in the fixture)
The second one is the reason this is worth an issue rather than a patch to one test: it
never touches a raw git subprocess. It fails inside tests/conftest.py's session-scoped
project template, which every sandbox test in the suite copies from — so the exposure is
suite-wide, not local to any test that happens to call subprocess.run(["git", ...]).
Scope
tests/conftest.py sets none of GIT_CONFIG_GLOBAL, GIT_CONFIG_SYSTEM, HOME,
commit.gpgsign or init.templateDir, and its git() helper spawns bare
["git", "-C", str(repo), *args].
- Eight further raw-subprocess sites in
tests/test_install.py, plus
tests/test_stories_e2e.py.
commit.gpgsign is only the cheapest demonstration; init.templateDir (which can install
hooks into every git init), core.autocrlf, core.hooksPath and a global
core.excludesFile all reach the fixtures the same way. A global core.excludesFile is
worth calling out separately, because several shield tests in test_install.py set that
key themselves and would be reading the developer's file in any test that does not.
CI is unaffected — hosted runners have clean configs — so this shows up only as a local
suite that fails for people whose git is configured normally, which is a poor first
experience for a new contributor and easy to misread as a real regression.
Suggested shape (not measured, so treat as a starting point)
One autouse session fixture in tests/conftest.py pointing GIT_CONFIG_GLOBAL and
GIT_CONFIG_SYSTEM at empty files under tmp_path_factory, rather than per-test -c
flags — the failure above happens in a fixture, so per-call flags would not have caught it.
Worth checking against test_shield_seeds_xdg_default_when_unset, which deliberately pins
GIT_CONFIG_NOSYSTEM=1, and against the Windows legs: suppressing the system config there
also suppresses Git-for-Windows' core.autocrlf=true, which has already produced one
Linux-invisible failure on PR #385.
Provenance
Raised by CodeRabbit on PR #385 against
test_shield_keeps_edge_whitespace_in_the_common_dir. The mechanism is real; the scope in
that comment is narrower than the defect. Filed separately rather than patched there
because a one-test fix would leave the suite equally exposed while making it look
isolated, and because #385 is already far past the size cap (4592/260, 1530 non-test).
The condition predates that branch.
The test suite spawns
gitwithout pinning the global/system config, so a developer's own~/.gitconfigreaches the fixtures. Measured, not reasoned — withGIT_CONFIG_GLOBALnaming a file that sets
commit.gpgsign = true:The second one is the reason this is worth an issue rather than a patch to one test: it
never touches a raw git subprocess. It fails inside
tests/conftest.py's session-scopedprojecttemplate, which every sandbox test in the suite copies from — so the exposure issuite-wide, not local to any test that happens to call
subprocess.run(["git", ...]).Scope
tests/conftest.pysets none ofGIT_CONFIG_GLOBAL,GIT_CONFIG_SYSTEM,HOME,commit.gpgsignorinit.templateDir, and itsgit()helper spawns bare["git", "-C", str(repo), *args].tests/test_install.py, plustests/test_stories_e2e.py.commit.gpgsignis only the cheapest demonstration;init.templateDir(which can installhooks into every
git init),core.autocrlf,core.hooksPathand a globalcore.excludesFileall reach the fixtures the same way. A globalcore.excludesFileisworth calling out separately, because several shield tests in
test_install.pyset thatkey themselves and would be reading the developer's file in any test that does not.
CI is unaffected — hosted runners have clean configs — so this shows up only as a local
suite that fails for people whose git is configured normally, which is a poor first
experience for a new contributor and easy to misread as a real regression.
Suggested shape (not measured, so treat as a starting point)
One autouse session fixture in
tests/conftest.pypointingGIT_CONFIG_GLOBALandGIT_CONFIG_SYSTEMat empty files undertmp_path_factory, rather than per-test-cflags — the failure above happens in a fixture, so per-call flags would not have caught it.
Worth checking against
test_shield_seeds_xdg_default_when_unset, which deliberately pinsGIT_CONFIG_NOSYSTEM=1, and against the Windows legs: suppressing the system config therealso suppresses Git-for-Windows'
core.autocrlf=true, which has already produced oneLinux-invisible failure on PR #385.
Provenance
Raised by CodeRabbit on PR #385 against
test_shield_keeps_edge_whitespace_in_the_common_dir. The mechanism is real; the scope inthat comment is narrower than the defect. Filed separately rather than patched there
because a one-test fix would leave the suite equally exposed while making it look
isolated, and because #385 is already far past the size cap (4592/260, 1530 non-test).
The condition predates that branch.