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
33 changes: 10 additions & 23 deletions crates/socket-patch-cli/tests/cli/shared_helper_copies.rs
Original file line number Diff line number Diff line change
@@ -1,24 +1,14 @@
//! One `binary()` and one `git_sha256` for every CLI test target (#824).
//!
//! `common/mod.rs` owns both helpers, and its own tests pin `git_sha256`
//! to the canonical Git-blob hash and to production's
//! `compute_git_sha256_from_bytes` (the two shapes the per-file copies
//! took). This ratchet keeps new private copies out: a file may define its
//! own only while it is listed below.
//! `common/oracle.rs` owns both helpers and `common/mod.rs` re-exports
//! them; `common`'s own tests pin `git_sha256` to the canonical Git-blob
//! hash and to production's `compute_git_sha256_from_bytes` (the two
//! shapes the per-file copies took). Shared modules whose includers don't
//! all declare `mod common` pull `common/oracle.rs` in on its own and
//! re-export it. This check keeps new private copies out.

use std::path::Path;

/// Files that still define a private `binary()` or `git_sha256`. Each is
/// a shared module whose includers don't all declare `mod common`.
/// Migrate a file onto `common` and delete its entry; a stale entry is
/// not an error, so a PR that migrates one never turns another red.
const PENDING_PRIVATE_HELPERS: &[&str] = &[
"vex_e2e_common/mod.rs",
"vlt_e2e_common/mod.rs",
"vlt_hosted_common/mod.rs",
"vlt_vendor_common/mod.rs",
];

/// Every `.rs` file under `tests/`, as (`/`-joined relative path, text).
fn test_sources() -> Vec<(String, String)> {
fn walk(dir: &Path, root: &Path, out: &mut Vec<(String, String)>) {
Expand Down Expand Up @@ -66,19 +56,16 @@ fn defines_private_helper(text: &str) -> bool {
fn no_new_private_binary_or_git_sha256() {
let unexpected: Vec<String> = test_sources()
.into_iter()
.filter(|(rel, text)| {
!rel.starts_with("common/")
&& !PENDING_PRIVATE_HELPERS.contains(&rel.as_str())
&& defines_private_helper(text)
})
.filter(|(rel, text)| !rel.starts_with("common/") && defines_private_helper(text))
.map(|(rel, _)| rel)
.collect();
assert!(
unexpected.is_empty(),
"these test files define their own binary() or git_sha256: {unexpected:?}. \
Use `common::binary` / `common::git_sha256` instead (declare \
`#[path = \"common/mod.rs\"] mod common;`, or `use crate::common::..` in a \
directory test binary). Do not add them to PENDING_PRIVATE_HELPERS."
`#[path = \"common/mod.rs\"] mod common;`, `use crate::common::..` in a \
directory test binary, or re-export them from `common/oracle.rs` in a \
shared module)."
);
}

Expand Down
40 changes: 13 additions & 27 deletions crates/socket-patch-cli/tests/common/mod.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
//! Helpers shared across the e2e-safety test suites.
//!
//! The original e2e files (`e2e_npm.rs`, `e2e_pypi.rs`, `e2e_gem.rs`)
//! each carry their own copy of the same `binary` / `run` /
//! `assert_run_ok` / `git_sha256` helpers. Rather than refactor those
//! files in this PR, this module is an additive landing place for the
//! same surface plus the new helpers the safety suites need
//! (synthetic manifest writers, pnpm runners, cargo runners). Existing
//! suites can migrate in a follow-up.
//! Helpers shared across the CLI test suites: the binary under test and
//! the Git-blob hash oracle (`oracle`), `run` / `assert_run_ok`, and the
//! synthetic manifest writers and package-manager runners the e2e suites
//! need. Test files use these instead of private copies;
//! `cli/shared_helper_copies.rs` enforces that for `binary` and
//! `git_sha256` (#824).
//!
//! Each test file pulls this in with `#[path = "common/mod.rs"] mod common;`.
//!
Expand Down Expand Up @@ -44,14 +41,14 @@ pub mod envelope;

pub use envelope::{envelope_error_code, envelope_error_message, json_string, parse_json_envelope};

// ── Binary discovery + invocation ─────────────────────────────────────
/// The binary under test and the Git-blob hash oracle. Shared modules
/// whose includers don't all declare `mod common` pull it in on its own
/// with `#[path = "../common/oracle.rs"] mod oracle;`.
pub mod oracle;

/// Absolute path to the built `socket-patch` binary that cargo
/// provides via the `CARGO_BIN_EXE_*` env var. Available because
/// these tests live in the same crate that produces the binary.
pub fn binary() -> PathBuf {
env!("CARGO_BIN_EXE_socket-patch").into()
}
pub use oracle::{binary, git_sha256};

// ── Binary discovery + invocation ─────────────────────────────────────

/// Quick check whether `cmd` is on PATH. Used to soft-skip
/// toolchain-dependent tests when the toolchain isn't installed
Expand Down Expand Up @@ -126,17 +123,6 @@ pub fn assert_run_ok(cwd: &Path, args: &[&str], context: &str) -> (String, Strin

// ── Hashing ───────────────────────────────────────────────────────────

/// Compute Git-flavored SHA-256: `SHA256("blob <len>\0" ++ content)`.
/// This is the hash socket-patch records in manifests under
/// `before_hash` / `after_hash`.
pub fn git_sha256(content: &[u8]) -> String {
let header = format!("blob {}\0", content.len());
let mut hasher = Sha256::new();
hasher.update(header.as_bytes());
hasher.update(content);
hex::encode(hasher.finalize())
}

/// Git-SHA-256 of the file at `path`. Panics if the file can't be
/// read — tests use this on paths they know exist.
pub fn git_sha256_file(path: &Path) -> String {
Expand Down
33 changes: 33 additions & 0 deletions crates/socket-patch-cli/tests/common/oracle.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//! The binary under test and the Git-blob hash oracle (#824).
//!
//! `common/mod.rs` re-exports both. Shared modules whose includers don't
//! all declare `mod common` pull this file in on its own with
//! `#[path = "../common/oracle.rs"] mod oracle;`, so every test target
//! uses the one `binary()` and the one `git_sha256` that
//! `common::oracle_selftests` pins.

#![allow(dead_code)]

use std::path::PathBuf;

use sha2::{Digest, Sha256};

/// Absolute path to the built `socket-patch` binary that cargo
/// provides via the `CARGO_BIN_EXE_*` env var. Available because
/// these tests live in the same crate that produces the binary.
pub fn binary() -> PathBuf {
env!("CARGO_BIN_EXE_socket-patch").into()
}

/// Compute Git-flavored SHA-256: `SHA256("blob <len>\0" ++ content)`.
/// This is the hash socket-patch records in manifests under
/// `before_hash` / `after_hash`. It is computed here, independently of
/// production's hasher, so a round trip through both can't agree on a
/// broken implementation.
pub fn git_sha256(content: &[u8]) -> String {
let header = format!("blob {}\0", content.len());
let mut hasher = Sha256::new();
hasher.update(header.as_bytes());
hasher.update(content);
hex::encode(hasher.finalize())
}
18 changes: 8 additions & 10 deletions crates/socket-patch-cli/tests/vex_e2e_common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,16 +99,14 @@ pub fn installed_pnpm_pre_10_5(proj: &Path) -> bool {
}
}

/// Absolute path of the `socket-patch` binary under test.
pub fn binary() -> PathBuf {
env!("CARGO_BIN_EXE_socket-patch").into()
}

/// Git-style sha256 of `bytes` — the `afterHash` a patch view carries for a
/// patched file (what installed-tree verification recomputes).
pub fn git_sha256(bytes: &[u8]) -> String {
socket_patch_core::hash::git_sha256::compute_git_sha256_from_bytes(bytes)
}
/// The binary under test and the Git-blob hash (the `afterHash` a patch
/// view carries for a patched file), shared with `common` (#824).
#[path = "../common/oracle.rs"]
mod oracle;

// Not every includer uses these.
#[allow(unused_imports)]
pub use oracle::{binary, git_sha256};

// ── Project shaping ───────────────────────────────────────────────────

Expand Down
9 changes: 3 additions & 6 deletions crates/socket-patch-cli/tests/vlt_e2e_common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1280,12 +1280,9 @@ pub fn sha256_hex(bytes: &[u8]) -> String {
hex::encode(Sha256::digest(bytes))
}

pub fn git_sha256(bytes: &[u8]) -> String {
let mut h = Sha256::new();
h.update(format!("blob {}\0", bytes.len()).as_bytes());
h.update(bytes);
hex::encode(h.finalize())
}
// Not every includer uses it.
#[allow(unused_imports)]
pub use common::git_sha256;

/// A dir vlt (rc.14) renames an old tree to and deletes in the background.
pub fn is_vlt_delete_staging(name: &std::ffi::OsStr) -> bool {
Expand Down
15 changes: 8 additions & 7 deletions crates/socket-patch-cli/tests/vlt_hosted_common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use std::path::{Path, PathBuf};

use base64::Engine as _;
use serde_json::{json, Value};
use sha2::{Digest, Sha256, Sha512};
use sha2::{Digest, Sha512};
use wiremock::matchers::{method, path, path_regex};
use wiremock::{Mock, MockServer, ResponseTemplate};

Expand Down Expand Up @@ -91,12 +91,13 @@ pub fn with_flags(line: &str, flags: u8) -> String {
line.replacen("[0,", &format!("[{flags},"), 1)
}

pub fn git_sha256(bytes: &[u8]) -> String {
let mut hasher = Sha256::new();
hasher.update(format!("blob {}\0", bytes.len()).as_bytes());
hasher.update(bytes);
hex::encode(hasher.finalize())
}
#[path = "../common/oracle.rs"]
mod oracle;

/// The Git-blob hash oracle shared with `common` (#824).
// Not every includer uses it.
#[allow(unused_imports)]
pub use oracle::git_sha256;

pub fn sha512_sri(bytes: &[u8]) -> String {
format!(
Expand Down
14 changes: 7 additions & 7 deletions crates/socket-patch-cli/tests/vlt_vendor_common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ use std::path::{Path, PathBuf};
use std::process::Command;

use serde_json::{json, Value};
use sha2::{Digest, Sha256};

pub const UUID: &str = "9f6b2c4e-1d3a-4f6b-8c2d-7e5a9b1c3d5f";
pub const UUID2: &str = "0a1b2c3d-4e5f-4a7b-8c9d-0e1f2a3b4c5d";
Expand All @@ -43,12 +42,13 @@ pub const VLT_LOCK: &str = "vlt-lock.json";
/// The real-vlt versions whose captures are committed.
pub const CAPTURED: &[&str] = &["1.2.0", "1.0.10", "1.0.4", "1.0.0-rc.32", "1.0.0-rc.14"];

pub fn git_sha256(bytes: &[u8]) -> String {
let mut hasher = Sha256::new();
hasher.update(format!("blob {}\0", bytes.len()).as_bytes());
hasher.update(bytes);
hex::encode(hasher.finalize())
}
#[path = "../common/oracle.rs"]
mod oracle;

/// The Git-blob hash oracle shared with `common` (#824).
// Not every includer uses it.
#[allow(unused_imports)]
pub use oracle::git_sha256;

pub fn fixtures() -> PathBuf {
Path::new(env!("CARGO_MANIFEST_DIR")).join("../socket-patch-core/tests/fixtures/vendor/npm/vlt")
Expand Down
Loading