mirror of
https://github.com/openai/codex.git
synced 2026-11-07 20:30:33 +00:00
Add opt-in Unicode canonical matching to exec policy rules (#59535)
## What changed - Support `canonical_matching=True` in `prefix_rule` and `canonical_matching = true` in managed TOML prefix rules. Apply Unicode canonical caseless matching to every prefix token, including alternatives, while keeping exact matching as the default. - Match case and canonically equivalent Unicode spellings, such as `bash` and `bAſh`, without resolving executables on the filesystem. - Preserve managed restrictions when checking absolute-path rule amendments, and enforce applicable `host_executable` path allowlists during basename fallback. ## Testing Add coverage for case folding, Unicode normalization, token alternatives, exact-match defaults, and host executable allowlists. Extend managed-policy and shell-execution tests to cover canonical matching. GitOrigin-RevId: c2f79069dc38d55c77028c457b22beb468d5c571
This commit is contained in:
@@ -638,7 +638,7 @@ async fn execpolicy_blocks_shell_invocation() -> Result<()> {
|
||||
.expect("create policy directory");
|
||||
fs::write(
|
||||
&policy_path,
|
||||
r#"prefix_rule(pattern=["echo"], decision="forbidden")"#,
|
||||
r#"prefix_rule(pattern=["bash"], canonical_matching=True, decision="forbidden")"#,
|
||||
)
|
||||
.expect("write policy file");
|
||||
});
|
||||
@@ -647,7 +647,7 @@ async fn execpolicy_blocks_shell_invocation() -> Result<()> {
|
||||
|
||||
let call_id = "shell-forbidden";
|
||||
let args = json!({
|
||||
"cmd": "echo blocked",
|
||||
"cmd": "bAſh --version",
|
||||
"yield_time_ms": 1_000,
|
||||
});
|
||||
|
||||
@@ -706,7 +706,7 @@ async fn execpolicy_blocks_shell_invocation() -> Result<()> {
|
||||
.function_call_output_text(call_id)
|
||||
.expect("forbidden command should produce a tool response");
|
||||
assert!(
|
||||
output.contains("policy forbids commands starting with `echo`"),
|
||||
output.contains("policy forbids commands starting with `'bAſh'`"),
|
||||
"unexpected output: {output}"
|
||||
);
|
||||
|
||||
@@ -720,7 +720,7 @@ async fn inherited_policy_allows_remembered_commands_and_enforces_managed_denial
|
||||
let test = test_codex()
|
||||
.with_cloud_config_bundle(CloudConfigBundleFixture::loader_with_enterprise_requirement(
|
||||
r#"[rules]
|
||||
prefix_rules = [{ pattern = [{ token = "touch" }, { token = "denied-marker" }], decision = "forbidden" }]"#,
|
||||
prefix_rules = [{ pattern = [{ token = "touch" }, { token = "denied-ma\u0301rker" }], canonical_matching = true, decision = "forbidden" }]"#,
|
||||
))
|
||||
.build_with_auto_env(&server)
|
||||
.await?;
|
||||
@@ -752,7 +752,7 @@ prefix_rules = [{ pattern = [{ token = "touch" }, { token = "denied-marker" }],
|
||||
sse(vec![
|
||||
ev_response_created("commands"),
|
||||
ev_exec_command_call("allowed", "touch allowed-marker"),
|
||||
ev_exec_command_call("denied", "touch denied-marker"),
|
||||
ev_exec_command_call("denied", "touch Denied-MárKer"),
|
||||
ev_completed("commands"),
|
||||
]),
|
||||
sse_completed("done"),
|
||||
@@ -784,12 +784,12 @@ prefix_rules = [{ pattern = [{ token = "touch" }, { token = "denied-marker" }],
|
||||
)
|
||||
.await?;
|
||||
assert!(files.iter().any(|file| file.file_name == "allowed-marker"));
|
||||
assert!(!files.iter().any(|file| file.file_name == "denied-marker"));
|
||||
assert!(!files.iter().any(|file| file.file_name == "Denied-MárKer"));
|
||||
let denial = requests
|
||||
.function_call_output_text("denied")
|
||||
.expect("denied command output");
|
||||
assert!(
|
||||
denial.contains("policy forbids commands starting with `touch denied-marker`"),
|
||||
denial.contains("policy forbids commands starting with `touch 'Denied-MárKer'`"),
|
||||
"{denial}"
|
||||
);
|
||||
Ok(())
|
||||
|
||||
Reference in New Issue
Block a user