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
31 changes: 18 additions & 13 deletions crates/socket-patch-cli/tests/e2e_gem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

#[path = "common/mod.rs"]
mod common;
use common::{binary, git_sha256};
use common::{binary, git_sha256, hermetic};

use std::path::{Path, PathBuf};
use std::process::{Command, Output};
Expand Down Expand Up @@ -60,20 +60,20 @@ fn git_sha256_file(path: &Path) -> String {
git_sha256(&content)
}

/// Run the binary with the hermetic `SOCKET_*` environment (no token, so the
/// scans take the public-proxy path `--proxy-url` pins). The gem crawler
/// reads `BUNDLE_PATH`, `BUNDLE_APP_CONFIG`, the user's `~/.bundle/config`
/// and the `gem env` homes (`GEM_HOME`, `GEM_PATH`, `~/.gem`), and the scans
/// are unscoped, so every `BUNDLE_*` var, both gem-home vars and an
/// activated venv are scrubbed and `HOME` points at a stand-in
/// (`jvm_env::isolate_cli`): any of them would add the developer's gems or
/// packages to the exact purl sets these tests assert.
fn run(cwd: &Path, args: &[&str]) -> (i32, String, String) {
let mut cmd = Command::new(binary());
let mut cmd = hermetic::command(&binary());
hermetic::scrub_extra(&mut cmd, &[hermetic::Extra::Bundle, hermetic::Extra::Venv]);
cmd.env_remove("GEM_HOME").env_remove("GEM_PATH");
common::jvm_env::isolate_cli(&mut cmd);
cmd.args(args).current_dir(cwd);
// Hermeticity, mirroring the production e2e suites: scrub every ambient
// `SOCKET_*` (token, api/proxy URL, org, legacy aliases — not just the
// two token vars) and block the socket-cli config.json, so a developer's
// login or configured apiBaseUrl cannot silently repoint or re-tier
// these runs.
for (k, _) in std::env::vars_os() {
if k.to_string_lossy().starts_with("SOCKET_") {
cmd.env_remove(&k);
}
}
cmd.env("SOCKET_NO_CONFIG", "true");
let out: Output = cmd.output().expect("failed to execute socket-patch binary");

let code = out.status.code().unwrap_or(-1);
Expand All @@ -94,6 +94,11 @@ fn assert_run_ok(cwd: &Path, args: &[&str], context: &str) -> (String, String) {
fn bundle_run(cwd: &Path, args: &[&str]) {
let mut cmd = Command::new("bundle");
cmd.args(args).current_dir(cwd);
// Scrub first: the sweeps would otherwise remove the BUNDLE_PATH below,
// and an ambient `BUNDLE_*` (frozen, deployment, without, ...) would
// change what this install does.
hermetic::scrub_socket_vars(&mut cmd);
hermetic::scrub_extra(&mut cmd, &[hermetic::Extra::Bundle]);
// Bundler 4 removed `bundle install --path`; BUNDLE_PATH is honored by
// bundler 2 through 4 and keeps the vendor/bundle/ruby/*/gems layout
// `find_gem_dir` expects. It also upholds cache_env's hermeticity
Expand Down
3 changes: 0 additions & 3 deletions crates/socket-patch-cli/tests/spawn_env_hygiene.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ use serial_test::serial;
/// scrubs by hand.
const PENDING_RAW_SPAWNS: &[&str] = &[
"apply/apply_network.rs",
"e2e_gem.rs",
"e2e_hosted_production.rs",
"e2e_maven.rs",
"e2e_npm.rs",
Expand All @@ -42,8 +41,6 @@ const PENDING_RAW_SPAWNS: &[&str] = &[
"e2e_vex_vendor.rs",
"rollback/rollback_multicopy_blob_gate.rs",
"vendor/in_process_vendor_bun.rs",
"vendor/vendor_gem_lockfile_only_e2e.rs",
"vendor/vendor_rerun_no_network_e2e.rs",
];

/// The environment `cmd`'s child would see: the parent environment with
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
//! Service vendoring of portable gems without a local install or registry fetch.

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

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

use wiremock::matchers::{method, path as wm_path};
use wiremock::{Mock, MockServer, ResponseTemplate};
Expand Down Expand Up @@ -126,11 +125,17 @@ async fn mount_gem_download(mock: &MockServer, gem: Vec<u8>) {
}

/// `vendor --json --vendor-source <source>` through the built binary, with
/// every ambient `SOCKET_*` var scrubbed and the API pointed at a
/// the hermetic `SOCKET_*` environment, every ambient `BUNDLE_*` var and
/// both gem-home vars scrubbed and `HOME` on a stand-in (an ambient
/// `BUNDLE_PATH`, app config, `~/.bundle/config` or gem home moves the gem
/// store the crawler reads) and the API pointed at a
/// guaranteed-dead endpoint (patch staging is satisfied from
/// `.socket/blobs`, so nothing should reach it).
fn run_vendor(root: &Path, source: &str, api_url: &str) -> (i32, serde_json::Value, String) {
let mut cmd = Command::new(binary());
let mut cmd = hermetic::command(&binary());
hermetic::scrub_extra(&mut cmd, &[hermetic::Extra::Bundle]);
cmd.env_remove("GEM_HOME").env_remove("GEM_PATH");
crate::common::jvm_env::isolate_cli(&mut cmd);
cmd.args([
"vendor",
"--json",
Expand All @@ -146,12 +151,6 @@ fn run_vendor(root: &Path, source: &str, api_url: &str) -> (i32, serde_json::Val
"test-org",
])
.current_dir(root);
for (key, _) in std::env::vars() {
if key.starts_with("SOCKET_") && key != "SOCKET_NO_CONFIG" {
cmd.env_remove(key);
}
}
cmd.env("SOCKET_TELEMETRY_DISABLED", "1");
let fixture = crate::prebuilt_common::Server::project(root);
fixture.command(&mut cmd);
let out = cmd.output().expect("run socket-patch vendor");
Expand Down
41 changes: 13 additions & 28 deletions crates/socket-patch-cli/tests/vendor/vendor_rerun_no_network_e2e.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,9 @@
//! Hermetic: every registry base and the patch API point at a
//! guaranteed-dead local endpoint, and patch staging reads `.socket/blobs`.

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

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

use sha2::{Digest, Sha256};

Expand Down Expand Up @@ -67,16 +66,20 @@ fn write_manifest(root: &Path, purl: &str, uuid: &str, file: &str, before: &[u8]
std::fs::write(socket.join("blobs").join(git_sha256(after)), after).unwrap();
}

/// `vendor --json --vendor-source build` through the built binary with
/// every ambient `SOCKET_*` var scrubbed, the API and every registry base
/// pointed at `dead`, and `env` on top.
/// `vendor --json --vendor-source service` through the built binary with
/// the hermetic `SOCKET_*` environment, an activated venv, the gem homes
/// and every ambient `BUNDLE_*` var scrubbed and `HOME` on a stand-in (they
/// move the Python and gem stores the crawlers read), the API and every
/// registry base pointed at `dead`, and `env` on top.
fn run_vendor(
root: &Path,
dead: &str,
extra: &[&str],
env: &[(&str, &str)],
) -> (i32, serde_json::Value, String) {
let mut cmd = Command::new(binary());
let mut cmd = hermetic::command(&binary());
hermetic::scrub_extra(&mut cmd, &[hermetic::Extra::Bundle, hermetic::Extra::Venv]);
crate::common::jvm_env::isolate_cli(&mut cmd);
cmd.args([
"vendor",
"--json",
Expand All @@ -93,16 +96,10 @@ fn run_vendor(
])
.args(extra)
.current_dir(root);
for (key, _) in std::env::vars() {
if key.starts_with("SOCKET_") && key != "SOCKET_NO_CONFIG" {
cmd.env_remove(key);
}
}
for var in ["VIRTUAL_ENV", "CONDA_PREFIX", "BUNDLE_PATH", "GEM_HOME"] {
for var in ["CONDA_PREFIX", "GEM_HOME", "GEM_PATH"] {
cmd.env_remove(var);
}
cmd.env("SOCKET_TELEMETRY_DISABLED", "1")
.env("SOCKET_CRATES_REGISTRY", dead)
cmd.env("SOCKET_CRATES_REGISTRY", dead)
.env("SOCKET_GOPROXY", dead)
.env("SOCKET_PYPI_JSON_API", dead)
.env("SOCKET_NPM_REGISTRY", dead)
Expand Down Expand Up @@ -850,7 +847,7 @@ async fn cargo_service_vendor_never_downloads_the_pristine_crate() {
let empty_home = tmp.path().join("cargo-home");
std::fs::create_dir_all(&empty_home).unwrap();

let mut cmd = Command::new(binary());
let mut cmd = hermetic::command(&binary());
cmd.args([
"vendor",
"--json",
Expand All @@ -864,13 +861,7 @@ async fn cargo_service_vendor_never_downloads_the_pristine_crate() {
"acme",
])
.current_dir(&root);
for (key, _) in std::env::vars() {
if key.starts_with("SOCKET_") && key != "SOCKET_NO_CONFIG" {
cmd.env_remove(key);
}
}
let out = cmd
.env("SOCKET_TELEMETRY_DISABLED", "1")
.env("SOCKET_CRATES_REGISTRY", registry.uri())
.env("CARGO_HOME", &empty_home)
.output()
Expand Down Expand Up @@ -975,7 +966,7 @@ async fn cargo_service_never_vendors_a_git_or_custom_registry_crate() {
let empty_home = tmp.path().join("cargo-home");
std::fs::create_dir_all(&empty_home).unwrap();

let mut cmd = Command::new(binary());
let mut cmd = hermetic::command(&binary());
cmd.args([
"vendor",
"--json",
Expand All @@ -989,13 +980,7 @@ async fn cargo_service_never_vendors_a_git_or_custom_registry_crate() {
"acme",
])
.current_dir(&root);
for (key, _) in std::env::vars() {
if key.starts_with("SOCKET_") && key != "SOCKET_NO_CONFIG" {
cmd.env_remove(key);
}
}
let out = cmd
.env("SOCKET_TELEMETRY_DISABLED", "1")
.env("SOCKET_CRATES_REGISTRY", registry.uri())
.env("CARGO_HOME", &empty_home)
.output()
Expand Down
Loading