1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
//! Environment hygiene for spawning git-aware subprocesses.
//!
//! When a process is invoked from inside a Git hook (pre-commit,
//! pre-push, post-checkout, ...) or from a CI runner, Git exports a
//! set of repository-routing environment variables into the hook's
//! environment: `GIT_DIR`, `GIT_INDEX_FILE`, `GIT_COMMON_DIR`,
//! `GIT_WORK_TREE`, `GIT_OBJECT_DIRECTORY`,
//! `GIT_ALTERNATE_OBJECT_DIRECTORIES`. Every subprocess the hook
//! spawns inherits them.
//!
//! Any of these variables redirect every Git call inside the
//! subprocess away from the subprocess's expected repository.
//! Downstream tools layered over Git — for our purposes, `nb`, which
//! is a bash script wrapping Git — then act on the wrong repo:
//! `nb notebooks add` writes a scratch notebook into the parent
//! repo, the subsequent `nb notebooks` listing reads from a
//! different root, and the test fails in ways that depend on the
//! hook environment (CI vs. local vs. the same tests run outside
//! any hook).
//!
//! The fix is mechanical: before invoking any Git-aware subprocess
//! from inside a context that may be hooked or CI-driven, remove
//! every `GIT_*` variable from the child's environment. The child
//! then starts from a clean slate and resolves the repository from
//! its own `cwd` / its own arguments.
//!
//! This module mirrors [`nbspec::git_env`](https://docs.rs/nbspec)
//! (which had the original CI-failure-driven implementation). The
//! tokio `Command` variant here is the form nb-api uses; consumers
//! using `std::process::Command` can swap in `env_remove` directly
//! without depending on this helper. See `nb-api:issues/2` for
//! the related read-path hygiene finding (show line-wrap) and
//! `nb-api:issues/3` for the original git-env finding reported by
//! Nbspec Owner.
use Command as StdCommand;
use Command;
/// Returns the names of every environment variable in the current
/// process whose name starts with `GIT_`. Exposed so other call
/// sites (a future `std::process::Command` variant in `git_env`, or
/// any caller that wants the list without the scrub) share one
/// enumeration policy.
///
/// **Blast vs. selective — deliberate decision.** The `GIT_` prefix
/// blast also removes intent vars (`GIT_CONFIG_GLOBAL`,
/// `GIT_SSH_COMMAND`, `GIT_TERMINAL_PROMPT`, ...). Today no nb-api
/// code path consumes those; the only vars that redirect Git's
/// view of the repository are `GIT_DIR`, `GIT_INDEX_FILE`,
/// `GIT_COMMON_DIR`, `GIT_WORK_TREE`, `GIT_OBJECT_DIRECTORY`, and
/// `GIT_ALTERNATE_OBJECT_DIRECTORIES`. A more selective policy
/// could enumerate exactly those. The blast is chosen for two
/// reasons: (1) any future `GIT_*` redirect that lands in this
/// range gets caught by default rather than requiring a code
/// change; (2) keeping the predicate to a prefix check is the
/// minimum surface to audit. Revisit if a container identity
/// mechanism ever routes through `GIT_CONFIG_GLOBAL` — at that
/// point a selective enumeration belongs here.
/// Removes every environment variable whose name starts with `GIT_`
/// from the given tokio `Command`'s environment. The spawned process
/// inherits every other variable from the parent (PATH, HOME,
/// LANG, ...), just not the ones that redirect Git's view of the
/// repository.
///
/// Pass the command BEFORE chaining `.args(...)` or `.env(...)` so
/// later `.env(name, value)` calls are not also removed.
///
/// # Example
///
/// ```no_run
/// use tokio::process::Command;
/// nb_api::scrub_git_env(&mut Command::new("nb"));
/// ```
/// Synchronous-`Command` variant of [`scrub_git_env`]. nb-api uses
/// `tokio::process::Command` for every `nb` invocation, but
/// `git_rev_parse` (the only direct `git` spawn) uses
/// `std::process::Command`. Both spawn sites must be scrubbed; if a
/// future helper spawns git synchronously, use this overload.
///
/// # Example
///
/// ```no_run
/// use std::process::Command;
/// nb_api::scrub_git_env_std(&mut Command::new("git"));
/// ```