Finding
The repo's fixture-isolation idiom for test scripts is git -C "$fixture" ...
(scripts/check-stale-base-overlap.test.sh:22, scripts/sync-standards-contract.test.sh:69,
and now the two portability suites via #2839). It is a good readability and
copy-paste guard. It is not an isolation guarantee.
git config's default --local scope, and git init's target, both follow the
GIT_DIR environment variable in preference to the working directory and in
preference to -C. GIT_DIR is exactly what git exports into every hook it
invokes. So any test suite run from inside a git hook — or from any process that
inherited GIT_DIR — writes its fixture identity into the caller's repository,
whichever isolation idiom the suite uses.
Reproduction
Both forms poison the caller's .git/config under an exported GIT_DIR:
# form 1: cd-scoped subshell (the pre-#2839 shape)
GIT_DIR=<real repo>/.git
BEFORE: (no local user.* keys)
subshell rc=0 gitdir-it-used=<real repo>/.git
AFTER: user.email=test@example.com
user.name=test
# form 2: the established `git -C "$fx"` idiom
== git -C "$fx" init/config under exported GIT_DIR ==
fixture has .git? NO
caller config user.*: user.email=test@example.com user.name=test
Only clearing the inherited state isolates the fixture:
== git -C with GIT_DIR/GIT_WORK_TREE unset in the subshell ==
fixture2 has .git? yes
caller config user.*: (clean)
Why this matters here
A poisoned user.email silently re-authors commits to test@example.com. Such a
commit fails this repo's required_signatures rule with no_user and cannot be
force-pushed over — the branch has to be abandoned and the tree rebuilt (this is
what happened to #2827 -> #2830).
Worktrees share the main clone's .git/config, so one leak poisons every
worktree of the repo at once.
Not done, deliberately
#2839 does not add unset GIT_DIR GIT_WORK_TREE hardening. It is a new shape
across roughly 30 test files, and nothing in this repo currently runs the suites
with GIT_DIR set (no core.hooksPath, no installed git hooks in the clone, and
CI invokes them as plain workflow steps). Filing the mechanism so the decision is
made deliberately rather than rediscovered after the next incident.
Options
- Do nothing; accept that fixture isolation depends on
GIT_DIR being unset.
- Add a shared test-harness preamble that clears
GIT_DIR/GIT_WORK_TREE once,
rather than per-call (lib/ already hosts shared test helpers).
- Add a portability/hygiene gate asserting fixture-building test scripts clear
the inherited git environment.
Related
No linked issue.
Finding
The repo's fixture-isolation idiom for test scripts is
git -C "$fixture" ...(
scripts/check-stale-base-overlap.test.sh:22,scripts/sync-standards-contract.test.sh:69,and now the two portability suites via #2839). It is a good readability and
copy-paste guard. It is not an isolation guarantee.
git config's default--localscope, andgit init's target, both follow theGIT_DIRenvironment variable in preference to the working directory and inpreference to
-C.GIT_DIRis exactly what git exports into every hook itinvokes. So any test suite run from inside a git hook — or from any process that
inherited
GIT_DIR— writes its fixture identity into the caller's repository,whichever isolation idiom the suite uses.
Reproduction
Both forms poison the caller's
.git/configunder an exportedGIT_DIR:Only clearing the inherited state isolates the fixture:
Why this matters here
A poisoned
user.emailsilently re-authors commits totest@example.com. Such acommit fails this repo's
required_signaturesrule withno_userand cannot beforce-pushed over — the branch has to be abandoned and the tree rebuilt (this is
what happened to #2827 -> #2830).
Worktrees share the main clone's
.git/config, so one leak poisons everyworktree of the repo at once.
Not done, deliberately
#2839 does not add
unset GIT_DIR GIT_WORK_TREEhardening. It is a new shapeacross roughly 30 test files, and nothing in this repo currently runs the suites
with
GIT_DIRset (nocore.hooksPath, no installed git hooks in the clone, andCI invokes them as plain workflow steps). Filing the mechanism so the decision is
made deliberately rather than rediscovered after the next incident.
Options
GIT_DIRbeing unset.GIT_DIR/GIT_WORK_TREEonce,rather than per-call (
lib/already hosts shared test helpers).the inherited git environment.
Related
No linked issue.
git -Cidiom in the two portability suites and carries thefull before/after evidence.