Skip to content

Give fixture git identity per command; no test writes git config identity - #2813

Merged
trissim merged 2 commits into
mainfrom
fix/fixture-git-identity
Oct 23, 2026
Merged

trissim merged 2 commits into
mainfrom
fix/fixture-git-identity

Conversation

@trissim

@trissim trissim commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Test fixtures wrote git identity with git config, which writes whatever repository git resolves. When GIT_DIR leaked in (git bisect run from a linked worktree, or a hook), that was the shared agent-comms .git/config. On 10-23 this put "Citation fixture" plus commit.gpgsign=false there, and "Ratchet test" too, which 106 real commits then carried. The conftest GIT_* scrub guards the environment, not the writer. This fixes the writer: no test writes identity or signing config any more.

The owner: tests/fixture_git.py declares the fixture identity once (user.name, user.email, commit.gpgsign). It derives two forms from that:

  • IDENTITY: the -c arguments for one git command.
  • ENVIRONMENT: the same settings through git's GIT_CONFIG_COUNT channel, for the git that code under test starts.

Sites fixed

  • tests/guards/test_debt_ratchet.py: two config user.* writes deleted. The runner passes IDENTITY on every command, and the per-commit -c commit.gpgsign=false folded into it.
  • tests/source_revision_fixture.py: config user.name, user.email and commit.gpgsign deleted. SourceRepository overrides Repo._run, the one git subprocess, to carry IDENTITY, which covers commit-tree and the tests that commit through source.git. git_input passes IDENTITY too.
  • tests/test_carry.py: two config user.* writes deleted; the runner passes IDENTITY.
  • tests/test_checkpoint_command.py: two config user.* writes deleted. The checkpoint command commits through its own git (cli_commands.py:1889), so an autouse fixture sets ENVIRONMENT with monkeypatch.
  • Hand-copied -c user.name=... identities folded into IDENTITY on the runner in test_proof_build, test_checkout_submodules, test_order_progress, test_installed_merge and test_phase_evidence.

Proof

  • Leak: a scratch bare repository was set as GIT_DIR and the fixtures were run directly, bypassing the conftest scrub.
    • origin/main's fixtures left user.name=Ratchet test, user.email=ratchet@example.invalid and commit.gpgsign=false in it.
    • This branch's fixtures left no user.* or gpgsign key.
  • Tests: run with -p no:xdist and HOME set to an empty directory, so no global identity can stand in.
    • 131 tests across the touched files and every user of source_revision_fixture passed.
    • test_install_announcements::test_failed_rehearsal_does_not_publish_to_the_source_bus failed only because the empty HOME had no .local. It passes with the real HOME.
  • debt_ratchet: 163 of 167 pass. Four test_clean_changed_lines_cannot_be_offset_with_a_deletion cases (FrozenFieldWrite and BannedVocabulary, under src/agent_comms and src/toad) fail with assert 0 == 1, and fail identically with origin/main's copy of the file. That red is already on main, and no open PR touches the ratchet.

Left alone: these sites already pass identity per command, so they cannot leak. They are not folded here because open PRs touch the same files: test_bus (#2795), test_install_rehearsal (#2556), test_storage_rules (#2801), test_storage_violations (#2469), test_unowned_checkout_work (#2801, #2469) and test_change_report (#2792).

🤖 Generated with Claude Code

trissim and others added 2 commits October 23, 2026 11:20
…tity

A fixture that runs `git config user.name ...` writes whatever repository
git resolves. When GIT_DIR leaks in (git bisect run from a linked worktree,
a hook), that is the caller's repository: on 10-23 source_revision_fixture
stamped "Citation fixture" and commit.gpgsign=false into the shared
agent-comms .git/config, and test_debt_ratchet stamped "Ratchet test",
which 106 real commits then carried. The conftest GIT_* scrub guards the
environment, not the writer.

tests/fixture_git.py declares the fixture identity once (user.name,
user.email, commit.gpgsign) and derives two forms: IDENTITY, the -c
arguments for one git command, and ENVIRONMENT, the same settings through
git's GIT_CONFIG_COUNT channel for a git the code under test starts.

- test_debt_ratchet, test_carry: config writes deleted; the Repository
  runner passes IDENTITY on every command.
- source_revision_fixture: config writes deleted; SourceRepository
  overrides Repo._run, the one git subprocess, to carry IDENTITY, and
  git_input passes it too.
- test_checkpoint_command: config writes deleted; the checkpoint command
  commits through its own git, so an autouse fixture sets ENVIRONMENT
  with monkeypatch.
- test_proof_build, test_checkout_submodules, test_order_progress,
  test_installed_merge, test_phase_evidence: their hand-copied -c
  identities fold into IDENTITY on the runner.

Proof: with GIT_DIR pointed at a scratch bare repository, origin/main's
fixtures wrote user.name, user.email and commit.gpgsign into it; these
write none. The touched tests pass with HOME set to an empty directory,
so no global identity stands in.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings October 23, 2026 15:21

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.

An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing.

@trissim
trissim merged commit 4abb08a into main Oct 23, 2026
7 of 8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants