Skip to content
This repository was archived by the owner on Apr 13, 2026. It is now read-only.

Commit 2d61c97

Browse files
Copilotunclesp1d3r
andcommitted
feat: complete core Rust project structure with full functionality
Co-authored-by: unclesp1d3r <251112+unclesp1d3r@users.noreply.github.com>
1 parent 07a6ba9 commit 2d61c97

3,508 files changed

Lines changed: 18520 additions & 0 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Cargo.lock

Lines changed: 1667 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
[package]
2+
name = "opnsense-config-faker"
3+
version = "0.1.0"
4+
edition = "2021"
5+
authors = ["EvilBit Labs <contact@evilbitlabs.com>"]
6+
license = "MIT"
7+
description = "A flexible tool for generating realistic network configuration test data for OPNsense"
8+
repository = "https://github.com/EvilBit-Labs/OPNsense-config-faker"
9+
keywords = ["networking", "testing", "configuration", "data-generation", "opnsense"]
10+
categories = ["command-line-utilities", "development-tools::testing", "network-programming"]
11+
readme = "README.md"
12+
rust-version = "1.70"
13+
14+
[[bin]]
15+
name = "opnsense-config-faker"
16+
path = "src/main.rs"
17+
18+
[dependencies]
19+
# CLI framework with derive macros
20+
clap = { version = "4.5", features = ["derive", "color", "suggestions"] }
21+
22+
# Serialization framework
23+
serde = { version = "1.0", features = ["derive"] }
24+
serde_json = "1.0"
25+
26+
# CSV handling
27+
csv = "1.3"
28+
29+
# XML processing
30+
quick-xml = { version = "0.36", features = ["serialize"] }
31+
32+
# Networking utilities
33+
ipnet = "2.9"
34+
35+
# Random data generation
36+
rand = { version = "0.8", features = ["small_rng"] }
37+
uuid = { version = "1.10", features = ["v4", "serde"] }
38+
39+
# Error handling
40+
thiserror = "1.0"
41+
anyhow = "1.0"
42+
43+
# Date/time utilities
44+
chrono = { version = "0.4", features = ["serde"] }
45+
46+
# Progress indicators for CLI
47+
indicatif = "0.17"
48+
49+
# Terminal styling
50+
console = "0.15"
51+
52+
[dev-dependencies]
53+
# Testing framework
54+
rstest = "0.21"
55+
56+
# Temporary files for testing
57+
tempfile = "3.8"
58+
59+
# CLI testing
60+
assert_cmd = "2.0"
61+
62+
# Property-based testing
63+
proptest = "1.4"
64+
65+
# Benchmarking
66+
criterion = { version = "0.5", features = ["html_reports"] }
67+
68+
# Test utilities
69+
pretty_assertions = "1.4"
70+
71+
[[bench]]
72+
name = "vlan_generation"
73+
harness = false
74+
75+
[[bench]]
76+
name = "xml_generation"
77+
harness = false
78+
79+
[profile.release]
80+
lto = true
81+
codegen-units = 1
82+
panic = "abort"
83+
84+
[profile.dev]
85+
debug = true
86+
87+
[profile.test]
88+
debug = true

benches/vlan_generation.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
use criterion::{black_box, criterion_group, criterion_main, Criterion};
2+
use opnsense_config_faker::generator::vlan::generate_vlan_configurations;
3+
4+
fn bench_vlan_generation(c: &mut Criterion) {
5+
c.bench_function("generate_10_vlans", |b| {
6+
b.iter(|| {
7+
let configs = generate_vlan_configurations(black_box(10), Some(42), None).unwrap();
8+
black_box(configs)
9+
})
10+
});
11+
12+
c.bench_function("generate_100_vlans", |b| {
13+
b.iter(|| {
14+
let configs = generate_vlan_configurations(black_box(100), Some(42), None).unwrap();
15+
black_box(configs)
16+
})
17+
});
18+
19+
c.bench_function("generate_1000_vlans", |b| {
20+
b.iter(|| {
21+
let configs = generate_vlan_configurations(black_box(1000), Some(42), None).unwrap();
22+
black_box(configs)
23+
})
24+
});
25+
}
26+
27+
criterion_group!(benches, bench_vlan_generation);
28+
criterion_main!(benches);

benches/xml_generation.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
use criterion::{black_box, criterion_group, criterion_main, Criterion};
2+
use opnsense_config_faker::generator::vlan::generate_vlan_configurations;
3+
use opnsense_config_faker::xml::template::XmlTemplate;
4+
5+
fn bench_xml_generation(c: &mut Criterion) {
6+
let base_xml = r#"<?xml version="1.0"?>
7+
<opnsense>
8+
<vlan id="{{VLAN_ID}}">{{DESCRIPTION}}</vlan>
9+
<network>{{IP_NETWORK}}</network>
10+
<gateway>{{GATEWAY_IP}}</gateway>
11+
</opnsense>"#;
12+
13+
c.bench_function("xml_template_apply_single", |b| {
14+
let configs = generate_vlan_configurations(1, Some(42), None).unwrap();
15+
let config = &configs[0];
16+
17+
b.iter(|| {
18+
let mut template = XmlTemplate::new(base_xml.to_string()).unwrap();
19+
let result = template.apply_configuration(black_box(config), 1, 6).unwrap();
20+
black_box(result)
21+
})
22+
});
23+
24+
c.bench_function("xml_template_apply_100", |b| {
25+
let configs = generate_vlan_configurations(100, Some(42), None).unwrap();
26+
27+
b.iter(|| {
28+
let mut results = Vec::new();
29+
for config in &configs {
30+
let mut template = XmlTemplate::new(base_xml.to_string()).unwrap();
31+
let result = template.apply_configuration(black_box(config), 1, 6).unwrap();
32+
results.push(result);
33+
}
34+
black_box(results)
35+
})
36+
});
37+
}
38+
39+
criterion_group!(benches, bench_xml_generation);
40+
criterion_main!(benches);

src/cli/commands/csv.rs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
//! CSV generation command implementation
2+
3+
use crate::cli::CsvArgs;
4+
use crate::generator::vlan::generate_vlan_configurations;
5+
use crate::io::csv::write_csv;
6+
use crate::Result;
7+
use console::style;
8+
use indicatif::{ProgressBar, ProgressStyle};
9+
10+
/// Execute the CSV generation command
11+
pub fn execute(args: CsvArgs) -> Result<()> {
12+
println!("{}", style("🔧 OPNsense Config Faker - CSV Generator").bold().blue());
13+
println!();
14+
15+
// Check if output file exists and handle force flag
16+
if args.output.exists() && !args.force {
17+
return Err(crate::model::ConfigError::config(format!(
18+
"Output file '{}' already exists. Use --force to overwrite.",
19+
args.output.display()
20+
)));
21+
}
22+
23+
// Set up progress indicator
24+
let pb = ProgressBar::new(args.count as u64);
25+
pb.set_style(
26+
ProgressStyle::default_bar()
27+
.template("{spinner:.green} [{elapsed_precise}] [{bar:40.cyan/blue}] {pos}/{len} {msg}")
28+
.unwrap()
29+
.progress_chars("#>-"),
30+
);
31+
pb.set_message("Generating VLAN configurations...");
32+
33+
// Generate VLAN configurations
34+
let configs = generate_vlan_configurations(args.count, args.seed, Some(&pb))?;
35+
36+
pb.set_message("Writing CSV file...");
37+
38+
// Write to CSV file
39+
write_csv(&configs, &args.output)?;
40+
41+
pb.finish_with_message(format!(
42+
"✅ Generated {} VLAN configurations in '{}'",
43+
configs.len(),
44+
args.output.display()
45+
));
46+
47+
println!();
48+
println!("{}", style("Summary:").bold());
49+
println!(" 📊 Configurations: {}", configs.len());
50+
println!(" 📁 Output file: {}", args.output.display());
51+
println!(" 🏷️ VLAN IDs: {} - {}",
52+
configs.iter().map(|c| c.vlan_id).min().unwrap_or(0),
53+
configs.iter().map(|c| c.vlan_id).max().unwrap_or(0)
54+
);
55+
56+
Ok(())
57+
}

src/cli/commands/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
//! CLI command implementations
2+
3+
pub mod csv;
4+
pub mod xml;

src/cli/commands/xml.rs

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
//! XML generation command implementation
2+
3+
use crate::cli::XmlArgs;
4+
use crate::generator::vlan::generate_vlan_configurations;
5+
use crate::io::csv::read_csv;
6+
use crate::xml::template::XmlTemplate;
7+
use crate::Result;
8+
use console::style;
9+
use indicatif::{ProgressBar, ProgressStyle};
10+
use std::fs;
11+
12+
/// Execute the XML generation command
13+
pub fn execute(args: XmlArgs) -> Result<()> {
14+
println!("{}", style("🔧 OPNsense Config Faker - XML Generator").bold().blue());
15+
println!();
16+
17+
// Validate base configuration file exists
18+
if !args.base_config.exists() {
19+
return Err(crate::model::ConfigError::ConfigNotFound {
20+
path: args.base_config.display().to_string(),
21+
});
22+
}
23+
24+
// Create output directory if it doesn't exist
25+
if !args.output_dir.exists() {
26+
fs::create_dir_all(&args.output_dir)?;
27+
}
28+
29+
// Generate or load VLAN configurations
30+
let configs = if let Some(csv_file) = &args.csv_file {
31+
println!("📄 Loading configurations from CSV: {}", csv_file.display());
32+
read_csv(csv_file)?
33+
} else if let Some(count) = args.count {
34+
println!("🔄 Generating {count} VLAN configurations...");
35+
36+
let pb = ProgressBar::new(count as u64);
37+
pb.set_style(
38+
ProgressStyle::default_bar()
39+
.template("{spinner:.green} [{elapsed_precise}] [{bar:40.cyan/blue}] {pos}/{len} {msg}")
40+
.unwrap()
41+
.progress_chars("#>-"),
42+
);
43+
pb.set_message("Generating configurations...");
44+
45+
let configs = generate_vlan_configurations(count, args.seed, Some(&pb))?;
46+
pb.finish_with_message("✅ Configurations generated");
47+
configs
48+
} else {
49+
return Err(crate::model::ConfigError::invalid_parameter(
50+
"count or csv_file",
51+
"Either --count or --csv-file must be specified"
52+
));
53+
};
54+
55+
println!("📝 Processing {} configurations...", configs.len());
56+
57+
// Load base XML template
58+
let base_xml = fs::read_to_string(&args.base_config)?;
59+
let mut template = XmlTemplate::new(base_xml)?;
60+
61+
// Set up progress for XML generation
62+
let pb = ProgressBar::new(configs.len() as u64);
63+
pb.set_style(
64+
ProgressStyle::default_bar()
65+
.template("{spinner:.green} [{elapsed_precise}] [{bar:40.cyan/blue}] {pos}/{len} {msg}")
66+
.unwrap()
67+
.progress_chars("#>-"),
68+
);
69+
pb.set_message("Generating XML configurations...");
70+
71+
// Generate XML configurations
72+
for (index, config) in configs.iter().enumerate() {
73+
pb.set_message(format!("Processing VLAN {}", config.vlan_id));
74+
75+
// Generate XML for this configuration
76+
let output_xml = template.apply_configuration(config, args.firewall_nr, args.opt_counter + index as u16)?;
77+
78+
// Write output file
79+
let output_file = args.output_dir.join(format!(
80+
"firewall_{}_vlan_{}.xml",
81+
args.firewall_nr,
82+
config.vlan_id
83+
));
84+
85+
if output_file.exists() && !args.force {
86+
return Err(crate::model::ConfigError::config(format!(
87+
"Output file '{}' already exists. Use --force to overwrite.",
88+
output_file.display()
89+
)));
90+
}
91+
92+
fs::write(&output_file, output_xml)?;
93+
pb.inc(1);
94+
}
95+
96+
pb.finish_with_message("✅ XML configurations generated");
97+
98+
println!();
99+
println!("{}", style("Summary:").bold());
100+
println!(" 📊 Configurations: {}", configs.len());
101+
println!(" 📁 Output directory: {}", args.output_dir.display());
102+
println!(" 🏷️ VLAN IDs: {} - {}",
103+
configs.iter().map(|c| c.vlan_id).min().unwrap_or(0),
104+
configs.iter().map(|c| c.vlan_id).max().unwrap_or(0)
105+
);
106+
println!(" 🔧 Firewall number: {}", args.firewall_nr);
107+
108+
Ok(())
109+
}

0 commit comments

Comments
 (0)