Skip to content

Commit cdb3669

Browse files
committed
Keep user Composer config out of test CLIs
From /code-review high: the Composer suites only dropped an ambient COMPOSER_VENDOR_DIR. The crawler also reads vendor-dir from the user-level config.json, which it finds through COMPOSER_HOME or an absolute XDG_CONFIG_HOME, so a developer whose Composer config sets vendor-dir still failed 2 e2e_composer tests and 1 e2e_composer_version_identity test. hermetic::Extra::Composer now removes every ambient COMPOSER_* var and pins COMPOSER_HOME to a missing directory, which outranks XDG_CONFIG_HOME and holds no config. Both Composer suites use it, and spawn_env_hygiene checks the scrub. Refs #823 Assisted-by: Claude Code:claude-opus-5-5
1 parent dce11cc commit cdb3669

4 files changed

Lines changed: 64 additions & 9 deletions

File tree

‎crates/socket-patch-cli/tests/common/hermetic.rs‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,14 @@ pub enum Extra {
209209
/// Every `POETRY_*` var: Poetry reads any config key from
210210
/// `POETRY_<KEY>` (`POETRY_VIRTUALENVS_PATH`, repository URLs, ...).
211211
Poetry,
212+
/// Every `COMPOSER_*` var, then `COMPOSER_HOME` pinned to a missing
213+
/// directory. The crawler resolves a project's vendor directory from
214+
/// `COMPOSER_VENDOR_DIR`, else the user-level `config.json` in the
215+
/// Composer home, which it finds through `COMPOSER_HOME` or an
216+
/// absolute `XDG_CONFIG_HOME`; any of them moves the crawl off the
217+
/// fixture's `vendor/`. The pin outranks `XDG_CONFIG_HOME` and holds
218+
/// no config. Run it before the suite sets its own `COMPOSER_*` values.
219+
Composer,
212220
}
213221

214222
/// Apply each of `extras` to `cmd` (see [`Extra`]). Run it before
@@ -279,6 +287,14 @@ pub fn scrub_extra(cmd: &mut Command, extras: &[Extra]) {
279287
}
280288
}
281289
}
290+
Extra::Composer => {
291+
for (key, _) in std::env::vars_os() {
292+
if key.to_string_lossy().starts_with("COMPOSER_") {
293+
cmd.env_remove(&key);
294+
}
295+
}
296+
cmd.env("COMPOSER_HOME", "/nonexistent/composer-home");
297+
}
282298
}
283299
}
284300
}

‎crates/socket-patch-cli/tests/e2e_composer.rs‎

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,20 +48,23 @@ async fn start_proxy() -> MockServer {
4848
/// `--proxy-url` pins). The scans are unscoped, so an activated venv is
4949
/// scrubbed and `HOME` points at a stand-in (`jvm_env::isolate_cli`): the
5050
/// developer's venv, `~/.m2` or user site-packages would add packages to
51-
/// the counts these tests assert. An ambient `COMPOSER_VENDOR_DIR` would
52-
/// move the vendor directory the crawler reads off the fixture's.
51+
/// the counts these tests assert. `Extra::Composer` keeps an ambient
52+
/// `COMPOSER_VENDOR_DIR` or user-level Composer config from moving the
53+
/// vendor directory the crawler reads off the fixture's.
5354
async fn run(args: &[&str], cwd: &std::path::Path, proxy_url: &str) -> Output {
5455
let mut args: Vec<String> = args.iter().map(|s| s.to_string()).collect();
5556
args.extend(["--proxy-url".to_string(), proxy_url.to_string()]);
5657
let cwd = cwd.to_path_buf();
5758
tokio::task::spawn_blocking(move || {
5859
let arg_refs: Vec<&str> = args.iter().map(String::as_str).collect();
5960
let mut cmd = hermetic::command(&binary());
60-
hermetic::scrub_extra(&mut cmd, &[hermetic::Extra::Venv]);
61+
hermetic::scrub_extra(
62+
&mut cmd,
63+
&[hermetic::Extra::Venv, hermetic::Extra::Composer],
64+
);
6165
common::jvm_env::isolate_cli(&mut cmd);
6266
cmd.args(&arg_refs)
6367
.current_dir(&cwd)
64-
.env_remove("COMPOSER_VENDOR_DIR")
6568
.output()
6669
.expect("Failed to run socket-patch binary")
6770
})

‎crates/socket-patch-cli/tests/e2e_composer_version_identity.rs‎

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -183,15 +183,18 @@ async fn mount_api(server: &MockServer, prebuilt: bool) {
183183
}
184184

185185
/// The built binary in the hermetic `SOCKET_*` environment, so the
186-
/// assertions reflect only the argv. The scans are unscoped, so an
187-
/// activated venv is scrubbed and `HOME` points at a stand-in
188-
/// (`jvm_env::isolate_cli`), and an ambient `COMPOSER_VENDOR_DIR` can't move
186+
/// assertions reflect only the argv. Its scans and `vex` runs crawl every
187+
/// ecosystem, so an activated venv is scrubbed and `HOME` points at a
188+
/// stand-in (`jvm_env::isolate_cli`), and `Extra::Composer` keeps an
189+
/// ambient `COMPOSER_VENDOR_DIR` or user-level Composer config from moving
189190
/// the vendor directory off the fixture's.
190191
fn cli() -> Command {
191192
let mut cmd = hermetic::binary_command();
192-
hermetic::scrub_extra(&mut cmd, &[hermetic::Extra::Venv]);
193+
hermetic::scrub_extra(
194+
&mut cmd,
195+
&[hermetic::Extra::Venv, hermetic::Extra::Composer],
196+
);
193197
prebuilt_common::jvm_env::isolate_cli(&mut cmd);
194-
cmd.env_remove("COMPOSER_VENDOR_DIR");
195198
cmd
196199
}
197200

‎crates/socket-patch-cli/tests/spawn_env_hygiene.rs‎

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,39 @@ fn bundle_extra_sweeps_every_bundler_override() {
454454
);
455455
}
456456

457+
#[test]
458+
#[serial]
459+
fn composer_extra_sweeps_overrides_and_pins_an_empty_home() {
460+
with_ambient(
461+
&[
462+
("COMPOSER_VENDOR_DIR", "third"),
463+
("COMPOSER_HOME", "/ambient/composer"),
464+
("COMPOSER_CACHE_DIR", "/ambient/composer-cache"),
465+
("XDG_CONFIG_HOME", "/ambient/config"),
466+
],
467+
|| {
468+
let mut cmd = Command::new("socket-patch");
469+
hermetic::scrub_extra(&mut cmd, &[Extra::Composer]);
470+
let env = effective_env(&cmd);
471+
assert_eq!(get(&env, "COMPOSER_VENDOR_DIR"), None);
472+
assert_eq!(get(&env, "COMPOSER_CACHE_DIR"), None);
473+
// The pin outranks XDG_CONFIG_HOME in the Composer home lookup.
474+
assert_eq!(
475+
get(&env, "COMPOSER_HOME"),
476+
Some("/nonexistent/composer-home")
477+
);
478+
assert_eq!(get(&env, "XDG_CONFIG_HOME"), Some("/ambient/config"));
479+
480+
// A suite's own COMPOSER_HOME, set after the scrub, survives.
481+
cmd.env("COMPOSER_HOME", "/fixture/home");
482+
assert_eq!(
483+
get(&effective_env(&cmd), "COMPOSER_HOME"),
484+
Some("/fixture/home")
485+
);
486+
},
487+
);
488+
}
489+
457490
#[test]
458491
#[serial]
459492
fn extra_seeds_are_scrubbed_whatever_the_ambient_value() {

0 commit comments

Comments
 (0)