feat(execpolicy): add network_rule parsing and persistence

This commit is contained in:
viyatb-oai
2026-02-02 11:30:46 -08:00
parent d3514bbdd2
commit 5d539f2c6d
7 changed files with 362 additions and 6 deletions

View File

@@ -6,6 +6,9 @@ use anyhow::Result;
use codex_execpolicy::Decision;
use codex_execpolicy::Error;
use codex_execpolicy::Evaluation;
use codex_execpolicy::NetworkRule;
use codex_execpolicy::NetworkRuleDecision;
use codex_execpolicy::NetworkRuleProtocol;
use codex_execpolicy::Policy;
use codex_execpolicy::PolicyParser;
use codex_execpolicy::RuleMatch;
@@ -72,6 +75,114 @@ prefix_rule(
Ok(())
}
#[test]
fn parses_network_rule() -> Result<()> {
let policy_src = r#"
network_rule(
host = "api.example.com",
protocol = "https",
decision = "allow",
justification = "Allow API calls",
)
"#;
let mut parser = PolicyParser::new();
parser.parse("test.rules", policy_src)?;
let policy = parser.build();
assert_eq!(
policy.network_rules(),
&[NetworkRule {
host: "api.example.com".to_string(),
protocol: NetworkRuleProtocol::Https,
decision: NetworkRuleDecision::Allow,
justification: Some("Allow API calls".to_string()),
}]
);
Ok(())
}
#[test]
fn rejects_network_rule_with_empty_host() {
let policy_src = r#"
network_rule(
host = " ",
protocol = "https",
decision = "allow",
)
"#;
let mut parser = PolicyParser::new();
let err = parser
.parse("test.rules", policy_src)
.expect_err("expected parse error");
assert!(
err.to_string()
.contains("invalid rule: host cannot be empty")
);
}
#[test]
fn rejects_network_rule_with_invalid_protocol() {
let policy_src = r#"
network_rule(
host = "api.example.com",
protocol = "socks5",
decision = "allow",
)
"#;
let mut parser = PolicyParser::new();
let err = parser
.parse("test.rules", policy_src)
.expect_err("expected parse error");
assert!(
err.to_string()
.contains("invalid rule: invalid network protocol: socks5")
);
}
#[test]
fn rejects_network_rule_with_invalid_decision() {
let policy_src = r#"
network_rule(
host = "api.example.com",
protocol = "https",
decision = "prompt",
)
"#;
let mut parser = PolicyParser::new();
let err = parser
.parse("test.rules", policy_src)
.expect_err("expected parse error");
assert!(
err.to_string()
.contains("invalid rule: invalid network decision: prompt")
);
}
#[test]
fn rejects_network_rule_with_empty_justification() {
let policy_src = r#"
network_rule(
host = "api.example.com",
protocol = "https",
decision = "allow",
justification = " ",
)
"#;
let mut parser = PolicyParser::new();
let err = parser
.parse("test.rules", policy_src)
.expect_err("expected parse error");
assert!(
err.to_string()
.contains("invalid rule: justification cannot be empty")
);
}
#[test]
fn justification_is_attached_to_forbidden_matches() -> Result<()> {
let policy_src = r#"