From 7ff781dc45ae334686e1779c1ef0f85fe02309b3 Mon Sep 17 00:00:00 2001 From: Zious Date: Fri, 3 Apr 2026 08:02:05 -0500 Subject: [PATCH 1/4] chore: add CI, README, LICENSE, and rustfmt config - GitHub Actions CI: test, clippy, format checks on PRs - MIT LICENSE file - README with install, usage, architecture docs - rustfmt.toml for consistent formatting - Auto-format all existing code to match --- .github/workflows/ci.yml | 42 ++++++++++++ LICENSE | 21 ++++++ README.md | 131 ++++++++++++++++++++++++++++++++++++++ rustfmt.toml | 4 ++ src/analyzer/dns.rs | 10 ++- src/decoder.rs | 23 +++---- src/main.rs | 27 ++++---- src/reader.rs | 3 +- tests/analyzer_tests.rs | 2 +- tests/cli_tests.rs | 10 ++- tests/decoder_tests.rs | 40 +++++------- tests/integration_test.rs | 23 ++----- tests/reader_tests.rs | 42 ++++++------ tests/reporter_tests.rs | 2 +- 14 files changed, 283 insertions(+), 97 deletions(-) create mode 100644 .github/workflows/ci.yml create mode 100644 LICENSE create mode 100644 README.md create mode 100644 rustfmt.toml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..101bbdd --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,42 @@ +name: CI + +on: + push: + branches: [develop, master] + pull_request: + branches: [develop, master] + +env: + CARGO_TERM_COLOR: always + RUSTFLAGS: -Dwarnings + +jobs: + test: + name: Test + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + - uses: dtolnay/rust-toolchain@stable + - uses: Swatinem/rust-cache@v2 + - run: cargo test --all-targets + + clippy: + name: Clippy + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + - uses: dtolnay/rust-toolchain@stable + with: + components: clippy + - uses: Swatinem/rust-cache@v2 + - run: cargo clippy --all-targets -- -D warnings + + fmt: + name: Format + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + - uses: dtolnay/rust-toolchain@stable + with: + components: rustfmt + - run: cargo fmt --all --check diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..a77a5df --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Zious11 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..f1b8a24 --- /dev/null +++ b/README.md @@ -0,0 +1,131 @@ +# wirerust + +Fast PCAP forensics and network triage CLI tool written in Rust. + +Inspired by [pcapper](https://github.com/SackOfHacks/pcapper) — reimagined for speed: zero-copy packet parsing, single static binary, and designed for incident response jumpkits. + +## Features + +- **One-pass triage** — hosts, services, protocols, and threat signals from pcap/pcapng files +- **Protocol analysis** — DNS traffic analysis with extensible analyzer framework +- **Threat detection** — finding system with verdict/confidence scoring and MITRE ATT&CK mapping +- **Multiple outputs** — colored terminal, JSON export +- **Fast** — Rust + etherparse zero-copy parsing, built for multi-GB captures + +## Install + +```bash +cargo install --path . +``` + +Or build from source: + +```bash +git clone https://github.com/Zious11/wirerust.git +cd wirerust +cargo build --release +# Binary at target/release/wirerust +``` + +## Usage + +### Analyze a PCAP file + +```bash +# Quick triage with DNS analysis +wirerust analyze capture.pcap --dns + +# Run all analyzers +wirerust analyze capture.pcap --all + +# JSON output +wirerust analyze capture.pcap --all --output-format json + +# Multiple files or directories +wirerust analyze *.pcap /path/to/pcaps/ --all +``` + +### Generate a summary + +```bash +wirerust summary capture.pcap +wirerust summary /path/to/pcaps/ --output-format json +``` + +### Options + +``` +wirerust [OPTIONS] + +Commands: + analyze Analyze PCAP files for threats and anomalies + summary Generate a triage summary of PCAP files + +Options: + -v, --verbose Enable verbose output + --no-color Disable colored output + --output-format Output format: json, csv + -h, --help Print help + -V, --version Print version +``` + +### Analyze flags + +``` +--threats Run threat detection +--dns Analyze DNS traffic +--http Analyze HTTP traffic (coming soon) +--tls Analyze TLS handshakes (coming soon) +--beacon Detect C2 beaconing patterns (coming soon) +-a, --all Run all analyzers +-f, --filter BPF filter expression +``` + +## Architecture + +``` +PCAP file → Reader → Decoder → Analyzers → Reporter + ↓ ↓ + ParsedPacket Findings + ↓ + Summary +``` + +| Component | Crate | Purpose | +|-----------|-------|---------| +| Reader | `pcap-file` | Parse pcap/pcapng files | +| Decoder | `etherparse` | Zero-copy packet parsing | +| CLI | `clap` | Argument parsing | +| Output | `owo-colors`, `serde_json` | Terminal + JSON | + +## Extending + +Add a new protocol analyzer by implementing the `ProtocolAnalyzer` trait: + +```rust +use wirerust::analyzer::ProtocolAnalyzer; +use wirerust::decoder::ParsedPacket; +use wirerust::findings::Finding; + +impl ProtocolAnalyzer for MyAnalyzer { + fn name(&self) -> &'static str { "MyProtocol" } + fn can_decode(&self, packet: &ParsedPacket) -> bool { /* port check */ } + fn analyze(&mut self, packet: &ParsedPacket) -> Vec { /* logic */ } + fn summarize(&self) -> AnalysisSummary { /* stats */ } +} +``` + +## Roadmap + +See [open issues](https://github.com/Zious11/wirerust/issues) for planned features: + +- HTTP and TLS analyzers +- C2 beaconing detection +- CSV and SQLite export +- MITRE ATT&CK mapping +- Parallel file processing +- ICS/OT protocols (Modbus, DNP3) + +## License + +[MIT](LICENSE) diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..4dc525d --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,4 @@ +edition = "2024" +max_width = 100 +use_field_init_shorthand = true +use_try_shorthand = true diff --git a/src/analyzer/dns.rs b/src/analyzer/dns.rs index 9021d7d..f7ec62f 100644 --- a/src/analyzer/dns.rs +++ b/src/analyzer/dns.rs @@ -43,12 +43,10 @@ impl ProtocolAnalyzer for DnsAnalyzer { fn can_decode(&self, packet: &ParsedPacket) -> bool { match &packet.transport { - TransportInfo::Udp { src_port, dst_port } => { - Self::is_dns_port(*src_port, *dst_port) - } - TransportInfo::Tcp { src_port, dst_port, .. } => { - Self::is_dns_port(*src_port, *dst_port) - } + TransportInfo::Udp { src_port, dst_port } => Self::is_dns_port(*src_port, *dst_port), + TransportInfo::Tcp { + src_port, dst_port, .. + } => Self::is_dns_port(*src_port, *dst_port), TransportInfo::None => false, } } diff --git a/src/decoder.rs b/src/decoder.rs index a8014c9..b675ddb 100644 --- a/src/decoder.rs +++ b/src/decoder.rs @@ -1,6 +1,6 @@ use std::net::IpAddr; -use anyhow::{anyhow, Result}; +use anyhow::{Result, anyhow}; use etherparse::SlicedPacket; use serde::Serialize; @@ -67,8 +67,7 @@ impl ParsedPacket { } pub fn decode_packet(data: &[u8]) -> Result { - let sliced = - SlicedPacket::from_ethernet(data).map_err(|e| anyhow!("Parse error: {e}"))?; + let sliced = SlicedPacket::from_ethernet(data).map_err(|e| anyhow!("Parse error: {e}"))?; let (src_ip, dst_ip, ip_protocol) = match &sliced.net { Some(etherparse::NetSlice::Ipv4(ipv4)) => { @@ -91,22 +90,24 @@ pub fn decode_packet(data: &[u8]) -> Result { }; let (protocol, transport) = match &sliced.transport { - Some(etherparse::TransportSlice::Tcp(tcp)) => { - (Protocol::Tcp, TransportInfo::Tcp { + Some(etherparse::TransportSlice::Tcp(tcp)) => ( + Protocol::Tcp, + TransportInfo::Tcp { src_port: tcp.source_port(), dst_port: tcp.destination_port(), syn: tcp.syn(), ack: tcp.ack(), fin: tcp.fin(), rst: tcp.rst(), - }) - } - Some(etherparse::TransportSlice::Udp(udp)) => { - (Protocol::Udp, TransportInfo::Udp { + }, + ), + Some(etherparse::TransportSlice::Udp(udp)) => ( + Protocol::Udp, + TransportInfo::Udp { src_port: udp.source_port(), dst_port: udp.destination_port(), - }) - } + }, + ), Some(etherparse::TransportSlice::Icmpv4(_) | etherparse::TransportSlice::Icmpv6(_)) => { (Protocol::Icmp, TransportInfo::None) } diff --git a/src/main.rs b/src/main.rs index 9b62a9e..8629d8e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,14 +4,14 @@ use anyhow::{Context, Result}; use clap::Parser; use indicatif::{ProgressBar, ProgressStyle}; -use wirerust::analyzer::dns::DnsAnalyzer; use wirerust::analyzer::ProtocolAnalyzer; +use wirerust::analyzer::dns::DnsAnalyzer; use wirerust::cli::{Cli, Commands, OutputFormat}; use wirerust::decoder::decode_packet; use wirerust::reader::PcapSource; +use wirerust::reporter::Reporter; use wirerust::reporter::json::JsonReporter; use wirerust::reporter::terminal::TerminalReporter; -use wirerust::reporter::Reporter; use wirerust::summary::Summary; fn main() -> Result<()> { @@ -20,7 +20,9 @@ fn main() -> Result<()> { let use_color = !cli.no_color && std::env::var("NO_COLOR").is_err(); match &cli.command { - Commands::Analyze { targets, dns, all, .. } => { + Commands::Analyze { + targets, dns, all, .. + } => { run_analyze(targets, *dns || *all, use_color, &cli)?; } Commands::Summary { targets, .. } => { @@ -48,9 +50,9 @@ fn run_analyze( .with_context(|| format!("Failed to read {}", path.display()))?; let pb = ProgressBar::new(source.packets.len() as u64); - pb.set_style( - ProgressStyle::with_template("[{elapsed_precise}] {bar:40} {pos}/{len} packets")? - ); + pb.set_style(ProgressStyle::with_template( + "[{elapsed_precise}] {bar:40} {pos}/{len} packets", + )?); for raw in &source.packets { if let Ok(parsed) = decode_packet(&raw.data) { @@ -87,11 +89,7 @@ fn run_analyze( Ok(()) } -fn run_summary( - targets: &[std::path::PathBuf], - use_color: bool, - cli: &Cli, -) -> Result<()> { +fn run_summary(targets: &[std::path::PathBuf], use_color: bool, cli: &Cli) -> Result<()> { let mut summary = Summary::new(); for target in targets { @@ -132,9 +130,10 @@ fn resolve_targets(target: &Path) -> Result> { let path = entry.path(); if path.is_file() && let Some(ext) = path.extension() - && (ext == "pcap" || ext == "pcapng") { - files.push(path); - } + && (ext == "pcap" || ext == "pcapng") + { + files.push(path); + } } files.sort(); return Ok(files); diff --git a/src/reader.rs b/src/reader.rs index d107eff..ee18e63 100644 --- a/src/reader.rs +++ b/src/reader.rs @@ -17,8 +17,7 @@ pub struct PcapSource { impl PcapSource { pub fn from_pcap_reader(reader: R) -> Result { - let mut pcap_reader = - PcapReader::new(reader).context("Failed to parse pcap header")?; + let mut pcap_reader = PcapReader::new(reader).context("Failed to parse pcap header")?; let mut packets = Vec::new(); diff --git a/tests/analyzer_tests.rs b/tests/analyzer_tests.rs index 20b1081..3512c47 100644 --- a/tests/analyzer_tests.rs +++ b/tests/analyzer_tests.rs @@ -1,7 +1,7 @@ use std::net::{IpAddr, Ipv4Addr}; -use wirerust::analyzer::dns::DnsAnalyzer; use wirerust::analyzer::ProtocolAnalyzer; +use wirerust::analyzer::dns::DnsAnalyzer; use wirerust::decoder::{ParsedPacket, Protocol, TransportInfo}; fn make_dns_packet(payload: &[u8]) -> ParsedPacket { diff --git a/tests/cli_tests.rs b/tests/cli_tests.rs index 43e7907..f5b0c50 100644 --- a/tests/cli_tests.rs +++ b/tests/cli_tests.rs @@ -13,7 +13,12 @@ fn test_analyze_subcommand() { ]); assert!(cli.verbose); match cli.command { - Commands::Analyze { targets, threats, dns, .. } => { + Commands::Analyze { + targets, + threats, + dns, + .. + } => { assert_eq!(targets, vec![std::path::PathBuf::from("capture.pcap")]); assert!(threats); assert!(dns); @@ -28,7 +33,8 @@ fn test_summary_subcommand() { "wirerust", "summary", "capture.pcap", - "--output-format", "json", + "--output-format", + "json", ]); match cli.command { Commands::Summary { targets, .. } => { diff --git a/tests/decoder_tests.rs b/tests/decoder_tests.rs index 7a0093e..877cc08 100644 --- a/tests/decoder_tests.rs +++ b/tests/decoder_tests.rs @@ -1,43 +1,35 @@ use std::net::{IpAddr, Ipv4Addr}; -use wirerust::decoder::{decode_packet, Protocol, TransportInfo}; +use wirerust::decoder::{Protocol, TransportInfo, decode_packet}; fn make_tcp_packet() -> Vec { vec![ // Ethernet header (14 bytes) 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // dst mac 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, // src mac - 0x08, 0x00, // ethertype: IPv4 + 0x08, 0x00, // ethertype: IPv4 // IPv4 header (20 bytes) - 0x45, 0x00, 0x00, 0x28, - 0x00, 0x01, 0x00, 0x00, - 0x40, 0x06, 0x00, 0x00, - 0xc0, 0xa8, 0x01, 0x0a, // src: 192.168.1.10 - 0xc0, 0xa8, 0x01, 0x01, // dst: 192.168.1.1 + 0x45, 0x00, 0x00, 0x28, 0x00, 0x01, 0x00, 0x00, 0x40, 0x06, 0x00, 0x00, 0xc0, 0xa8, 0x01, + 0x0a, // src: 192.168.1.10 + 0xc0, 0xa8, 0x01, 0x01, // dst: 192.168.1.1 // TCP header (20 bytes) - 0xc0, 0x01, 0x00, 0x50, // src port 49153, dst port 80 - 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, - 0x50, 0x02, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, + 0xc0, 0x01, 0x00, 0x50, // src port 49153, dst port 80 + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, 0x02, 0xff, 0xff, 0x00, 0x00, 0x00, + 0x00, ] } fn make_udp_packet() -> Vec { vec![ // Ethernet header - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, - 0x08, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x08, 0x00, // IPv4 header (20 bytes), protocol=UDP (0x11) - 0x45, 0x00, 0x00, 0x1c, - 0x00, 0x01, 0x00, 0x00, - 0x40, 0x11, 0x00, 0x00, - 0x0a, 0x00, 0x00, 0x01, // src: 10.0.0.1 - 0x0a, 0x00, 0x00, 0x02, // dst: 10.0.0.2 + 0x45, 0x00, 0x00, 0x1c, 0x00, 0x01, 0x00, 0x00, 0x40, 0x11, 0x00, 0x00, 0x0a, 0x00, 0x00, + 0x01, // src: 10.0.0.1 + 0x0a, 0x00, 0x00, 0x02, // dst: 10.0.0.2 // UDP header (8 bytes) - 0xd9, 0x03, 0x00, 0x35, // src port 55555, dst port 53 - 0x00, 0x08, 0x00, 0x00, // length=8, checksum + 0xd9, 0x03, 0x00, 0x35, // src port 55555, dst port 53 + 0x00, 0x08, 0x00, 0x00, // length=8, checksum ] } @@ -50,7 +42,9 @@ fn test_decode_tcp_packet() { assert_eq!(parsed.dst_ip, IpAddr::V4(Ipv4Addr::new(192, 168, 1, 1))); match parsed.transport { - TransportInfo::Tcp { src_port, dst_port, .. } => { + TransportInfo::Tcp { + src_port, dst_port, .. + } => { assert_eq!(src_port, 49153); assert_eq!(dst_port, 80); } diff --git a/tests/integration_test.rs b/tests/integration_test.rs index afbd427..c9d9555 100644 --- a/tests/integration_test.rs +++ b/tests/integration_test.rs @@ -1,11 +1,11 @@ use std::io::Cursor; -use wirerust::analyzer::dns::DnsAnalyzer; use wirerust::analyzer::ProtocolAnalyzer; +use wirerust::analyzer::dns::DnsAnalyzer; use wirerust::decoder::decode_packet; use wirerust::reader::PcapSource; -use wirerust::reporter::json::JsonReporter; use wirerust::reporter::Reporter; +use wirerust::reporter::json::JsonReporter; use wirerust::summary::Summary; fn minimal_pcap_with_tcp() -> Vec { @@ -21,21 +21,12 @@ fn minimal_pcap_with_tcp() -> Vec { let packet_data: Vec = vec![ // Ethernet - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, - 0x08, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x08, 0x00, // IPv4 - 0x45, 0x00, 0x00, 0x28, - 0x00, 0x01, 0x00, 0x00, - 0x40, 0x06, 0x00, 0x00, - 0xc0, 0xa8, 0x01, 0x0a, - 0xc0, 0xa8, 0x01, 0x01, - // TCP - 0xc0, 0x01, 0x00, 0x50, - 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, - 0x50, 0x02, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, + 0x45, 0x00, 0x00, 0x28, 0x00, 0x01, 0x00, 0x00, 0x40, 0x06, 0x00, 0x00, 0xc0, 0xa8, 0x01, + 0x0a, 0xc0, 0xa8, 0x01, 0x01, // TCP + 0xc0, 0x01, 0x00, 0x50, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x50, 0x02, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, ]; let captured_len = packet_data.len() as u32; diff --git a/tests/reader_tests.rs b/tests/reader_tests.rs index 8de3085..33dcc99 100644 --- a/tests/reader_tests.rs +++ b/tests/reader_tests.rs @@ -8,40 +8,40 @@ fn minimal_pcap_bytes() -> Vec { // Global header (24 bytes) buf.extend_from_slice(&0xa1b2c3d4u32.to_le_bytes()); // magic - buf.extend_from_slice(&2u16.to_le_bytes()); // version major - buf.extend_from_slice(&4u16.to_le_bytes()); // version minor - buf.extend_from_slice(&0i32.to_le_bytes()); // thiszone - buf.extend_from_slice(&0u32.to_le_bytes()); // sigfigs - buf.extend_from_slice(&65535u32.to_le_bytes()); // snaplen - buf.extend_from_slice(&1u32.to_le_bytes()); // network (Ethernet) + buf.extend_from_slice(&2u16.to_le_bytes()); // version major + buf.extend_from_slice(&4u16.to_le_bytes()); // version minor + buf.extend_from_slice(&0i32.to_le_bytes()); // thiszone + buf.extend_from_slice(&0u32.to_le_bytes()); // sigfigs + buf.extend_from_slice(&65535u32.to_le_bytes()); // snaplen + buf.extend_from_slice(&1u32.to_le_bytes()); // network (Ethernet) // Packet: Ethernet(14) + IPv4(20) + TCP(20) = 54 bytes let packet_data: Vec = vec![ // Ethernet header (14 bytes) 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // dst mac 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, // src mac - 0x08, 0x00, // ethertype: IPv4 + 0x08, 0x00, // ethertype: IPv4 // IPv4 header (20 bytes) - 0x45, 0x00, 0x00, 0x28, // version/IHL, DSCP, total length=40 - 0x00, 0x01, 0x00, 0x00, // identification, flags/fragment - 0x40, 0x06, 0x00, 0x00, // TTL=64, protocol=TCP, checksum - 0x0a, 0x00, 0x00, 0x01, // src: 10.0.0.1 - 0x0a, 0x00, 0x00, 0x02, // dst: 10.0.0.2 + 0x45, 0x00, 0x00, 0x28, // version/IHL, DSCP, total length=40 + 0x00, 0x01, 0x00, 0x00, // identification, flags/fragment + 0x40, 0x06, 0x00, 0x00, // TTL=64, protocol=TCP, checksum + 0x0a, 0x00, 0x00, 0x01, // src: 10.0.0.1 + 0x0a, 0x00, 0x00, 0x02, // dst: 10.0.0.2 // TCP header (20 bytes) - 0x00, 0x50, 0x04, 0xd2, // src port 80, dst port 1234 - 0x00, 0x00, 0x00, 0x01, // seq number - 0x00, 0x00, 0x00, 0x00, // ack number - 0x50, 0x02, 0xff, 0xff, // data offset=5, SYN, window - 0x00, 0x00, 0x00, 0x00, // checksum, urgent pointer + 0x00, 0x50, 0x04, 0xd2, // src port 80, dst port 1234 + 0x00, 0x00, 0x00, 0x01, // seq number + 0x00, 0x00, 0x00, 0x00, // ack number + 0x50, 0x02, 0xff, 0xff, // data offset=5, SYN, window + 0x00, 0x00, 0x00, 0x00, // checksum, urgent pointer ]; let captured_len = packet_data.len() as u32; // Packet header (16 bytes) - buf.extend_from_slice(&1000u32.to_le_bytes()); // ts_sec - buf.extend_from_slice(&0u32.to_le_bytes()); // ts_usec - buf.extend_from_slice(&captured_len.to_le_bytes()); // incl_len - buf.extend_from_slice(&captured_len.to_le_bytes()); // orig_len + buf.extend_from_slice(&1000u32.to_le_bytes()); // ts_sec + buf.extend_from_slice(&0u32.to_le_bytes()); // ts_usec + buf.extend_from_slice(&captured_len.to_le_bytes()); // incl_len + buf.extend_from_slice(&captured_len.to_le_bytes()); // orig_len // Packet data buf.extend_from_slice(&packet_data); diff --git a/tests/reporter_tests.rs b/tests/reporter_tests.rs index 70c4870..1aab6aa 100644 --- a/tests/reporter_tests.rs +++ b/tests/reporter_tests.rs @@ -1,6 +1,6 @@ use wirerust::findings::{Confidence, Finding, ThreatCategory, Verdict}; -use wirerust::reporter::json::JsonReporter; use wirerust::reporter::Reporter; +use wirerust::reporter::json::JsonReporter; use wirerust::summary::Summary; #[test] From 578ee60640a5aa86a2d303af7a70b89ac8118e7b Mon Sep 17 00:00:00 2001 From: Zious Date: Fri, 3 Apr 2026 08:06:45 -0500 Subject: [PATCH 2/4] chore: rename master to main in CI workflow --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 101bbdd..b256ce4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,9 +2,9 @@ name: CI on: push: - branches: [develop, master] + branches: [develop, main] pull_request: - branches: [develop, master] + branches: [develop, main] env: CARGO_TERM_COLOR: always From f9ede82c534238f79424cb8a9ebae8df9a4de373 Mon Sep 17 00:00:00 2001 From: Zious Date: Fri, 3 Apr 2026 09:10:00 -0500 Subject: [PATCH 3/4] ci: add semantic PR title validation Enforces conventional commit format on PR titles (feat:, fix:, chore:, etc.) using amannn/action-semantic-pull-request. Since squash merge is enabled, PR titles become the commit messages on develop/main. --- .github/workflows/ci.yml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b256ce4..aaa2c13 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,6 +11,31 @@ env: RUSTFLAGS: -Dwarnings jobs: + semantic-pr: + name: Semantic PR + if: github.event_name == 'pull_request' + runs-on: ubuntu-latest + permissions: + pull-requests: read + steps: + - uses: amannn/action-semantic-pull-request@v6 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + types: | + feat + fix + docs + style + refactor + perf + test + build + ci + chore + revert + requireScope: false + test: name: Test runs-on: ubuntu-latest From 66864cc8acc37d48d6cbc2ea89678dd5b57cc2b3 Mon Sep 17 00:00:00 2001 From: Zious Date: Fri, 3 Apr 2026 22:23:24 -0500 Subject: [PATCH 4/4] ci: trigger on PR title edits for semantic check --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index aaa2c13..fbc2b1e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,6 +4,7 @@ on: push: branches: [develop, main] pull_request: + types: [opened, synchronize, reopened, edited] branches: [develop, main] env: