tests: scrub inherited git env pointers at package import - #87
Conversation
Defense-in-depth follow-up to #86: any runner of the tests/ suite is now safe from hook-inherited GIT_DIR poisoning, not just the sanitized pre-push wrapper. Regression tests pin in-process absence and a freshly-poisoned child-import scrub. scripts/ root verified unexposed (327/327 under poisoned GIT_DIR, zero config writes) and left as-is. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: dd453149d3
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| "GIT_COMMON_DIR", | ||
| ): |
There was a problem hiding this comment.
Scrub
GIT_CONFIG before running temp-repo commands
When the suite inherits GIT_CONFIG=/path/to/config, this allowlist leaves it active, so temp-repository calls such as PublicExportSafetyTests._init() running git config user.email/user.name silently modify that external file rather than the temporary repo. This reproduces the configuration-corruption class the change is intended to prevent; Git 2.43 also includes GIT_CONFIG in git rev-parse --local-env-vars, and the official documentation says it takes configuration from the named file instead of .git/config (Git documentation). Add GIT_CONFIG to the scrubbed variables while continuing to preserve the intentionally retained global/system settings.
Useful? React with 👍 / 👎.
Summary
Defense-in-depth follow-up to #86, operator-directed:
tests/__init__.pynow scrubs inherited per-repo git environment pointers (GIT_DIR,GIT_WORK_TREE,GIT_INDEX_FILE,GIT_PREFIX,GIT_OBJECT_DIRECTORY,GIT_ALTERNATE_OBJECT_DIRECTORIES,GIT_COMMON_DIR) at package import — so every runner of the suite is safe from the incident class (hook-inherited absoluteGIT_DIRmaking temp-dir git calls mutate the real.git/config), not just the sanitized pre-push wrapper.Scoping decisions (each verified or reasoned in the diff comment):
GIT_CONFIG_GLOBAL/GIT_CONFIG_SYSTEMdeliberately untouched — temp-repo commits rely on machine identity.scripts/root deliberately untouched — namespace package (no__init__to ride) AND empirically unexposed: 327/327 pass under a poisoned absoluteGIT_DIRwith zero config writes.Regression tests (2, in
tests/test_git_env_hardening.py): in-process absence of all seven pointers, and a freshly-poisoned child interpreter whoseimport testsmust scrub them all.Verification: the incident reproduction (poisoned absolute
GIT_DIR→ 23 errors) now runs 658/658 green with zero config mutation; clean runs unaffected (660/660 with the new tests; 327/327 scripts). Test infrastructure only — no version bump; changelog fragment included.Cross-check (verbatim)
Codex (
gpt-5.6-sol, effortlow, directcodex execunder operator broker-bypass authorization):Concerns (all integrated): document that poisoned-env tests must set variables post-import — added to the comment; regression test asserting variable absence — added (both in-process and child-import forms); global-config exclusion and
scripts/exclusion judged justified as scoped.author: claude
author_model: claude-fable-5 (effort: default)
standing_directives: operator-directed follow-up (2026-08-03 "Proceed with the test-setUp git-env hardening"); directive #9 defense-in-depth for ledger plugin.tests.inherit.git.hook.env.mutate.real.repo; #7 model+effort stated; #8 no fan-out
tier: 2
cross_check: PROCEED (codex gpt-5.6-sol, effort low, direct codex exec under operator broker-bypass authorization 2026-08-03; raw verdict quoted in PR body; both actionable concerns integrated)
post_condition: 660/660 + 327/327 tests OK; incident reproduction now green (was 23 errors) with zero config mutation; changelog dry-run OK; push traversed the #86 gate
mcp_coverage_gap: none — test infrastructure; gemini_mcp_path: retired / not applicable
contributor_rights: OWNER-AUTHORED
operator_reserved: no
plugin_affected: NONE — test infrastructure, no distributed plugin content
readme_refresh_status: README unaffected (no release, no version bump)
🤖 Generated with Claude Code