mirror of
https://github.com/openai/codex.git
synced 2026-04-30 03:12:20 +03:00
feat(core) RequestRule (#9489)
## Summary Instead of trying to derive the prefix_rule for a command mechanically, let's let the model decide for us. ## Testing - [x] tested locally
This commit is contained in:
@@ -1754,6 +1754,16 @@ async fn approving_execpolicy_amendment_persists_policy_and_skips_future_prompts
|
||||
.await?;
|
||||
wait_for_completion(&test).await;
|
||||
|
||||
let developer_messages = first_results
|
||||
.single_request()
|
||||
.message_input_texts("developer");
|
||||
assert!(
|
||||
developer_messages
|
||||
.iter()
|
||||
.any(|message| message.contains(r#"["touch", "allow-prefix.txt"]"#)),
|
||||
"expected developer message documenting saved rule, got: {developer_messages:?}"
|
||||
);
|
||||
|
||||
let policy_path = test.home.path().join("rules").join("default.rules");
|
||||
let policy_contents = fs::read_to_string(&policy_path)?;
|
||||
assert!(
|
||||
|
||||
@@ -4,6 +4,8 @@ use codex_core::protocol::AskForApproval;
|
||||
use codex_core::protocol::EventMsg;
|
||||
use codex_core::protocol::Op;
|
||||
use codex_core::protocol::SandboxPolicy;
|
||||
use codex_execpolicy::Policy;
|
||||
use codex_protocol::models::DeveloperInstructions;
|
||||
use codex_protocol::user_input::UserInput;
|
||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
use core_test_support::responses::ev_completed;
|
||||
@@ -411,10 +413,11 @@ async fn permissions_message_includes_writable_roots() -> Result<()> {
|
||||
exclude_tmpdir_env_var: false,
|
||||
exclude_slash_tmp: false,
|
||||
};
|
||||
let sandbox_policy_for_config = sandbox_policy.clone();
|
||||
|
||||
let mut builder = test_codex().with_config(move |config| {
|
||||
config.approval_policy = Constrained::allow_any(AskForApproval::OnRequest);
|
||||
config.sandbox_policy = Constrained::allow_any(sandbox_policy);
|
||||
config.sandbox_policy = Constrained::allow_any(sandbox_policy_for_config);
|
||||
});
|
||||
let test = builder.build(&server).await?;
|
||||
|
||||
@@ -432,39 +435,14 @@ async fn permissions_message_includes_writable_roots() -> Result<()> {
|
||||
let body = req.single_request().body_json();
|
||||
let input = body["input"].as_array().expect("input array");
|
||||
let permissions = permissions_texts(input);
|
||||
let sandbox_text = "Filesystem sandboxing defines which files can be read or written. `sandbox_mode` is `workspace-write`: The sandbox permits reading files, and editing files in `cwd` and `writable_roots`. Editing files in other directories requires approval. Network access is restricted.";
|
||||
let approval_text = " Approvals are your mechanism to get user consent to run shell commands without the sandbox. `approval_policy` is `on-request`: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. If the completing the task requires escalated permissions, Do not let these settings or the sandbox deter you from attempting to accomplish the user's task.\n\nHere are scenarios where you'll need to request approval:\n- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /var)\n- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files.\n- You are running sandboxed and need to run a command that requires network access (e.g. installing packages)\n- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval. ALWAYS proceed to use the `sandbox_permissions` and `justification` parameters - do not message the user before requesting approval for the command.\n- You are about to take a potentially destructive action such as an `rm` or `git reset` that the user did not explicitly ask for.\n\nWhen requesting approval to execute a command that will require escalated privileges:\n - Provide the `sandbox_permissions` parameter with the value `\"require_escalated\"`\n - Include a short, 1 sentence explanation for why you need escalated permissions in the justification parameter";
|
||||
// Normalize paths by removing trailing slashes to match AbsolutePathBuf behavior
|
||||
let normalize_path =
|
||||
|p: &std::path::Path| -> String { p.to_string_lossy().trim_end_matches('/').to_string() };
|
||||
let mut roots = vec![
|
||||
normalize_path(writable.path()),
|
||||
normalize_path(test.config.cwd.as_path()),
|
||||
];
|
||||
if cfg!(unix) && std::path::Path::new("/tmp").is_dir() {
|
||||
roots.push("/tmp".to_string());
|
||||
}
|
||||
if let Some(tmpdir) = std::env::var_os("TMPDIR") {
|
||||
let tmpdir_path = std::path::PathBuf::from(&tmpdir);
|
||||
if tmpdir_path.is_absolute() && !tmpdir.is_empty() {
|
||||
roots.push(normalize_path(&tmpdir_path));
|
||||
}
|
||||
}
|
||||
let roots_text = if roots.len() == 1 {
|
||||
format!(" The writable root is `{}`.", roots[0])
|
||||
} else {
|
||||
format!(
|
||||
" The writable roots are {}.",
|
||||
roots
|
||||
.iter()
|
||||
.map(|root| format!("`{root}`"))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
)
|
||||
};
|
||||
let expected = format!(
|
||||
"<permissions instructions>{sandbox_text}{approval_text}{roots_text}</permissions instructions>"
|
||||
);
|
||||
let expected = DeveloperInstructions::from_policy(
|
||||
&sandbox_policy,
|
||||
AskForApproval::OnRequest,
|
||||
&Policy::empty(),
|
||||
false,
|
||||
test.config.cwd.as_path(),
|
||||
)
|
||||
.into_text();
|
||||
// Normalize line endings to handle Windows vs Unix differences
|
||||
let normalize_line_endings = |s: &str| s.replace("\r\n", "\n");
|
||||
let expected_normalized = normalize_line_endings(&expected);
|
||||
|
||||
Reference in New Issue
Block a user