Skip to content

test: isolate the two raw git spawns that read the developer's gitconfig - #3863

Open
worktrunk-bot wants to merge 2 commits into
mainfrom
nightly/clean-32454340858
Open

test: isolate the two raw git spawns that read the developer's gitconfig#3863
worktrunk-bot wants to merge 2 commits into
mainfrom
nightly/clean-32454340858

Conversation

@worktrunk-bot

@worktrunk-bot worktrunk-bot commented Aug 21, 2026

Copy link
Copy Markdown
Collaborator

Found during the nightly survey. Two raw Command::new spawns in the test tree drive git with an inherited environment, so they read the developer's ~/.gitconfig — breaking the invariant tests/CLAUDE.md states absolutely: "No git the suite runs reads the developer's ~/.gitconfig, whatever the test drives it through and wherever the fixture lives". Both take the same one-line fix, configure_git_cmd on the spawned command.

  • tests/integration_tests/security.rstest_git_rejects_ansi_escape_in_branch_names spawns bash to run git branch. The git inherits the shell's environment, so the isolation goes on the shell, exactly as test_git_rejects_nul_in_commit_messages already does for its sh child in the same file. This one also drops the LC_ALL/LANG=C pin that the test's own stderr assertion depends on.
  • tests/helpers/wt-perf/tests/cli.rssetup_layers_prune_state_onto_a_canonical_base inspects the built fixture with a bare git branch --format=…. wt-perf is in default-members and its in-package CLI tests run under a workspace cargo test, so they're inside the same guarantee. The crate's own git_command() helper documents this rule for the library side but is private to the lib, so the test applies worktrunk::testing::configure_git_cmd directly.
Why the locale matters, and what I verified

The security test's assertion is stderr.contains("not a valid branch name") || stderr.contains("invalid"). Git ships translated messages, so on a contributor's machine with a non-English locale that reads a translated rendering and the test fails with "Expected git to complain about invalid branch name". The German catalog renders that msgid as ist kein gültiger Branchname, which matches neither disjunct — the || stderr.contains("invalid") fallback wouldn't have saved it either.

Verified on this runner:

  • '%s' is not a valid branch name is a live msgid in the shipped German catalog at /usr/share/locale/de/LC_MESSAGES/git.mo (offset 140661), so the string is genuinely subject to translation rather than hardcoded English.
  • git_test_env pins LC_ALL=C and LANG=C (src/testing/mod.rs), and configure_git_cmd applies both that and the HERMETIC_TEST_GIT_ENV config-deny floor.
  • cargo test --test integration security:: — all 10 tests pass with the change. cargo test -p wt-perf --test cli — all 10 pass.

Not verified end-to-end: the runner only has C, C.utf8, POSIX, and en_US.utf8 generated and locale-gen isn't available unprivileged, so I could not actually drive the test under a translated locale and watch it fail. The failing path is inferred from the catalog evidence above, not observed.

The wt-perf site's practical blast radius is small — --format=%(refname:short) pins the output and the assertion uses .any() — so host config would have to do something fairly exotic to break it. It's fixed because the invariant is stated without exceptions, not because a failure was observed.

Swept the rest of the tree for raw Command::new spawns of a shell or of git. Everything else is either isolated already (bare_repository.rs's apply_wt_env calls configure_git_cmd; wt-perf/src/lib.rs routes through git_command()) or drives something other than git (config_show.rs, completion.rs, shell_wrapper.rs, shell_powershell.rs, nushell_default_config_dir.rs, configure_shell.rs). wt-perf/src/main.rs's rev-parse --git-common-dir is binary code run against the developer's real repo, so leaving it uninsulated is correct.

No regression test: the changes are to tests' own setup, and the only guard that would catch a recurrence is a source-scanning lint for raw git/shell spawns, which is brittle enough that I'd rather leave the gap noted here than build it. Happy to add one if you'd prefer.

test_git_rejects_ansi_escape_in_branch_names spawned a bare
Command::new("bash") whose git inherited the developer's ~/.gitconfig and
locale, against the invariant tests/CLAUDE.md states for every git the
suite runs. The missing LC_ALL/LANG=C pin is what the test's own stderr
assertion rests on — git ships translated messages, so the check for
"not a valid branch name" fails on a non-English machine.

Apply repo.configure_git_cmd to the shell, as the sh child in the same
file already does.
@worktrunk-bot worktrunk-bot added the nightly-cleanup Issues found by nightly code quality sweep label Aug 21, 2026

@worktrunk-bot worktrunk-bot left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

The change itself is right: configure_git_cmd on the shell is the only place the isolation can go, since the git bash spawns inherits it, and the locale pin is genuinely load-bearing — the German catalog renders that msgid as ist kein gültiger Branchname, which matches neither disjunct in the assertion, so the fallback || stderr.contains("invalid") wouldn't have saved it either.

One gap the sweep in the description missed, because it was scoped to shell children rather than to git spawns: tests/helpers/wt-perf/tests/cli.rs spawns a bare Command::new("git") directly. In setup_layers_prune_state_onto_a_canonical_base, the fixture inspection .args(["-C", repo.to_str().unwrap(), "branch", "--format=%(refname:short)"]) runs with an inherited environment and no floor, so it reads the developer's ~/.gitconfig. wt-perf is in default-members, and its own Cargo.toml header says a workspace cargo test builds and runs these in-package CLI tests — so this is inside the guarantee tests/CLAUDE.md states, and it's the same one-line fix (worktrunk::testing::configure_git_cmd is already imported by wt-perf/src/lib.rs, and the crate's own private git_command() helper documents the same rule for the library side).

Practical blast radius there is small — --format=%(refname:short) pins the output and the assertion uses .any(), so host config would have to do something fairly exotic to break it — which is why I'd rather ask than fold it in: happy to push it onto this branch (retitling to cover both), or leave this PR atomic and take it separately.

What I verified
  • configure_git_cmd applies scrub_git_path_vars, HERMETIC_TEST_GIT_ENV, and git_test_env (src/testing/mod.rs); the scrub is a strict improvement here since the test relies on cwd discovery from repo.root_path().
  • Nothing in the applied set perturbs this test: no commit is made (identity/date are inert), no network is touched, and $'\x1b' is bash ANSI-C quoting, which is locale-independent under LC_ALL=C.
  • Swept the whole tree for raw Command::new spawns of a shell or of git. Everything else is either isolated already (bare_repository.rs's apply_wt_env calls configure_git_cmd; wt-perf/src/lib.rs routes through git_command()) or drives something other than git (config_show.rs, completion.rs, shell_wrapper.rs, shell_powershell.rs, nushell_default_config_dir.rs, configure_shell.rs). wt-perf/src/main.rs's rev-parse --git-common-dir is binary code run against the developer's real repo, so leaving it uninsulated is correct.
  • test (linux), code-coverage, codecov/patch and codecov/project are green on bc9ff50; test (macos) and test (windows) were still running when I wrote this.

Nit on the description, not the code: the sh child it points at is ~300 lines up, not twelve.

The bare `Command::new("git")` in `setup_layers_prune_state_onto_a_canonical_base`
inherits the developer's environment and reads their `~/.gitconfig`. wt-perf is in
`default-members` and these in-package CLI tests run under a workspace `cargo test`,
so they sit inside the guarantee `tests/CLAUDE.md` states.
@worktrunk-bot worktrunk-bot changed the title test(security): isolate the bash child that drives git branch test: isolate the two raw git spawns that read the developer's gitconfig Aug 21, 2026
@worktrunk-bot

Copy link
Copy Markdown
Collaborator Author

Folded it in as 54f1986, and retitled/rewrote the description to cover both sites.

Took the fold-in over a separate PR because the two hunks aren't independent changes that happen to sit near each other — they're the same invariant (tests/CLAUDE.md: no git the suite runs reads the developer's ~/.gitconfig, whatever the test drives it through) enforced at the two places that still violated it. Splitting would put a one-line test-setup change through a second full review round, and leave the PR that claims to close the gap knowingly closing half of it. Happy to split if you'd rather review them apart.

worktrunk::testing::configure_git_cmd applies directly in the test crate — the review's pointer to wt-perf/src/lib.rs is right that the import exists there, but git_command() itself is private to the lib, so tests/cli.rs can't route through it and calls configure_git_cmd on the Command. cargo test -p wt-perf --test cli passes (10/10), as does cargo clippy -p wt-perf --all-targets.

Also fixed the description's "twelve lines up" — the sh child it points at is ~300 lines up, so the new body just says "in the same file".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

nightly-cleanup Issues found by nightly code quality sweep

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant