Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 4 additions & 11 deletions crates/socket-patch-cli/tests/apply/apply_invariants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,9 @@
//! crawler won't match, which trips the "no packages found / offline"
//! branches and exercises the invariants without needing a real fixture.

use crate::common::{binary, git_sha256};
use crate::common::{binary, git_sha256, hermetic_command};

use std::path::{Path, PathBuf};
use std::process::Command;

use sha2::{Digest, Sha256};

Expand Down Expand Up @@ -113,11 +112,9 @@ fn collect_files(root: &Path, dir: &Path, out: &mut Vec<(PathBuf, Vec<u8>)>) {
fn run_apply(cwd: &Path, extra: &[&str]) -> (i32, String) {
let mut args = vec!["apply", "--json"];
args.extend_from_slice(extra);
let out = Command::new(binary())
let out = hermetic_command(&binary())
.args(&args)
.current_dir(cwd)
.env_remove("SOCKET_API_TOKEN")
.env_remove("SOCKET_CLI_API_TOKEN")
.output()
.expect("run socket-patch");
(
Expand Down Expand Up @@ -455,11 +452,9 @@ fn apply_with_no_socket_dir_emits_no_manifest_envelope() {
#[test]
fn apply_with_no_socket_dir_silent_emits_nothing() {
let tmp = tempfile::tempdir().expect("tempdir");
let out = Command::new(binary())
let out = hermetic_command(&binary())
.args(["apply", "--silent"])
.current_dir(tmp.path())
.env_remove("SOCKET_API_TOKEN")
.env_remove("SOCKET_CLI_API_TOKEN")
.output()
.expect("run socket-patch");
assert_eq!(out.status.code(), Some(0));
Expand All @@ -475,11 +470,9 @@ fn apply_with_no_socket_dir_silent_emits_nothing() {
// the message simply never existed — i.e. it would not actually prove
// the silent-mode short-circuit suppresses anything.
let tmp2 = tempfile::tempdir().expect("tempdir");
let loud = Command::new(binary())
let loud = hermetic_command(&binary())
.args(["apply"])
.current_dir(tmp2.path())
.env_remove("SOCKET_API_TOKEN")
.env_remove("SOCKET_CLI_API_TOKEN")
.output()
.expect("run socket-patch");
assert_eq!(loud.status.code(), Some(0));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@
//! modified"). When NO variant matches, the base still fails with
//! "no matching variant found" and the file stays untouched.

use crate::common::{binary, git_sha256};
use crate::common::hermetic::{self, Extra};
use crate::common::{binary, git_sha256, hermetic_command};

use std::path::{Path, PathBuf};
use std::process::Command;

const SINGLETON_PURL: &str = "pkg:gem/rack@3.1.0";
const UUID_SINGLETON: &str = "31313131-3131-4131-8131-313131313131";
Expand All @@ -55,23 +55,15 @@ fn with_marker(base: &[u8], marker: &[u8]) -> Vec<u8> {
}

/// Run `socket-patch apply --offline --ecosystems gem <extra>` in `cwd`
/// with the ambient `SOCKET_*` environment scrubbed (prefix scrub, keeping
/// `SOCKET_NO_CONFIG`) so only the argv decides behavior, and telemetry
/// disabled.
/// with the hermetic `SOCKET_*` environment (`hermetic_command`) and the
/// ambient `BUNDLE_*` scrubbed, so only the argv decides behavior.
fn run_apply(cwd: &Path, extra: &[&str]) -> (i32, String, String) {
let mut cmd = Command::new(binary());
let mut cmd = hermetic_command(&binary());
cmd.arg("apply")
.args(["--offline", "--ecosystems", "gem"])
.args(extra)
.current_dir(cwd);
for (key, _) in std::env::vars_os() {
if key.to_string_lossy().starts_with("SOCKET_")
&& key.to_string_lossy() != "SOCKET_NO_CONFIG"
{
cmd.env_remove(&key);
}
}
cmd.env("SOCKET_TELEMETRY_DISABLED", "1");
hermetic::scrub_extra(&mut cmd, &[Extra::Bundle]);
let out = cmd.output().expect("run socket-patch apply");
(
out.status.code().unwrap_or(-1),
Expand Down
26 changes: 9 additions & 17 deletions crates/socket-patch-cli/tests/apply/covgap_commands_apply.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,13 @@ use common::{git_sha256, parse_json_envelope, run_with_env};

// ───────────────────────── shared fixture helpers ─────────────────────────

/// Run `socket-patch apply <args>` in `cwd` with the ambient `SOCKET_*`
/// environment scrubbed (see `common::run_with_env`), telemetry disabled,
/// and `extra_env` landing last (so tests can inject API URLs / TMPDIR).
/// Run `socket-patch apply <args>` in `cwd` with the hermetic `SOCKET_*`
/// environment (see `common::run_with_env`) and `extra_env` landing last
/// (so tests can inject API URLs / TMPDIR).
fn run_apply(cwd: &Path, args: &[&str], extra_env: &[(&str, &str)]) -> (i32, String, String) {
let mut argv: Vec<&str> = vec!["apply"];
argv.extend_from_slice(args);
let mut env: Vec<(&str, &str)> = vec![("SOCKET_TELEMETRY_DISABLED", "1")];
env.extend_from_slice(extra_env);
run_with_env(cwd, &argv, &env)
run_with_env(cwd, &argv, extra_env)
}

/// One camelCase manifest record (the TS-compatible on-disk schema).
Expand Down Expand Up @@ -714,7 +712,6 @@ fn corrupt_manifest_under_pnp_layout_reports_manifest_error_not_refusal() {
#[cfg(unix)]
mod gem_fallback_home_human {
use super::*;
use std::process::Command;

const QUALIFIED_PURL: &str = "pkg:gem/rack@3.1.0?platform=ruby";
const ORIGINAL: &[u8] = b"module Rack\n VERSION = 'VULNERABLE'\nend\n";
Expand Down Expand Up @@ -753,19 +750,14 @@ mod gem_fallback_home_human {
file
}

/// Human-mode apply with SOCKET_*/BUNDLE_* scrubbed, PATH = the
/// fake-gem bin dir only, BUNDLE_PATH = the store root.
/// Human-mode apply with the hermetic SOCKET_* env and BUNDLE_*
/// scrubbed, PATH = the fake-gem bin dir only, BUNDLE_PATH = the store
/// root.
fn run_apply_human(project: &Path, bin_dir: &Path, store_root: &Path) -> (i32, String, String) {
let mut cmd = Command::new(common::binary());
let mut cmd = common::hermetic_command(&common::binary());
cmd.args(["apply", "--offline", "--ecosystems", "gem", "--cwd"])
.arg(project);
for (key, _) in std::env::vars_os() {
let k = key.to_string_lossy();
if (k.starts_with("SOCKET_") && k != "SOCKET_NO_CONFIG") || k.starts_with("BUNDLE_") {
cmd.env_remove(&key);
}
}
cmd.env("SOCKET_TELEMETRY_DISABLED", "1");
common::hermetic::scrub_extra(&mut cmd, &[common::hermetic::Extra::Bundle]);
cmd.env("PATH", bin_dir);
cmd.env("BUNDLE_PATH", store_root);
let out = cmd.output().expect("run socket-patch apply");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@
//! * non-JSON runs print ONE stderr warning, gated on `!--silent`
//! (`--silent` = errors only — a bare crawler eprintln violated that).

use crate::common::{binary, git_sha256};
use crate::common::hermetic::{self, Extra};
use crate::common::{binary, git_sha256, hermetic_command};

use std::path::Path;
use std::process::Command;

const PURL: &str = "pkg:gem/rack@3.1.0";
const CODE: &str = "gem_bundle_config_path_ignored";
Expand Down Expand Up @@ -76,21 +76,15 @@ fn build_project(root: &Path, outside: &Path, with_store: bool) {
}
}

/// Run the binary with SOCKET_*/BUNDLE_* scrubbed and PATH pointed at an
/// empty dir, so no ambient bundler config and no real `gem` binary can
/// perturb discovery.
/// Run the binary with the hermetic SOCKET_* env, BUNDLE_* scrubbed and
/// PATH pointed at an empty dir, so no ambient bundler config and no real
/// `gem` binary can perturb discovery.
fn run(root: &Path, args: &[&str]) -> (i32, String, String) {
let empty_path = root.join("empty-bin");
std::fs::create_dir_all(&empty_path).unwrap();
let mut cmd = Command::new(binary());
let mut cmd = hermetic_command(&binary());
cmd.args(args).arg("--cwd").arg(root);
for (key, _) in std::env::vars_os() {
let k = key.to_string_lossy();
if (k.starts_with("SOCKET_") && k != "SOCKET_NO_CONFIG") || k.starts_with("BUNDLE_") {
cmd.env_remove(&key);
}
}
cmd.env("SOCKET_TELEMETRY_DISABLED", "1");
hermetic::scrub_extra(&mut cmd, &[Extra::Bundle]);
cmd.env("PATH", &empty_path);
let out = cmd.output().expect("run socket-patch");
(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@

#![cfg(unix)]

use crate::common::{binary, git_sha256};
use crate::common::hermetic::{self, Extra};
use crate::common::{binary, git_sha256, hermetic_command};

use std::path::{Path, PathBuf};
use std::process::Command;

const BASE_PURL: &str = "pkg:gem/rack@3.1.0";
const QUALIFIED_PURL: &str = "pkg:gem/rack@3.1.0?platform=ruby";
Expand Down Expand Up @@ -126,20 +126,15 @@ fn build_fixture(with_store: bool, home_bytes: &[u8], purl: &str) -> Fixture {
}
}

/// Run apply with SOCKET_*/BUNDLE_* scrubbed, PATH = the fake-gem bin dir
/// only, and BUNDLE_PATH set to the store root when present.
/// Run apply with the hermetic SOCKET_* env and BUNDLE_* scrubbed, PATH =
/// the fake-gem bin dir only, and BUNDLE_PATH set to the store root when
/// present.
fn run_apply(fx: &Fixture, extra: &[&str]) -> (i32, String, String) {
let mut cmd = Command::new(binary());
let mut cmd = hermetic_command(&binary());
cmd.args(["apply", "--offline", "--ecosystems", "gem", "--cwd"])
.arg(fx.project.path())
.args(extra);
for (key, _) in std::env::vars_os() {
let k = key.to_string_lossy();
if (k.starts_with("SOCKET_") && k != "SOCKET_NO_CONFIG") || k.starts_with("BUNDLE_") {
cmd.env_remove(&key);
}
}
cmd.env("SOCKET_TELEMETRY_DISABLED", "1");
hermetic::scrub_extra(&mut cmd, &[Extra::Bundle]);
cmd.env("PATH", &fx.bin_dir);
if let Some(store_root) = &fx.store_root {
cmd.env("BUNDLE_PATH", store_root);
Expand Down
30 changes: 9 additions & 21 deletions crates/socket-patch-cli/tests/apply/in_process_gem_multicopy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@
//! physical copy is patched (and later restored) AND that the JSON summary
//! counts every copy.

use crate::common::{binary, git_sha256};
use crate::common::hermetic::{self, Extra};
use crate::common::{binary, git_sha256, hermetic_command};

use std::path::{Path, PathBuf};
use std::process::Command;

const PURL: &str = "pkg:gem/rack@3.1.0";

Expand Down Expand Up @@ -94,21 +94,15 @@ fn build_two_store_project(tmp: &Path) -> (PathBuf, PathBuf, PathBuf, String, St
)
}

/// Run the given subcommand with the ambient `SOCKET_*` and `BUNDLE_*`
/// environment scrubbed (a developer's `BUNDLE_PATH` export or
/// `BUNDLE_APP_CONFIG` must not steer discovery), telemetry disabled.
/// Run the given subcommand with the hermetic `SOCKET_*` environment and
/// the ambient `BUNDLE_*` scrubbed (a developer's `BUNDLE_PATH` export or
/// `BUNDLE_APP_CONFIG` must not steer discovery).
fn run_json(root: &Path, args: &[&str]) -> (i32, serde_json::Value) {
let mut cmd = Command::new(binary());
let mut cmd = hermetic_command(&binary());
cmd.args(args)
.args(["--json", "--offline", "--ecosystems", "gem", "--cwd"])
.arg(root);
for (key, _) in std::env::vars_os() {
let k = key.to_string_lossy();
if (k.starts_with("SOCKET_") && k != "SOCKET_NO_CONFIG") || k.starts_with("BUNDLE_") {
cmd.env_remove(&key);
}
}
cmd.env("SOCKET_TELEMETRY_DISABLED", "1");
hermetic::scrub_extra(&mut cmd, &[Extra::Bundle]);
let out = cmd.output().expect("run socket-patch");
let code = out.status.code().unwrap_or(-1);
let stdout = String::from_utf8_lossy(&out.stdout).to_string();
Expand Down Expand Up @@ -269,17 +263,11 @@ fn build_platform_variant_project(tmp: &Path) -> (PathBuf, PathBuf, PathBuf, Vec

/// `run_json` without `--json`, for `vex`, whose stdout is the document.
fn run_raw(root: &Path, args: &[&str]) -> (i32, String, String) {
let mut cmd = Command::new(binary());
let mut cmd = hermetic_command(&binary());
cmd.args(args)
.args(["--offline", "--ecosystems", "gem", "--cwd"])
.arg(root);
for (key, _) in std::env::vars_os() {
let k = key.to_string_lossy();
if (k.starts_with("SOCKET_") && k != "SOCKET_NO_CONFIG") || k.starts_with("BUNDLE_") {
cmd.env_remove(&key);
}
}
cmd.env("SOCKET_TELEMETRY_DISABLED", "1");
hermetic::scrub_extra(&mut cmd, &[Extra::Bundle]);
let out = cmd.output().expect("run socket-patch");
(
out.status.code().unwrap_or(-1),
Expand Down
11 changes: 5 additions & 6 deletions crates/socket-patch-cli/tests/apply/in_process_npm_multicopy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,10 @@
//! assert EVERY physical copy is patched (and later restored) AND that the
//! JSON summary counts every copy.

use crate::common::{binary, git_sha256};
use crate::common::{binary, git_sha256, hermetic_command};

use std::ffi::OsStr;
use std::path::{Path, PathBuf};
use std::process::Command;

/// Write `node_modules/.../<name>/{package.json,index.js}` at the given
/// `pkg_dir` (which already encodes the nesting), returning the index.js path.
Expand Down Expand Up @@ -124,7 +123,7 @@ fn run_apply(root: &Path) -> (i32, serde_json::Value) {

/// `run_apply` plus `extra` arguments (flags or path targets).
fn run_apply_with(root: &Path, extra: &[&OsStr]) -> (i32, serde_json::Value) {
let out = Command::new(binary())
let out = hermetic_command(&binary())
.args([
"apply",
"--json",
Expand Down Expand Up @@ -228,7 +227,7 @@ fn rollback_restores_every_on_disk_copy_of_a_duplicated_package() {
}

// Now roll back and assert EVERY copy is restored to pristine bytes.
let out = Command::new(binary())
let out = hermetic_command(&binary())
.args([
"rollback",
"--json",
Expand Down Expand Up @@ -324,7 +323,7 @@ fn run_rollback(root: &Path) -> (i32, serde_json::Value) {

/// `run_rollback` plus `extra` arguments (flags or path targets).
fn run_rollback_with(root: &Path, extra: &[&OsStr]) -> (i32, serde_json::Value) {
let out = Command::new(binary())
let out = hermetic_command(&binary())
.args([
"rollback",
"--json",
Expand Down Expand Up @@ -662,7 +661,7 @@ fn apply_and_rollback_refuse_a_node_modules_link_to_first_party_source() {
);
};

let out = Command::new(binary())
let out = hermetic_command(&binary())
.args([
"apply",
"--json",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
//! Requires: `python3` with `venv` and `pip` on PATH. Skipped (visibly)
//! when python3 is missing — same contract as `in_process_pypi_apply`.

use crate::common::{binary, git_sha256};
use crate::common::hermetic::{self, Extra};
use crate::common::{binary, git_sha256, hermetic_command};

use std::path::{Path, PathBuf};
use std::process::Command;
Expand All @@ -28,43 +29,21 @@ const PYPI_PACKAGE: &str = "six";
const PYPI_VERSION: &str = "1.16.0";
const UUID: &str = "12121212-1212-4121-8121-121212121212";

/// Spawn the CLI with the ambient environment scrubbed, so the flags each
/// test passes are the only thing deciding behaviour.
/// Spawn the CLI with the hermetic `SOCKET_*` environment
/// (`hermetic_command`), so the flags each test passes are the only thing
/// deciding behaviour: an ambient `SOCKET_DRY_RUN=true` would turn both real
/// applies here into no-op dry runs, and `SOCKET_GLOBAL` /
/// `SOCKET_GLOBAL_PREFIX` would aim the crawl (and the patch writes) at the
/// host's real site-packages.
///
/// The binary binds a wide `SOCKET_*` env surface: an ambient
/// `SOCKET_DRY_RUN=true` turns both real applies here into no-op dry runs
/// (every variant `verified`, exit 0 — both tests red), and
/// `SOCKET_GLOBAL` / `SOCKET_GLOBAL_PREFIX` aim the crawl — and the patch
/// WRITES — at the host's real site-packages. Seed-then-scrub (mirrors
/// `common::run_with_env`): the highest-risk vars are seeded with hostile
/// values so a dropped scrub line turns the tests red immediately;
/// telemetry opt-outs are deliberately kept.
///
/// `VIRTUAL_ENV` must go too: the PyPI crawler early-returns on it, so an
/// activated ambient venv hijacks discovery away from the tmp venv (six is
/// "not installed" — both tests red) or, if that venv holds six@1.16.0,
/// aims the patch at the developer's own environment. A hostile seed is
/// impossible here (only a *real* venv path triggers the early return), so
/// it is plain-removed.
/// `VIRTUAL_ENV` must go too (`Extra::Venv`): the PyPI crawler early-returns
/// on it, so an activated ambient venv hijacks discovery away from the tmp
/// venv (six is "not installed", both tests red) or, if that venv holds
/// six@1.16.0, aims the patch at the developer's own environment.
fn run_apply_scrubbed(args: &[&str]) -> std::process::Output {
let mut cmd = Command::new(binary());
cmd.args(args)
.env("SOCKET_DRY_RUN", "true")
.env("SOCKET_GLOBAL", "true")
.env("SOCKET_GLOBAL_PREFIX", "/nonexistent")
.env("SOCKET_MANIFEST_PATH", "/nonexistent/manifest.json")
.env_remove("SOCKET_DRY_RUN")
.env_remove("SOCKET_GLOBAL")
.env_remove("SOCKET_GLOBAL_PREFIX")
.env_remove("SOCKET_MANIFEST_PATH")
.env_remove("VIRTUAL_ENV");
for (key, _) in std::env::vars_os() {
let name = key.to_string_lossy();
if name.starts_with("SOCKET_") && !name.contains("TELEMETRY") && name != "SOCKET_NO_CONFIG"
{
cmd.env_remove(&key);
}
}
let mut cmd = hermetic_command(&binary());
cmd.args(args);
hermetic::scrub_extra(&mut cmd, &[Extra::Venv]);
cmd.output().expect("run socket-patch apply")
}

Expand Down
Loading
Loading