mirror of
https://github.com/openai/codex.git
synced 2026-05-02 20:32:04 +03:00
feat(core): persist network approvals in execpolicy (#12357)
## Summary Persist network approval allow/deny decisions as `network_rule(...)` entries in execpolicy (not proxy config) It adds `network_rule` parsing + append support in `codex-execpolicy`, including `decision="prompt"` (parse-only; not compiled into proxy allow/deny lists) - compile execpolicy network rules into proxy allow/deny lists and update the live proxy state on approval - preserve requirements execpolicy `network_rule(...)` entries when merging with file-based execpolicy - reject broad wildcard hosts (for example `*`) for persisted `network_rule(...)`
This commit is contained in:
@@ -18,6 +18,8 @@ use std::sync::Arc;
|
||||
use crate::decision::Decision;
|
||||
use crate::error::Error;
|
||||
use crate::error::Result;
|
||||
use crate::rule::NetworkRule;
|
||||
use crate::rule::NetworkRuleProtocol;
|
||||
use crate::rule::PatternToken;
|
||||
use crate::rule::PrefixPattern;
|
||||
use crate::rule::PrefixRule;
|
||||
@@ -71,12 +73,14 @@ impl PolicyParser {
|
||||
#[derive(Debug, ProvidesStaticType)]
|
||||
struct PolicyBuilder {
|
||||
rules_by_program: MultiMap<String, RuleRef>,
|
||||
network_rules: Vec<NetworkRule>,
|
||||
}
|
||||
|
||||
impl PolicyBuilder {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
rules_by_program: MultiMap::new(),
|
||||
network_rules: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,8 +89,12 @@ impl PolicyBuilder {
|
||||
.insert(rule.program().to_string(), rule);
|
||||
}
|
||||
|
||||
fn add_network_rule(&mut self, rule: NetworkRule) {
|
||||
self.network_rules.push(rule);
|
||||
}
|
||||
|
||||
fn build(self) -> crate::policy::Policy {
|
||||
crate::policy::Policy::new(self.rules_by_program)
|
||||
crate::policy::Policy::from_parts(self.rules_by_program, self.network_rules)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,6 +150,13 @@ fn parse_examples<'v>(examples: UnpackList<Value<'v>>) -> Result<Vec<Vec<String>
|
||||
examples.items.into_iter().map(parse_example).collect()
|
||||
}
|
||||
|
||||
fn parse_network_rule_decision(raw: &str) -> Result<Decision> {
|
||||
match raw {
|
||||
"deny" => Ok(Decision::Forbidden),
|
||||
other => Decision::parse(other),
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_example<'v>(value: Value<'v>) -> Result<Vec<String>> {
|
||||
if let Some(raw) = value.unpack_str() {
|
||||
parse_string_example(raw)
|
||||
@@ -266,4 +281,31 @@ fn policy_builtins(builder: &mut GlobalsBuilder) {
|
||||
rules.into_iter().for_each(|rule| builder.add_rule(rule));
|
||||
Ok(NoneType)
|
||||
}
|
||||
|
||||
fn network_rule<'v>(
|
||||
host: &'v str,
|
||||
protocol: &'v str,
|
||||
decision: &'v str,
|
||||
justification: Option<&'v str>,
|
||||
eval: &mut Evaluator<'v, '_, '_>,
|
||||
) -> anyhow::Result<NoneType> {
|
||||
let protocol = NetworkRuleProtocol::parse(protocol)?;
|
||||
let decision = parse_network_rule_decision(decision)?;
|
||||
let justification = match justification {
|
||||
Some(raw) if raw.trim().is_empty() => {
|
||||
return Err(Error::InvalidRule("justification cannot be empty".to_string()).into());
|
||||
}
|
||||
Some(raw) => Some(raw.to_string()),
|
||||
None => None,
|
||||
};
|
||||
|
||||
let mut builder = policy_builder(eval);
|
||||
builder.add_network_rule(NetworkRule {
|
||||
host: crate::rule::normalize_network_rule_host(host)?,
|
||||
protocol,
|
||||
decision,
|
||||
justification,
|
||||
});
|
||||
Ok(NoneType)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user