diff --git a/README.md b/README.md index 7552abe3..b6c8e5c5 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,7 @@ cargo install httpjail - 🌐 **HTTP/HTTPS interception** - Transparent proxy with TLS certificate injection - 🎯 **Regex-based filtering** - Flexible allow/deny rules with regex patterns - 📝 **Request logging** - Monitor and log all HTTP/HTTPS requests +- ⛔ **Default deny** - Requests are blocked unless explicitly allowed - 🖥️ **Cross-platform** - Native support for Linux and macOS - ⚡ **Zero configuration** - Works out of the box with sensible defaults @@ -28,6 +29,8 @@ cargo install httpjail ## Quick Start +> By default, httpjail denies all network requests. Add `allow:` rules to permit traffic. + ```bash # Allow only requests to github.com httpjail -r "allow: github\.com" -r "deny: .*" -- claude diff --git a/src/main.rs b/src/main.rs index 12db7d39..48295da7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -194,10 +194,9 @@ fn build_rules(args: &Args) -> Result> { rules.push(parse_rule(rule_str)?); } - // If no rules specified, default to allow all (for testing) + // If no rules specified, the rule engine will deny all requests by default if rules.is_empty() { - info!("No rules specified, defaulting to allow all"); - rules.push(Rule::new(Action::Allow, ".*")?); + info!("No rules specified; unmatched requests will be denied"); } Ok(rules) @@ -524,36 +523,26 @@ mod tests { use hyper::Method; #[test] - fn test_rule_matching() { - let rule = Rule::new(Action::Allow, r"github\.com").unwrap(); - assert!(rule.matches(Method::GET, "https://github.com/user/repo")); - assert!(rule.matches(Method::POST, "http://api.github.com/v3/repos")); - assert!(!rule.matches(Method::GET, "https://gitlab.com/user/repo")); - } + fn test_build_rules_no_rules_default_deny() { + let args = Args { + rules: vec![], + config: None, + request_log: None, + interactive: false, + weak: false, + verbose: 0, + timeout: None, + no_jail_cleanup: false, + cleanup: false, + server: false, + command: vec![], + }; - #[test] - fn test_rule_engine() { - let rules = vec![ - Rule::new(Action::Allow, r"github\.com").unwrap(), - Rule::new(Action::Deny, r"telemetry").unwrap(), - Rule::new(Action::Deny, r".*").unwrap(), - ]; + let rules = build_rules(&args).unwrap(); + assert!(rules.is_empty()); + // Rule engine should deny requests when no rules are specified let engine = RuleEngine::new(rules, None); - - // Test allow rule - assert!(matches!( - engine.evaluate(Method::GET, "https://github.com/api"), - Action::Allow - )); - - // Test deny rule - assert!(matches!( - engine.evaluate(Method::POST, "https://telemetry.example.com"), - Action::Deny - )); - - // Test default deny assert!(matches!( engine.evaluate(Method::GET, "https://example.com"), Action::Deny diff --git a/src/rules.rs b/src/rules.rs index 629cb559..698077a0 100644 --- a/src/rules.rs +++ b/src/rules.rs @@ -226,4 +226,14 @@ mod tests { let contents = std::fs::read_to_string(log_file.path()).unwrap(); assert!(contents.contains("- GET https://blocked.com")); } + + #[test] + fn test_default_deny_with_no_rules() { + let engine = RuleEngine::new(vec![], None); + + assert!(matches!( + engine.evaluate(Method::GET, "https://example.com"), + Action::Deny + )); + } }