fangorn/ex_git_objectstore
public
Test suite corrupts the developer's checkout via git upward-discovery (no isolation) #74
Links
No links yet.
Summary
The test suite can silently corrupt the developer’s working checkout. Under the full concurrent run (mix test, max_cases: 20), integration/protocol tests that run git in scratch/temp directories can escape via git’s upward repository discovery and mutate this project’s real .git.
Observed damage on a real checkout (after mix test ran via the git_hooks pre-push):
remote.origin.urlrewritten to a dead ephemeral test server (http://127.0.0.1:PORT/repo)origin/mainforce-updated to scratch commits (“c1”/“c2”)core.bareset totrue(breaks all subsequentgit status/operations)- stray commits (“first”/“track”/“second”/…) left on the checked-out branch
lfs.urlpointed at a dead localhost endpoint
Root cause (deterministically reproduced)
A git command run in a directory that is not itself a repo walks up the filesystem until it finds a .git. When a test’s scratch dir setup races/fails under load, the next mutating git command (config, remote set-url, fetch, commit) finds the project’s .git and mutates it. Minimal repro from a scratch dir inside the project:
$ ( cd tmp/x/not-a-repo && git config core.bare true )
fatal: this operation must be run in a work tree # <- but it set core.bare on the PROJECT repo
The server-side test repos are in-memory and clients clone into temp dirs, so the corruption is purely this upward-escape; it is flaky because it only triggers when a setup step loses a race under load.
Fix
Set GIT_CEILING_DIRECTORIES to the project root in test/test_helper.exs, so git’s upward discovery stops before the project root and any stray command fails loudly in its own directory instead of corrupting the checkout. Verified: with the guard, the same repro fails not in a git directory (exit 128) and the real .git is untouched.
Adds a regression test (test/ex_git_objectstore/test_isolation_test.exs) asserting the guard is set and that git cannot discover the project repo from a scratch dir.
Out of scope (follow-up)
The guard contains the damage but does not fix the underlying flakiness: several protocol/HTTP/daemon integration tests fail under heavy concurrent load (port/timeout races). That load-sensitivity should be tracked and fixed separately.
Acceptance criteria
GIT_CEILING_DIRECTORIESguard in place; regression test passes.- Running the suite (even with failing tests) cannot alter the project repo’s config, refs, or worktree.