From 1498116afeb18645a665f0bb83d4702b4ddc9c2e Mon Sep 17 00:00:00 2001 From: Ammar Bandukwala Date: Wed, 10 Sep 2025 12:06:18 -0500 Subject: [PATCH] Add simple text config file support --- README.md | 35 +++++++++----------------------- src/main.rs | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 66 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index 2065b655..d1730e21 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ httpjail -r "deny: telemetry\..*" -r "allow: .*" -- ./my-app httpjail -r "allow-get: api\.github\.com" -r "deny: .*" -- git pull # Use config file for complex rules -httpjail --config rules.yaml -- python script.py +httpjail --config rules.txt -- python script.py ``` ## Architecture Overview @@ -152,41 +152,26 @@ httpjail \ ### Configuration File -Create a `rules.yaml`: +Create a `rules.txt` (one rule per line, `#` comments and blank lines are ignored): -```yaml -# rules.yaml -rules: - - action: allow - pattern: "github\.com" - methods: ["GET", "POST"] - - - action: allow - pattern: "api\..*\.com" - methods: ["GET"] - - - action: deny - pattern: "telemetry" - - - action: deny - pattern: ".*" - -logging: - level: info - file: /var/log/httpjail.log +```text +# rules.txt +allow-get: github\.com +deny: telemetry +allow: .* ``` Use the config: ```bash -httpjail --config rules.yaml -- ./my-application +httpjail --config rules.txt -- ./my-application ``` ### Advanced Options ```bash # Dry run - log what would be blocked without blocking -httpjail --dry-run --config rules.yaml -- ./app +httpjail --dry-run --config rules.txt -- ./app # Verbose logging httpjail -vvv --allow ".*" -- curl https://example.com @@ -257,7 +242,7 @@ RULE FORMAT: EXAMPLES: httpjail -r "allow: github\.com" -r "deny: .*" -- git clone https://github.com/user/repo - httpjail --config rules.yaml -- npm install + httpjail --config rules.txt -- npm install httpjail --dry-run -r "deny: telemetry" -r "allow: .*" -- ./application httpjail --weak -r "allow: .*" -- npm test # Use environment variables only ``` diff --git a/src/main.rs b/src/main.rs index e5cdab07..831660b2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,4 @@ -use anyhow::Result; +use anyhow::{Context, Result}; use clap::Parser; use httpjail::jail::{JailConfig, create_jail}; use httpjail::proxy::ProxyServer; @@ -175,7 +175,20 @@ fn parse_rule(rule_str: &str) -> Result { fn build_rules(args: &Args) -> Result> { let mut rules = Vec::new(); - // Parse rules in the exact order specified + // Load rules from config file if provided + if let Some(config_path) = &args.config { + let contents = std::fs::read_to_string(config_path) + .with_context(|| format!("Failed to read config file: {}", config_path))?; + for line in contents.lines() { + let line = line.trim(); + if line.is_empty() || line.starts_with('#') { + continue; + } + rules.push(parse_rule(line)?); + } + } + + // Parse command line rules in the exact order specified for rule_str in &args.rules { rules.push(parse_rule(rule_str)?); } @@ -501,4 +514,45 @@ mod tests { Action::Allow )); } + + #[test] + fn test_build_rules_from_config_file() { + use std::io::Write; + use tempfile::NamedTempFile; + + let mut file = NamedTempFile::new().unwrap(); + writeln!( + file, + "allow-get: google\\.com\n# comment\ndeny: yahoo.com\n\nallow: .*" + ) + .unwrap(); + + let args = Args { + rules: vec![], + config: Some(file.path().to_str().unwrap().to_string()), + dry_run: false, + log_only: false, + no_tls_intercept: false, + interactive: false, + weak: false, + verbose: 0, + timeout: None, + no_jail_cleanup: false, + cleanup: false, + command: vec![], + }; + + let rules = build_rules(&args).unwrap(); + assert_eq!(rules.len(), 3); + + // First rule should be allow for GET method only + assert!(matches!(rules[0].action, Action::Allow)); + assert!(rules[0].methods.as_ref().unwrap().contains(&Method::GET)); + + // Second rule should be deny + assert!(matches!(rules[1].action, Action::Deny)); + + // Third rule allow all + assert!(matches!(rules[2].action, Action::Allow)); + } }