Repository navigation
fix(git): clear git's repository-local env for cbm's own git children (#2003) - #2341
Merged
Merged
Conversation
…#2003) Git exports repository-local variables (GIT_DIR, GIT_WORK_TREE, GIT_INDEX_FILE, GIT_COMMON_DIR, ...) into hooks, and some editors export them into their terminals. They take precedence over `git -C <dir>`, and every git child cbm spawned inherited them. A cbm started from such an environment therefore resolved every project against the CALLER's repository: git_context reported a plain directory as is_git=true with the caller's worktree root, branch and HEAD, the history pass attributed the caller's commits to it, and the watcher / detect_changes / artifact git calls read (and `config merge.ours.driver` could write) the wrong repository. Fix: one production helper, src/foundation/git_env.{c,h}, holds the 15-variable list `git rev-parse --local-env-vars` prints and builds the child environment with exactly those removed -- a POSIX envp array or a Windows CREATE_UNICODE_ENVIRONMENT block (case-insensitive names). It is applied per spawn; cbm's own environment is never modified (no unsetenv in the parent, which would race other threads): - cbm_popen_git(cmd): read-mode popen for git command lines. POSIX spawns /bin/sh -c via posix_spawn with the scrubbed envp (stdin /dev/null, pipe ends close-on-exec, reaped by cbm_pclose); Windows passes the block to the existing handle-isolated CreateProcessW spawn. Fails closed. - cbm_proc_opts_t.strip_git_repo_env: cbm_subprocess_spawn passes the scrubbed envp to posix_spawnp / the fork+exec child, or the block to CreateProcessW. Fails closed. - Every git spawn uses them: git_context, pass_githistory, artifact (4 sites), the watcher's git runner, and detect_changes' git commands. search_code's grep scan keeps the inherited environment. Tests (RED before, green after, RED on revert of the helper and of the call sites): - git_context::git_context_ignores_inherited_repo_env -- GIT_DIR and the hook set pointing at a decoy repo: a plain dir is is_git=false, a fixture repo reports its own HEAD and branch, the decoy is untouched. - git_context::githistory_ignores_inherited_repo_env -- the history pass on a plain dir sees 0 commits (was the decoy's 4). - subprocess::subprocess_strip_git_repo_env_is_per_child and popen_git_strips_repo_env_and_reports_exit_status -- all 15 variables are gone in the child, unrelated variables pass through, the parent environment is unchanged, and cbm_pclose keeps pclose() status semantics. Proof (macOS arm64, GIT_DIR/GIT_WORK_TREE/GIT_INDEX_FILE/GIT_PREFIX exported at a decoy clone, `cli index_status verbose=true`): a plain dir went from is_git=true, worktree_root=<decoy>, branch=<decoy's> (v0.11.0) to is_git=false; a fixture repo went from the decoy's root/branch/HEAD to its own root and branch. Refs #2003 Signed-off-by: Martin Vogel <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Git exports repository-local variables (GIT_DIR, GIT_WORK_TREE,
GIT_INDEX_FILE, GIT_COMMON_DIR, ...) into hooks, and some editors export
them into their terminals. They take precedence over
git -C <dir>, andevery git child cbm spawned inherited them. A cbm started from such an
environment therefore resolved every project against the CALLER's
repository: git_context reported a plain directory as is_git=true with
the caller's worktree root, branch and HEAD, the history pass attributed
the caller's commits to it, and the watcher / detect_changes /
artifact git calls read (and
config merge.ours.drivercould write) thewrong repository.
Fix: one production helper, src/foundation/git_env.{c,h}, holds the
15-variable list
git rev-parse --local-env-varsprints and builds thechild environment with exactly those removed -- a POSIX envp array or a
Windows CREATE_UNICODE_ENVIRONMENT block (case-insensitive names). It is
applied per spawn; cbm's own environment is never modified (no unsetenv
in the parent, which would race other threads):
/bin/sh -c via posix_spawn with the scrubbed envp (stdin /dev/null,
pipe ends close-on-exec, reaped by cbm_pclose); Windows passes the block
to the existing handle-isolated CreateProcessW spawn. Fails closed.
scrubbed envp to posix_spawnp / the fork+exec child, or the block to
CreateProcessW. Fails closed.
(4 sites), the watcher's git runner, and detect_changes' git commands.
search_code's grep scan keeps the inherited environment.
Tests (RED before, green after, RED on revert of the helper and of the
call sites):
hook set pointing at a decoy repo: a plain dir is is_git=false, a
fixture repo reports its own HEAD and branch, the decoy is untouched.
on a plain dir sees 0 commits (was the decoy's 4).
popen_git_strips_repo_env_and_reports_exit_status -- all 15 variables
are gone in the child, unrelated variables pass through, the parent
environment is unchanged, and cbm_pclose keeps pclose() status
semantics.
Proof (macOS arm64, GIT_DIR/GIT_WORK_TREE/GIT_INDEX_FILE/GIT_PREFIX
exported at a decoy clone,
cli index_status verbose=true): a plain dirwent from is_git=true, worktree_root=, branch=<decoy's> (v0.11.0)
to is_git=false; a fixture repo went from the decoy's root/branch/HEAD
to its own root and branch.
Refs #2003
Production half of #2003 (the test-suite half is the
fix/issue-2003PR). Windows branches are reviewed but only exercised on the Windows CI leg.