Skip to content

Commit 49847ef

Browse files
CI: hermetic spawns in vlt test commons (#823) (#1488)
* Start fix for #823 (slice 10) Assisted-by: Claude Code:claude-opus-5-5 * Spawn vlt test children through hermetic builder The vlt e2e, hosted and vendor test helpers each started socket-patch with a bare Command::new and their own SOCKET_* sweep. Those copies had drifted from tests/common/hermetic.rs: none removed flag-bound vars set in-process after the sweep, none used the hostile seeds that catch a dropped scrub, and the hosted helper left an ambient SOCKET_TELEMETRY_DISABLED=0 in place. All three now build on hermetic::command and keep only their own vlt and proxy scrubs. They leave PENDING_RAW_SPAWNS, so the ratchet keeps them hermetic. Refs #823 Assisted-by: Claude Code:claude-opus-5-5 * Keep test opt-outs after the vlt env scrub The shared vlt scrub also removes SOCKET_* vars, so running it on a socket-patch child built by the hermetic builder would turn telemetry and the update check back on. Add a vlt scrub that leaves SOCKET_* to the builder, as the bun suites already have, and use it for the vlt e2e CLI child instead of re-applying the opt-outs by hand. Refs #823 Assisted-by: Claude Code:claude-opus-5-5 --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 690dc1c commit 49847ef

5 files changed

Lines changed: 55 additions & 53 deletions

File tree

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

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -318,8 +318,9 @@ fn scrub_parent_vars(cmd: &mut Command, parent: Vec<OsString>, ambient: fn(&str)
318318

319319
// ── Ambient-env scrub for the vlt suites ──────────────────────────────
320320

321-
/// True for an ambient variable the real-vlt suites strip from every child
322-
/// (vlt and the CLI under test) before [`isolate`]:
321+
/// True for an ambient variable the real-vlt suites strip from every vlt
322+
/// child before [`isolate`] (a `socket-patch` child built with
323+
/// `hermetic::command` takes [`scrub_ambient_vlt_tool_env`] instead):
323324
///
324325
/// * every `VLT_*` — vlt reads each config option from `VLT_<OPTION>`
325326
/// (`VLT_REGISTRY`, `VLT_REGISTRIES`, `VLT_CACHE`, `VLT_STORE_LINKER`);
@@ -343,6 +344,18 @@ pub fn scrub_ambient_vlt_env(cmd: &mut Command) {
343344
scrub_parent_vars(cmd, parent_var_names(), is_ambient_vlt_var);
344345
}
345346

347+
/// [`is_ambient_vlt_var`] minus `SOCKET_*`.
348+
fn is_ambient_vlt_tool_var(name: &str) -> bool {
349+
!name.starts_with("SOCKET_") && is_ambient_vlt_var(name)
350+
}
351+
352+
/// [`scrub_ambient_vlt_env`] minus `SOCKET_*`, for a `socket-patch` child
353+
/// built with `hermetic::command`: the builder already handled `SOCKET_*`,
354+
/// and removing them again would undo the opt-outs it forces on.
355+
pub fn scrub_ambient_vlt_tool_env(cmd: &mut Command) {
356+
scrub_parent_vars(cmd, parent_var_names(), is_ambient_vlt_tool_var);
357+
}
358+
346359
// ── Self-tests ────────────────────────────────────────────────────────
347360
//
348361
// Integration-test crates do not get `cfg(test)`, so — exactly as in
@@ -454,6 +467,24 @@ mod cache_env_selftests {
454467
}
455468
}
456469

470+
/// The CLI-child variant keeps every `SOCKET_*`, so it never undoes
471+
/// the opt-outs `hermetic::command` forces on, and still strips the
472+
/// vlt, npm and Python config.
473+
#[test]
474+
fn ambient_vlt_tool_scrub_leaves_socket_vars_to_the_hermetic_builder() {
475+
for name in [
476+
"SOCKET_TELEMETRY_DISABLED",
477+
"SOCKET_NO_UPDATE_CHECK",
478+
"SOCKET_NO_CONFIG",
479+
"SOCKET_API_TOKEN",
480+
] {
481+
assert!(!is_ambient_vlt_tool_var(name), "{name} must survive");
482+
}
483+
for name in ["VLT_REGISTRY", "npm_config_registry", "VIRTUAL_ENV"] {
484+
assert!(is_ambient_vlt_tool_var(name), "{name} must be scrubbed");
485+
}
486+
}
487+
457488
#[test]
458489
fn ambient_vlt_scrub_removes_only_matching_parent_vars() {
459490
let parent = parent_var_names();

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

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,6 @@ const PENDING_RAW_SPAWNS: &[&str] = &[
5858
"vex_e2e_common/uv.rs",
5959
"vex_pdm_hatch_common/mod.rs",
6060
"vex_pipenv_pip_common/mod.rs",
61-
"vlt_e2e_common/mod.rs",
62-
"vlt_hosted_common/mod.rs",
63-
"vlt_vendor_common/mod.rs",
6461
];
6562

6663
/// The environment `cmd`'s child would see: the parent environment with

‎crates/socket-patch-cli/tests/vlt_e2e_common/mod.rs‎

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1758,25 +1758,22 @@ pub fn urlencode(s: &str) -> String {
17581758

17591759
// ── socket-patch ──────────────────────────────────────────────────────────
17601760

1761-
/// The socket-patch binary with the ambient `SOCKET_*`, `VLT_*`, npm and
1762-
/// proxy environment scrubbed.
1761+
/// The socket-patch binary with the hermetic `SOCKET_*` environment (see
1762+
/// `common::hermetic::command`) and the ambient `VLT_*`, npm and proxy
1763+
/// environment scrubbed.
17631764
pub fn socket_cmd() -> Command {
1764-
let mut cmd = Command::new(socket_bin());
1765-
cache_env::scrub_ambient_vlt_env(&mut cmd);
1765+
let mut cmd = common::hermetic::command(&socket_bin());
1766+
cache_env::scrub_ambient_vlt_tool_env(&mut cmd);
17661767
for (key, _) in std::env::vars_os() {
17671768
let name = key.to_string_lossy();
17681769
if ["http_proxy", "https_proxy", "all_proxy", "no_proxy"]
17691770
.iter()
17701771
.any(|p| name.eq_ignore_ascii_case(p))
1771-
|| name.starts_with("SOCKET_PATCH_VLT_E2E_")
17721772
{
17731773
cmd.env_remove(&key);
17741774
}
17751775
}
1776-
cmd.env("SOCKET_NO_CONFIG", "1")
1777-
.env("SOCKET_NO_UPDATE_CHECK", "1")
1778-
.env("SOCKET_TELEMETRY_DISABLED", "1")
1779-
.env("VLT_TELEMETRY", "0")
1776+
cmd.env("VLT_TELEMETRY", "0")
17801777
.env("LANG", "C")
17811778
.env("LC_ALL", "C");
17821779
cmd

‎crates/socket-patch-cli/tests/vlt_hosted_common/mod.rs‎

Lines changed: 8 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ pub fn with_flags(line: &str, flags: u8) -> String {
9191
line.replacen("[0,", &format!("[{flags},"), 1)
9292
}
9393

94+
#[path = "../common/hermetic.rs"]
95+
mod hermetic;
9496
#[path = "../common/oracle.rs"]
9597
mod oracle;
9698

@@ -418,32 +420,19 @@ pub fn ledger_path(root: &Path) -> PathBuf {
418420
root.join(".socket/vendor/redirect-state.json")
419421
}
420422

421-
/// The `socket-patch` binary with the ambient `SOCKET_*` and proxy
422-
/// environment scrubbed (telemetry opt-outs kept).
423+
/// The `socket-patch` binary with the hermetic `SOCKET_*` environment (see
424+
/// `hermetic::command`) and the ambient proxy environment scrubbed.
423425
pub fn scrubbed_cli() -> std::process::Command {
424-
let mut cmd = std::process::Command::new(env!("CARGO_BIN_EXE_socket-patch"));
425-
cmd.env("SOCKET_DRY_RUN", "true")
426-
.env("SOCKET_OFFLINE", "true")
427-
.env("SOCKET_NO_VLT_INSTALL_CLEANUP", "true")
428-
.env_remove("SOCKET_DRY_RUN")
429-
.env_remove("SOCKET_OFFLINE")
430-
.env_remove("SOCKET_NO_VLT_INSTALL_CLEANUP");
426+
let mut cmd = hermetic::binary_command();
431427
for (key, _) in std::env::vars_os() {
432428
let name = key.to_string_lossy();
433-
let proxy = name.eq_ignore_ascii_case("http_proxy")
434-
|| name.eq_ignore_ascii_case("https_proxy")
435-
|| name.eq_ignore_ascii_case("all_proxy")
436-
|| name.eq_ignore_ascii_case("no_proxy");
437-
if proxy
438-
|| (name.starts_with("SOCKET_")
439-
&& !name.contains("TELEMETRY")
440-
&& name != "SOCKET_NO_CONFIG")
429+
if ["http_proxy", "https_proxy", "all_proxy", "no_proxy"]
430+
.iter()
431+
.any(|p| name.eq_ignore_ascii_case(p))
441432
{
442433
cmd.env_remove(&key);
443434
}
444435
}
445-
cmd.env("SOCKET_NO_CONFIG", "1")
446-
.env("SOCKET_NO_UPDATE_CHECK", "1");
447436
cmd
448437
}
449438

‎crates/socket-patch-cli/tests/vlt_vendor_common/mod.rs‎

Lines changed: 8 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
1919
#![allow(dead_code)]
2020

21+
#[path = "../common/hermetic.rs"]
22+
mod hermetic;
2123
#[path = "../prebuilt_common/mod.rs"]
2224
mod prebuilt_common;
2325

@@ -347,34 +349,20 @@ pub fn capture_project(root: &Path, case: &Case) {
347349

348350
// ── CLI ──────────────────────────────────────────────────────────────────
349351

350-
/// The `socket-patch` binary with the ambient `SOCKET_*`, `VLT_*` and proxy
351-
/// environment scrubbed (telemetry disabled).
352+
/// The `socket-patch` binary with the hermetic `SOCKET_*` environment (see
353+
/// `hermetic::command`) and the ambient `VLT_*` and proxy environment
354+
/// scrubbed.
352355
pub fn cli() -> Command {
353-
let mut cmd = Command::new(env!("CARGO_BIN_EXE_socket-patch"));
356+
let mut cmd = hermetic::binary_command();
354357
for (key, _) in std::env::vars_os() {
355-
let name = key.to_string_lossy().to_string();
358+
let name = key.to_string_lossy();
356359
let proxy = ["http_proxy", "https_proxy", "all_proxy", "no_proxy"]
357360
.iter()
358361
.any(|p| name.eq_ignore_ascii_case(p));
359-
if proxy
360-
|| name.starts_with("VLT_")
361-
|| (name.starts_with("SOCKET_") && name != "SOCKET_NO_CONFIG")
362-
{
362+
if proxy || name.starts_with("VLT_") {
363363
cmd.env_remove(&key);
364364
}
365365
}
366-
for key in [
367-
"SOCKET_OFFLINE",
368-
"SOCKET_DRY_RUN",
369-
"SOCKET_API_URL",
370-
"SOCKET_PROXY_URL",
371-
"SOCKET_NO_VLT_INSTALL_CLEANUP",
372-
] {
373-
cmd.env_remove(key);
374-
}
375-
cmd.env("SOCKET_TELEMETRY_DISABLED", "1")
376-
.env("SOCKET_NO_CONFIG", "1")
377-
.env("SOCKET_NO_UPDATE_CHECK", "1");
378366
cmd
379367
}
380368

0 commit comments

Comments
 (0)