Compare commits

...

8 Commits

Author SHA1 Message Date
jif-oai
3ad5474de5 nit fix 2026-03-16 15:57:44 +00:00
jif-oai
983e8f3d78 nit 2026-03-16 15:11:48 +00:00
jif-oai
0ea52bc958 Update role_tests.rs 2026-03-16 14:03:33 +00:00
jif-oai
4dc05e7c86 drop on windows 2026-03-16 13:38:30 +00:00
jif-oai
1e9e8a67c3 nit fix 2026-03-16 12:28:51 +00:00
jif-oai
80b00f0d2f Update explorer.toml 2026-03-16 10:56:51 +00:00
jif-oai
c76b76693b fix test 2026-03-16 10:20:02 +00:00
jif-oai
548bf124de feat: explorer read only 2026-03-16 10:16:40 +00:00
4 changed files with 20 additions and 18 deletions

View File

@@ -0,0 +1 @@
sandbox_mode = "read-only"

View File

@@ -5,6 +5,7 @@ use crate::config_loader::ConfigLayerStackOrdering;
use crate::plugins::PluginsManager;
use crate::skills::SkillsManager;
use codex_protocol::openai_models::ReasoningEffort;
use codex_protocol::protocol::SandboxPolicy;
use pretty_assertions::assert_eq;
use std::fs;
use std::path::PathBuf;
@@ -67,17 +68,27 @@ async fn apply_role_returns_error_for_unknown_role() {
}
#[tokio::test]
#[ignore = "No role requiring it for now"]
async fn apply_explorer_role_sets_model_and_adds_session_flags_layer() {
let (_home, mut config) = test_config_with_cli_overrides(Vec::new()).await;
#[cfg_attr(target_os = "windows", ignore)]
async fn apply_explorer_role_sets_read_only_config_and_adds_session_flags_layer() {
let (_home, mut config) = test_config_with_cli_overrides(vec![(
"sandbox_mode".to_string(),
TomlValue::String("workspace-write".to_string()),
)])
.await;
let before_layers = session_flags_layer_count(&config);
assert!(matches!(
config.permissions.sandbox_policy.get(),
SandboxPolicy::WorkspaceWrite { .. }
));
apply_role_to_config(&mut config, Some("explorer"))
.await
.expect("explorer role should apply");
assert_eq!(config.model.as_deref(), Some("gpt-5.1-codex-mini"));
assert_eq!(config.model_reasoning_effort, Some(ReasoningEffort::Medium));
assert_eq!(
config.permissions.sandbox_policy.get(),
&SandboxPolicy::new_read_only_policy()
);
assert_eq!(session_flags_layer_count(&config), before_layers + 1);
}
@@ -673,6 +684,9 @@ fn spawn_tool_spec_marks_role_locked_reasoning_effort_only() {
#[test]
fn built_in_config_file_contents_resolves_explorer_only() {
let explorer =
built_in::config_file_contents(Path::new("explorer.toml")).expect("explorer config");
assert!(explorer.contains("sandbox_mode = \"read-only\""));
assert_eq!(
built_in::config_file_contents(Path::new("missing.toml")),
None

View File

@@ -300,13 +300,6 @@ fn apply_spawn_agent_runtime_overrides(
config.permissions.shell_environment_policy = turn.shell_environment_policy.clone();
config.codex_linux_sandbox_exe = turn.codex_linux_sandbox_exe.clone();
config.cwd = turn.cwd.clone();
config
.permissions
.sandbox_policy
.set(turn.sandbox_policy.get().clone())
.map_err(|err| {
FunctionCallError::RespondToModel(format!("sandbox_policy is invalid: {err}"))
})?;
config.permissions.file_system_sandbox_policy = turn.file_system_sandbox_policy.clone();
config.permissions.network_sandbox_policy = turn.network_sandbox_policy;
Ok(())

View File

@@ -282,7 +282,6 @@ async fn spawn_agent_reapplies_runtime_sandbox_after_role_config() {
"spawn_agent",
function_payload(json!({
"message": "await this command",
"agent_type": "explorer"
})),
);
let output = SpawnAgentHandler
@@ -1069,11 +1068,6 @@ async fn build_agent_spawn_config_uses_turn_context_values() {
.approval_policy
.set(AskForApproval::OnRequest)
.expect("approval policy set");
expected
.permissions
.sandbox_policy
.set(turn.sandbox_policy.get().clone())
.expect("sandbox policy set");
expected.permissions.file_system_sandbox_policy = file_system_sandbox_policy;
expected.permissions.network_sandbox_policy = network_sandbox_policy;
assert_eq!(config, expected);