Development record
check-attribution-cases.sh scratch repos are not hermetic so an inherited GIT_DIR makes the corpus report green while rewriting the ambient repository history
check-attribution-cases.sh scratch repos are not hermetic so an inherited GIT_DIR makes the corpus report green while rewriting the ambient repository history
Evidence
scripts/check-attribution-cases.sh:495 — bare git init -q "$repo"; every later call is git -C "$repo" ... with no env scrub. An absolute inherited GIT_DIR overrides -C. Reproduced in a sandbox victim repo: GIT_DIR=/victim/.git bash scripts/check-attribution-cases.sh → 74 passed, 0 failed, exit 0 while the victim's refs/heads/main was moved to a bogus empty commit and 13 scratch commits + 12 reset --hard entries were written into its object store. A live instance of the shell shim iss-28 (severity major) explicitly deferred ("Go-only per maintainer Option A; cross-language scaffolding deferred").
Adversarial verdict: CONFIRMED, understated (minor→moderate)
Not merely "confusing diagnosis" (the gpgsign scenario is loud): there is a real green-while-corrupting path via inherited GIT_DIR, absolute form as exported in hook / rebase -x / bisect contexts. Not exposed in CI (clean runner) but exposed to local make check-attribution (not a preflight prereq; pre-push unsets GIT_DIR but never calls it). Fix: hoist the existing convention — unset GIT_DIR GIT_WORK_TREE GIT_INDEX_FILE GIT_OBJECT_DIRECTORY GIT_ALTERNATE_OBJECT_DIRECTORIES GIT_CONFIG GIT_CONFIG_COUNT GIT_CONFIG_PARAMETERS; export GIT_CONFIG_GLOBAL=/dev/null GIT_CONFIG_NOSYSTEM=1 at the top, and check the commit status in commit_as. iss-28 currently reads closed; this is its live shell instance.
Frontmatter
| id | iss-313 |
|---|---|
| type | issue |
| lifecycle | resolved |
| severity | minor |
.abcd/work/issues/resolved/iss-313-check-attribution-cases-sh-scratch-repos.md
open on GitHub ↗ · commit history ↗
mentions4
- dcn-26082000000000032026-08-20 — Bug-hunt round 1 (hunt A), landed late: the round ran 2026-08-19 on a branch that
- dcn-26082600000000012026-08-26 — bughunt round 7 (state #368): hardened the new issue-resolution
- iss-28scaffold a hermetic git environment for tests that shell out to git: any test invoking git as a subprocess can read the developer's real ~/.gitconfig (identity, aliases, includeIf, hooks path) — non-determinism and identity leakage into fixtures — or, via one un-scoped call (missing -C/cwd) or corrupted repo state, mutate the ambient repo's config, refs, or history. Per-call temp-repo scoping is defence-in-breadth only; the robust fix also isolates the git environment. Ship a shared hermetic-git helper in the generated test scaffolding, per target language (Go gitIsolatedEnv(), pytest fixture, shell shim), that pins HOME and XDG_CONFIG_HOME to a per-test temp dir, sets GIT_CONFIG_GLOBAL/GIT_CONFIG_SYSTEM to /dev/null (or GIT_CONFIG_NOSYSTEM=1), supplies identity via GIT_AUTHOR_*/GIT_COMMITTER_* env rather than git config, sets GIT_TERMINAL_PROMPT=0 and core.hooksPath=/dev/null, and is always combined with scoping to the temp repo — documented in the scaffolded repo's testing conventions/AGENTS.md so it is the path of least resistance. Optional enforcement: a lint/pre-commit check flagging git subprocesses in test code that bypass the helper, turning convention into guarantee. Exactly the cross-repo hygiene the scaffolder exists to standardise; removes a whole class of flaky-test and repo-pollution bugs.
- iss-2608261041020040check-issue-resolution-cases.sh runs its scratch-repo git commands under the inherited environment, so an ambient GIT_DIR or global core.hooksPath corrupts the caller's repo or breaks the gate. The harness builds ~60 'git -C $d' fixtures but omits the hermetic-env scrub its sibling check-attribution-cases.sh carries (iss-28, iss-313, resolved four days before this script was authored): an inherited absolute GIT_DIR overrides -C and redirects the fixture commits and config onto the ambient repository while every case still prints ok (green-while-corrupting, reachable on a direct make preflight under a git alias / rebase -x / bisect run); and an inherited GIT_CONFIG_GLOBAL / core.hooksPath — which this repo's .githooks/pre-push documents the maintainer uses — fires the developer's global pre-commit hook inside the scratch repos and turns make lint-issues red with no gate diagnostic. Fix: hoist the same unset GIT_DIR family + export GIT_CONFIG_GLOBAL=/dev/null scrub before the first git call.