mirror of
https://github.com/openai/codex.git
synced 2026-11-06 00:30:29 +00:00
chore(core) Restrict model-suggested rules (#11671)
## Summary If the model suggests a bad rule, don't show it to the user. This does not impact the parsing of existing rules, just the ones we show. ## Testing - [x] Added unit tests - [x] Ran locally
This commit is contained in:
1 parent
1e75173ebd
commit
e6e4c5fa3a
1 file changed
+158
@@ -35,6 +35,54 @@ const PROMPT_CONFLICT_REASON: &str =
|
|||||||
const RULES_DIR_NAME: &str = "rules";
|
const RULES_DIR_NAME: &str = "rules";
|
||||||
const RULE_EXTENSION: &str = "rules";
|
const RULE_EXTENSION: &str = "rules";
|
||||||
const DEFAULT_POLICY_FILE: &str = "default.rules";
|
const DEFAULT_POLICY_FILE: &str = "default.rules";
|
||||||
|
static BANNED_PREFIX_SUGGESTIONS: &[&[&str]] = &[
|
||||||
|
&["python3"],
|
||||||
|
&["python3", "-"],
|
||||||
|
&["python3", "-c"],
|
||||||
|
&["python"],
|
||||||
|
&["python", "-"],
|
||||||
|
&["python", "-c"],
|
||||||
|
&["py"],
|
||||||
|
&["py", "-3"],
|
||||||
|
&["pythonw"],
|
||||||
|
&["pyw"],
|
||||||
|
&["pypy"],
|
||||||
|
&["pypy3"],
|
||||||
|
&["git"],
|
||||||
|
&["bash"],
|
||||||
|
&["bash", "-lc"],
|
||||||
|
&["sh"],
|
||||||
|
&["sh", "-c"],
|
||||||
|
&["sh", "-lc"],
|
||||||
|
&["zsh"],
|
||||||
|
&["zsh", "-lc"],
|
||||||
|
&["/bin/zsh"],
|
||||||
|
&["/bin/zsh", "-lc"],
|
||||||
|
&["/bin/bash"],
|
||||||
|
&["/bin/bash", "-lc"],
|
||||||
|
&["pwsh"],
|
||||||
|
&["pwsh", "-Command"],
|
||||||
|
&["pwsh", "-c"],
|
||||||
|
&["powershell"],
|
||||||
|
&["powershell", "-Command"],
|
||||||
|
&["powershell", "-c"],
|
||||||
|
&["powershell.exe"],
|
||||||
|
&["powershell.exe", "-Command"],
|
||||||
|
&["powershell.exe", "-c"],
|
||||||
|
&["env"],
|
||||||
|
&["sudo"],
|
||||||
|
&["node"],
|
||||||
|
&["node", "-e"],
|
||||||
|
&["perl"],
|
||||||
|
&["perl", "-e"],
|
||||||
|
&["ruby"],
|
||||||
|
&["ruby", "-e"],
|
||||||
|
&["php"],
|
||||||
|
&["php", "-r"],
|
||||||
|
&["lua"],
|
||||||
|
&["lua", "-e"],
|
||||||
|
&["osascript"],
|
||||||
|
];
|
||||||
|
|
||||||
fn is_policy_match(rule_match: &RuleMatch) -> bool {
|
fn is_policy_match(rule_match: &RuleMatch) -> bool {
|
||||||
match rule_match {
|
match rule_match {
|
||||||
@@ -240,6 +288,10 @@ pub async fn load_exec_policy(config_stack: &ConfigLayerStack) -> Result<Policy,
|
|||||||
policy_paths.extend(layer_policy_paths);
|
policy_paths.extend(layer_policy_paths);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
tracing::trace!(
|
||||||
|
policy_paths = ?policy_paths,
|
||||||
|
"loaded exec policies"
|
||||||
|
);
|
||||||
|
|
||||||
let mut parser = PolicyParser::new();
|
let mut parser = PolicyParser::new();
|
||||||
for policy_path in &policy_paths {
|
for policy_path in &policy_paths {
|
||||||
@@ -261,6 +313,7 @@ pub async fn load_exec_policy(config_stack: &ConfigLayerStack) -> Result<Policy,
|
|||||||
|
|
||||||
let policy = parser.build();
|
let policy = parser.build();
|
||||||
tracing::debug!("loaded rules from {} files", policy_paths.len());
|
tracing::debug!("loaded rules from {} files", policy_paths.len());
|
||||||
|
tracing::trace!(rules = ?policy, "exec policy rules loaded");
|
||||||
|
|
||||||
let Some(requirements_policy) = config_stack.requirements().exec_policy.as_deref() else {
|
let Some(requirements_policy) = config_stack.requirements().exec_policy.as_deref() else {
|
||||||
return Ok(policy);
|
return Ok(policy);
|
||||||
@@ -418,6 +471,15 @@ fn derive_requested_execpolicy_amendment(
|
|||||||
if prefix_rule.is_empty() {
|
if prefix_rule.is_empty() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
if BANNED_PREFIX_SUGGESTIONS.iter().any(|banned| {
|
||||||
|
prefix_rule.len() == banned.len()
|
||||||
|
&& prefix_rule
|
||||||
|
.iter()
|
||||||
|
.map(String::as_str)
|
||||||
|
.eq(banned.iter().copied())
|
||||||
|
}) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
if matched_rules
|
if matched_rules
|
||||||
.iter()
|
.iter()
|
||||||
@@ -1384,6 +1446,102 @@ prefix_rule(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn derive_requested_execpolicy_amendment_returns_none_for_missing_prefix_rule() {
|
||||||
|
assert_eq!(None, derive_requested_execpolicy_amendment(None, &[]));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn derive_requested_execpolicy_amendment_returns_none_for_empty_prefix_rule() {
|
||||||
|
assert_eq!(
|
||||||
|
None,
|
||||||
|
derive_requested_execpolicy_amendment(Some(&Vec::new()), &[])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn derive_requested_execpolicy_amendment_returns_none_for_exact_banned_prefix_rule() {
|
||||||
|
assert_eq!(
|
||||||
|
None,
|
||||||
|
derive_requested_execpolicy_amendment(
|
||||||
|
Some(&vec!["python".to_string(), "-c".to_string()]),
|
||||||
|
&[],
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn derive_requested_execpolicy_amendment_returns_none_for_windows_and_pypy_variants() {
|
||||||
|
for prefix_rule in [
|
||||||
|
vec!["py".to_string()],
|
||||||
|
vec!["py".to_string(), "-3".to_string()],
|
||||||
|
vec!["pythonw".to_string()],
|
||||||
|
vec!["pyw".to_string()],
|
||||||
|
vec!["pypy".to_string()],
|
||||||
|
vec!["pypy3".to_string()],
|
||||||
|
] {
|
||||||
|
assert_eq!(
|
||||||
|
None,
|
||||||
|
derive_requested_execpolicy_amendment(Some(&prefix_rule), &[])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn derive_requested_execpolicy_amendment_returns_none_for_shell_and_powershell_variants() {
|
||||||
|
for prefix_rule in [
|
||||||
|
vec!["bash".to_string(), "-lc".to_string()],
|
||||||
|
vec!["sh".to_string(), "-c".to_string()],
|
||||||
|
vec!["sh".to_string(), "-lc".to_string()],
|
||||||
|
vec!["zsh".to_string(), "-lc".to_string()],
|
||||||
|
vec!["/bin/bash".to_string(), "-lc".to_string()],
|
||||||
|
vec!["/bin/zsh".to_string(), "-lc".to_string()],
|
||||||
|
vec!["pwsh".to_string()],
|
||||||
|
vec!["pwsh".to_string(), "-Command".to_string()],
|
||||||
|
vec!["pwsh".to_string(), "-c".to_string()],
|
||||||
|
vec!["powershell".to_string()],
|
||||||
|
vec!["powershell".to_string(), "-Command".to_string()],
|
||||||
|
vec!["powershell".to_string(), "-c".to_string()],
|
||||||
|
vec!["powershell.exe".to_string()],
|
||||||
|
vec!["powershell.exe".to_string(), "-Command".to_string()],
|
||||||
|
vec!["powershell.exe".to_string(), "-c".to_string()],
|
||||||
|
] {
|
||||||
|
assert_eq!(
|
||||||
|
None,
|
||||||
|
derive_requested_execpolicy_amendment(Some(&prefix_rule), &[])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn derive_requested_execpolicy_amendment_allows_non_exact_banned_prefix_rule_match() {
|
||||||
|
let prefix_rule = vec![
|
||||||
|
"python".to_string(),
|
||||||
|
"-c".to_string(),
|
||||||
|
"print('hi')".to_string(),
|
||||||
|
];
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
Some(ExecPolicyAmendment::new(prefix_rule.clone())),
|
||||||
|
derive_requested_execpolicy_amendment(Some(&prefix_rule), &[])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn derive_requested_execpolicy_amendment_returns_none_when_policy_prompt_matches() {
|
||||||
|
let prefix_rule = vec!["cargo".to_string(), "build".to_string()];
|
||||||
|
let matched_rules = vec![RuleMatch::PrefixRuleMatch {
|
||||||
|
matched_prefix: vec!["cargo".to_string()],
|
||||||
|
decision: Decision::Prompt,
|
||||||
|
justification: None,
|
||||||
|
}];
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
None,
|
||||||
|
derive_requested_execpolicy_amendment(Some(&prefix_rule), &matched_rules)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn dangerous_rm_rf_requires_approval_in_danger_full_access() {
|
async fn dangerous_rm_rf_requires_approval_in_danger_full_access() {
|
||||||
let command = vec_str(&["rm", "-rf", "/tmp/nonexistent"]);
|
let command = vec_str(&["rm", "-rf", "/tmp/nonexistent"]);
|
||||||
|
|||||||
Reference in new issue
Block a user