Files
MetaCrate/programs/tests/packet_dump_cli.rs
Chili Palmer f0420f6c8b
Some checks failed
Native Rust workspace compile / compile (push) Has been cancelled
Implement native PacketDump capture (#87)
2026-08-11 08:06:25 +00:00

216 lines
6.5 KiB
Rust

use std::fs;
use std::path::{Path, PathBuf};
use std::process::{Command, Output, Stdio};
use std::sync::atomic::{AtomicU64, Ordering};
const USE_CIRCUIT_CODE: &str = concat!(
"400000000000ffff000344332211",
"000102030405060708090a0b0c0d0e0f",
"101112131415161718191a1b1c1d1e1f"
);
const UNKNOWN_PACKET: &str = "400000000000fe";
const EXIT_USAGE: i32 = 2;
const EXIT_INPUT: i32 = 3;
const EXIT_OUTPUT: i32 = 5;
static TEMP_ID: AtomicU64 = AtomicU64::new(0);
struct TestDir(PathBuf);
impl TestDir {
fn new(test_name: &str) -> Self {
let id = TEMP_ID.fetch_add(1, Ordering::Relaxed);
let path = std::env::temp_dir().join(format!(
"metacrate-packet-dump-{test_name}-{}-{id}",
std::process::id()
));
fs::create_dir(&path).expect("create isolated test directory");
Self(path)
}
fn path(&self, name: &str) -> PathBuf {
self.0.join(name)
}
}
impl Drop for TestDir {
fn drop(&mut self) {
let _ = fs::remove_dir_all(&self.0);
}
}
fn run(args: &[&str]) -> Output {
Command::new(env!("CARGO_BIN_EXE_packet-dump"))
.args(args)
.stdin(Stdio::null())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.output()
.expect("run packet-dump")
}
fn text(bytes: &[u8]) -> &str {
std::str::from_utf8(bytes).expect("command output is UTF-8")
}
fn path_text(path: &Path) -> &str {
path.to_str().expect("test path is UTF-8")
}
fn assert_exit(output: &Output, expected: i32) {
assert_eq!(
output.status.code(),
Some(expected),
"stdout:\n{}\nstderr:\n{}",
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)
);
}
fn script(directory: &TestDir) -> PathBuf {
let path = directory.path("packets.tsv");
fs::write(
&path,
format!(
"# direction, simulator, and wire bytes\n\
incoming\tAlpha Region\t{USE_CIRCUIT_CODE}\n\
outgoing\tBeta Region\t{USE_CIRCUIT_CODE}\n\
incoming\tAlpha Region\t{UNKNOWN_PACKET}\n"
),
)
.expect("write fake packet script");
path
}
#[test]
fn help_preserves_upstream_arguments_and_documents_safe_capture_controls() {
let output = run(&["--help"]);
assert!(output.status.success());
let help = text(&output.stdout);
for marker in [
"[FIRSTNAME]",
"[LASTNAME]",
"[PASSWORD]",
"[SECONDS]",
"--fake-script",
"--direction",
"--packet-type",
"--raw",
"--output",
"--max-output-bytes",
"--max-packets",
"incoming<TAB>simulator<TAB>hex-bytes",
] {
assert!(help.contains(marker), "help omitted {marker}:\n{help}");
}
let output = run(&[]);
assert_exit(&output, EXIT_USAGE);
assert!(text(&output.stderr).contains("Usage: packet-dump"));
}
#[test]
fn fake_capture_decodes_directions_types_headers_raw_bytes_and_malformed_data() {
let directory = TestDir::new("capture");
let script = script(&directory);
let output = run(&["--fake-script", path_text(&script), "--raw"]);
assert!(output.status.success(), "{}", text(&output.stderr));
assert!(output.stderr.is_empty());
let output = text(&output.stdout);
assert!(output.contains(
"IN type=UseCircuitCode simulator=Alpha Region bytes=46 sequence=0 frequency=Low id=3 reliable=true resent=false zerocoded=false appended_acks=false"
));
assert!(output.contains(&format!("raw={USE_CIRCUIT_CODE}")));
assert!(output.contains("OUT type=UseCircuitCode simulator=Beta Region bytes=46"));
assert!(output.contains("IN malformed-or-unknown simulator=Alpha Region bytes=7"));
assert!(output.contains("Capture complete; packets=3 dropped=0 active_tasks=0 open_sockets=0"));
let output = run(&[
"--fake-script",
path_text(&script),
"--direction",
"incoming",
"--packet-type",
"UseCircuitCode",
]);
assert!(output.status.success());
let output = text(&output.stdout);
assert!(output.contains("IN type=UseCircuitCode"));
assert!(!output.contains("OUT type="));
assert!(!output.contains("malformed-or-unknown"));
assert!(output.contains("Capture complete; packets=1"));
}
#[test]
fn output_file_packet_and_byte_limits_are_enforced_without_unbounded_writes() {
let directory = TestDir::new("limits");
let script = script(&directory);
let capture = directory.path("capture.log");
let output = run(&[
"--fake-script",
path_text(&script),
"--max-packets",
"1",
"--output",
path_text(&capture),
]);
assert!(output.status.success(), "{}", text(&output.stderr));
assert!(output.stdout.is_empty());
let saved = fs::read_to_string(capture).expect("read capture output");
assert!(saved.contains("Packet limit reached"));
assert!(saved.contains("Capture complete; packets=1"));
let limited = directory.path("limited.log");
let output = run(&[
"--fake-script",
path_text(&script),
"--max-output-bytes",
"10",
"--output",
path_text(&limited),
]);
assert_exit(&output, EXIT_OUTPUT);
assert!(text(&output.stderr).contains("output byte limit"));
assert_eq!(
fs::metadata(limited).expect("limited file metadata").len(),
0
);
let output = run(&["--fake-script", path_text(&script), "--max-packets", "0"]);
assert_exit(&output, EXIT_USAGE);
}
#[test]
fn invalid_scripts_filters_and_credentials_fail_without_leaking_secrets() {
let directory = TestDir::new("invalid");
let invalid = directory.path("invalid.tsv");
fs::write(&invalid, "incoming\tRegion\tzz\n").expect("write invalid script");
let output = run(&["--fake-script", path_text(&invalid)]);
assert_exit(&output, EXIT_INPUT);
assert!(output.stdout.is_empty());
assert!(text(&output.stderr).contains("non-hex digit"));
let valid = script(&directory);
let output = run(&[
"--fake-script",
path_text(&valid),
"--packet-type",
"NotAPacket",
]);
assert_exit(&output, EXIT_USAGE);
assert!(text(&output.stderr).contains("unknown packet type"));
let password = "do-not-print-this-password";
let output = run(&[
"First",
"Last",
password,
"10",
"--fake-script",
path_text(&valid),
]);
assert_exit(&output, EXIT_USAGE);
assert!(!text(&output.stdout).contains(password));
assert!(!text(&output.stderr).contains(password));
}