Skip to content

Commit 982413d

Browse files
authored
Add simple text config file support (#12)
1 parent cbe6901 commit 982413d

2 files changed

Lines changed: 66 additions & 27 deletions

File tree

README.md

Lines changed: 10 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ httpjail -r "deny: telemetry\..*" -r "allow: .*" -- ./my-app
4242
httpjail -r "allow-get: api\.github\.com" -r "deny: .*" -- git pull
4343

4444
# Use config file for complex rules
45-
httpjail --config rules.yaml -- python script.py
45+
httpjail --config rules.txt -- python script.py
4646
```
4747

4848
## Architecture Overview
@@ -148,41 +148,26 @@ httpjail \
148148

149149
### Configuration File
150150

151-
Create a `rules.yaml`:
151+
Create a `rules.txt` (one rule per line, `#` comments and blank lines are ignored):
152152

153-
```yaml
154-
# rules.yaml
155-
rules:
156-
- action: allow
157-
pattern: "github\.com"
158-
methods: ["GET", "POST"]
159-
160-
- action: allow
161-
pattern: "api\..*\.com"
162-
methods: ["GET"]
163-
164-
- action: deny
165-
pattern: "telemetry"
166-
167-
- action: deny
168-
pattern: ".*"
169-
170-
logging:
171-
level: info
172-
file: /var/log/httpjail.log
153+
```text
154+
# rules.txt
155+
allow-get: github\.com
156+
deny: telemetry
157+
allow: .*
173158
```
174159

175160
Use the config:
176161

177162
```bash
178-
httpjail --config rules.yaml -- ./my-application
163+
httpjail --config rules.txt -- ./my-application
179164
```
180165

181166
### Advanced Options
182167

183168
```bash
184169
# Dry run - log what would be blocked without blocking
185-
httpjail --dry-run --config rules.yaml -- ./app
170+
httpjail --dry-run --config rules.txt -- ./app
186171

187172
# Verbose logging
188173
httpjail -vvv --allow ".*" -- curl https://example.com
@@ -253,7 +238,7 @@ RULE FORMAT:
253238
254239
EXAMPLES:
255240
httpjail -r "allow: github\.com" -r "deny: .*" -- git clone https://github.com/user/repo
256-
httpjail --config rules.yaml -- npm install
241+
httpjail --config rules.txt -- npm install
257242
httpjail --dry-run -r "deny: telemetry" -r "allow: .*" -- ./application
258243
httpjail --weak -r "allow: .*" -- npm test # Use environment variables only
259244
```

src/main.rs

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use anyhow::Result;
1+
use anyhow::{Context, Result};
22
use clap::Parser;
33
use httpjail::jail::{JailConfig, create_jail};
44
use httpjail::proxy::ProxyServer;
@@ -175,7 +175,20 @@ fn parse_rule(rule_str: &str) -> Result<Rule> {
175175
fn build_rules(args: &Args) -> Result<Vec<Rule>> {
176176
let mut rules = Vec::new();
177177

178-
// Parse rules in the exact order specified
178+
// Load rules from config file if provided
179+
if let Some(config_path) = &args.config {
180+
let contents = std::fs::read_to_string(config_path)
181+
.with_context(|| format!("Failed to read config file: {}", config_path))?;
182+
for line in contents.lines() {
183+
let line = line.trim();
184+
if line.is_empty() || line.starts_with('#') {
185+
continue;
186+
}
187+
rules.push(parse_rule(line)?);
188+
}
189+
}
190+
191+
// Parse command line rules in the exact order specified
179192
for rule_str in &args.rules {
180193
rules.push(parse_rule(rule_str)?);
181194
}
@@ -501,4 +514,45 @@ mod tests {
501514
Action::Allow
502515
));
503516
}
517+
518+
#[test]
519+
fn test_build_rules_from_config_file() {
520+
use std::io::Write;
521+
use tempfile::NamedTempFile;
522+
523+
let mut file = NamedTempFile::new().unwrap();
524+
writeln!(
525+
file,
526+
"allow-get: google\\.com\n# comment\ndeny: yahoo.com\n\nallow: .*"
527+
)
528+
.unwrap();
529+
530+
let args = Args {
531+
rules: vec![],
532+
config: Some(file.path().to_str().unwrap().to_string()),
533+
dry_run: false,
534+
log_only: false,
535+
no_tls_intercept: false,
536+
interactive: false,
537+
weak: false,
538+
verbose: 0,
539+
timeout: None,
540+
no_jail_cleanup: false,
541+
cleanup: false,
542+
command: vec![],
543+
};
544+
545+
let rules = build_rules(&args).unwrap();
546+
assert_eq!(rules.len(), 3);
547+
548+
// First rule should be allow for GET method only
549+
assert!(matches!(rules[0].action, Action::Allow));
550+
assert!(rules[0].methods.as_ref().unwrap().contains(&Method::GET));
551+
552+
// Second rule should be deny
553+
assert!(matches!(rules[1].action, Action::Deny));
554+
555+
// Third rule allow all
556+
assert!(matches!(rules[2].action, Action::Allow));
557+
}
504558
}

0 commit comments

Comments
 (0)