mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
chore(core) rm AskForApproval::OnFailure (#28418)
## Summary Deletes the OnFailure variant of the `AskForApproval` enum. This option has been deprecated since #11631. ## Testing - [x] Tests pass
This commit is contained in:
committed by
GitHub
Unverified
parent
e476fc16ce
commit
2cf2a6a844
@@ -1085,40 +1085,6 @@ fn scenarios() -> Vec<ScenarioSpec> {
|
||||
output_contains: "rejected by user",
|
||||
},
|
||||
},
|
||||
ScenarioSpec {
|
||||
name: "danger_full_access_on_failure_allows_outside_write",
|
||||
approval_policy: OnFailure,
|
||||
sandbox_policy: SandboxPolicy::DangerFullAccess,
|
||||
action: ActionKind::WriteFile {
|
||||
target: TargetPath::OutsideWorkspace("dfa_on_failure.txt"),
|
||||
content: "danger-on-failure",
|
||||
},
|
||||
sandbox_permissions: SandboxPermissions::UseDefault,
|
||||
features: vec![],
|
||||
model_override: Some("gpt-5.2"),
|
||||
outcome: Outcome::Auto,
|
||||
expectation: Expectation::FileCreated {
|
||||
target: TargetPath::OutsideWorkspace("dfa_on_failure.txt"),
|
||||
content: "danger-on-failure",
|
||||
},
|
||||
},
|
||||
ScenarioSpec {
|
||||
name: "danger_full_access_on_failure_allows_outside_write_gpt_5_1_no_exit",
|
||||
approval_policy: OnFailure,
|
||||
sandbox_policy: SandboxPolicy::DangerFullAccess,
|
||||
action: ActionKind::WriteFile {
|
||||
target: TargetPath::OutsideWorkspace("dfa_on_failure_5_1.txt"),
|
||||
content: "danger-on-failure",
|
||||
},
|
||||
sandbox_permissions: SandboxPermissions::UseDefault,
|
||||
features: vec![],
|
||||
model_override: Some("gpt-5.4"),
|
||||
outcome: Outcome::Auto,
|
||||
expectation: Expectation::FileCreatedNoExitCode {
|
||||
target: TargetPath::OutsideWorkspace("dfa_on_failure_5_1.txt"),
|
||||
content: "danger-on-failure",
|
||||
},
|
||||
},
|
||||
ScenarioSpec {
|
||||
name: "danger_full_access_unless_trusted_requests_approval",
|
||||
approval_policy: UnlessTrusted,
|
||||
@@ -1297,48 +1263,6 @@ fn scenarios() -> Vec<ScenarioSpec> {
|
||||
message_contains: &["exec command rejected by user"],
|
||||
},
|
||||
},
|
||||
#[cfg(not(target_os = "linux"))] // TODO (pakrym): figure out why linux behaves differently
|
||||
ScenarioSpec {
|
||||
name: "read_only_on_failure_escalates_after_sandbox_error",
|
||||
approval_policy: OnFailure,
|
||||
sandbox_policy: SandboxPolicy::new_read_only_policy(),
|
||||
action: ActionKind::WriteFile {
|
||||
target: TargetPath::Workspace("ro_on_failure.txt"),
|
||||
content: "read-only-on-failure",
|
||||
},
|
||||
sandbox_permissions: SandboxPermissions::UseDefault,
|
||||
features: vec![],
|
||||
model_override: Some("gpt-5.2"),
|
||||
outcome: Outcome::ExecApproval {
|
||||
decision: ReviewDecision::Approved,
|
||||
expected_reason: Some("command failed; retry without sandbox?"),
|
||||
},
|
||||
expectation: Expectation::FileCreated {
|
||||
target: TargetPath::Workspace("ro_on_failure.txt"),
|
||||
content: "read-only-on-failure",
|
||||
},
|
||||
},
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
ScenarioSpec {
|
||||
name: "read_only_on_failure_escalates_after_sandbox_error_gpt_5_1_no_exit",
|
||||
approval_policy: OnFailure,
|
||||
sandbox_policy: SandboxPolicy::new_read_only_policy(),
|
||||
action: ActionKind::WriteFile {
|
||||
target: TargetPath::Workspace("ro_on_failure_5_1.txt"),
|
||||
content: "read-only-on-failure",
|
||||
},
|
||||
sandbox_permissions: SandboxPermissions::UseDefault,
|
||||
features: vec![],
|
||||
model_override: Some("gpt-5.4"),
|
||||
outcome: Outcome::ExecApproval {
|
||||
decision: ReviewDecision::Approved,
|
||||
expected_reason: Some("command failed; retry without sandbox?"),
|
||||
},
|
||||
expectation: Expectation::FileCreatedNoExitCode {
|
||||
target: TargetPath::Workspace("ro_on_failure_5_1.txt"),
|
||||
content: "read-only-on-failure",
|
||||
},
|
||||
},
|
||||
ScenarioSpec {
|
||||
name: "read_only_on_request_network_escalates_when_approved",
|
||||
approval_policy: OnRequest,
|
||||
@@ -1676,27 +1600,6 @@ fn scenarios() -> Vec<ScenarioSpec> {
|
||||
body_contains: "workspace-network-ok",
|
||||
},
|
||||
},
|
||||
#[cfg(not(target_os = "linux"))] // TODO (pakrym): figure out why linux behaves differently
|
||||
ScenarioSpec {
|
||||
name: "workspace_write_on_failure_escalates_outside_workspace",
|
||||
approval_policy: OnFailure,
|
||||
sandbox_policy: workspace_write(false),
|
||||
action: ActionKind::WriteFile {
|
||||
target: TargetPath::OutsideWorkspace("ww_on_failure.txt"),
|
||||
content: "workspace-on-failure",
|
||||
},
|
||||
sandbox_permissions: SandboxPermissions::UseDefault,
|
||||
features: vec![],
|
||||
model_override: Some("gpt-5.2"),
|
||||
outcome: Outcome::ExecApproval {
|
||||
decision: ReviewDecision::Approved,
|
||||
expected_reason: Some("command failed; retry without sandbox?"),
|
||||
},
|
||||
expectation: Expectation::FileCreated {
|
||||
target: TargetPath::OutsideWorkspace("ww_on_failure.txt"),
|
||||
content: "workspace-on-failure",
|
||||
},
|
||||
},
|
||||
ScenarioSpec {
|
||||
name: "workspace_write_unless_trusted_requires_approval_outside_workspace",
|
||||
approval_policy: UnlessTrusted,
|
||||
@@ -2982,7 +2885,7 @@ mode = "limited"
|
||||
allow_local_binding = true
|
||||
"#,
|
||||
)?;
|
||||
let approval_policy = AskForApproval::OnFailure;
|
||||
let approval_policy = AskForApproval::OnRequest;
|
||||
let sandbox_policy = SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: vec![],
|
||||
network_access: true,
|
||||
@@ -3467,7 +3370,7 @@ mode = "limited"
|
||||
allow_local_binding = true
|
||||
"#,
|
||||
)?;
|
||||
let approval_policy = AskForApproval::OnFailure;
|
||||
let approval_policy = AskForApproval::OnRequest;
|
||||
let turn_sandbox_policy = SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: vec![],
|
||||
network_access: true,
|
||||
|
||||
@@ -2200,7 +2200,7 @@ allow_local_binding = true
|
||||
)
|
||||
.await;
|
||||
|
||||
let approval_policy = AskForApproval::OnFailure;
|
||||
let approval_policy = AskForApproval::OnRequest;
|
||||
let permission_profile = network_workspace_write_profile();
|
||||
let permission_profile_for_config = permission_profile.clone();
|
||||
let test = test_codex()
|
||||
@@ -2283,71 +2283,6 @@ allow_local_binding = true
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
#[tokio::test]
|
||||
async fn permission_request_hook_sees_retry_context_after_sandbox_denial() -> Result<()> {
|
||||
skip_if_no_network!(Ok(()));
|
||||
|
||||
let server = start_mock_server().await;
|
||||
let call_id = "permissionrequest-retry-shell-command";
|
||||
let marker = "permissionrequest_retry_marker.txt";
|
||||
let command = format!("printf retry > {marker}");
|
||||
let args = serde_json::json!({ "command": command });
|
||||
let responses = mount_sse_sequence(
|
||||
&server,
|
||||
vec![
|
||||
sse(vec![
|
||||
ev_response_created("resp-1"),
|
||||
core_test_support::responses::ev_function_call(
|
||||
call_id,
|
||||
"shell_command",
|
||||
&serde_json::to_string(&args)?,
|
||||
),
|
||||
ev_completed("resp-1"),
|
||||
]),
|
||||
sse(vec![
|
||||
ev_response_created("resp-2"),
|
||||
ev_assistant_message("msg-1", "permission request hook allowed retry"),
|
||||
ev_completed("resp-2"),
|
||||
]),
|
||||
],
|
||||
)
|
||||
.await;
|
||||
|
||||
let mut builder = test_codex()
|
||||
.with_pre_build_hook(|home| {
|
||||
install_allow_permission_request_hook(home)
|
||||
.expect("failed to write permission request hook test fixture");
|
||||
})
|
||||
.with_config(trust_discovered_hooks);
|
||||
let test = builder.build(&server).await?;
|
||||
let marker_path = test.workspace_path(marker);
|
||||
let _ = fs::remove_file(&marker_path);
|
||||
|
||||
test.submit_turn_with_approval_and_permission_profile(
|
||||
"retry the shell command after sandbox denial",
|
||||
AskForApproval::OnFailure,
|
||||
PermissionProfile::read_only(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
let requests = responses.requests();
|
||||
assert_eq!(requests.len(), 2);
|
||||
requests[1].function_call_output(call_id);
|
||||
assert_eq!(
|
||||
fs::read_to_string(&marker_path).context("read retry marker")?,
|
||||
"retry"
|
||||
);
|
||||
|
||||
assert_single_permission_request_hook_input(
|
||||
test.codex_home_path(),
|
||||
&command,
|
||||
/*description*/ None,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn pre_tool_use_blocks_shell_command_before_execution() -> Result<()> {
|
||||
skip_if_no_network!(Ok(()));
|
||||
|
||||
@@ -165,7 +165,7 @@ mode = "limited"
|
||||
allow_local_binding = true
|
||||
"#,
|
||||
)?;
|
||||
let approval_policy = AskForApproval::OnFailure;
|
||||
let approval_policy = AskForApproval::OnRequest;
|
||||
let permission_profile = PermissionProfile::workspace_write_with(
|
||||
&[],
|
||||
NetworkSandboxPolicy::Enabled,
|
||||
@@ -263,7 +263,7 @@ async fn submit_managed_network_turn(
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
environments: Some(turn_environment_selections),
|
||||
approval_policy: Some(AskForApproval::OnFailure),
|
||||
approval_policy: Some(AskForApproval::OnRequest),
|
||||
approvals_reviewer: Some(ApprovalsReviewer::User),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
permission_profile,
|
||||
|
||||
@@ -315,151 +315,6 @@ async fn explicit_remote_shell_runs_in_remote_cwd() -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn remote_sandbox_denial_requests_approval_and_retries() -> Result<()> {
|
||||
skip_if_no_network!(Ok(()));
|
||||
skip_if_wine_exec!(Ok(()), "requires the Docker-backed POSIX executor");
|
||||
let Some(_remote_env) = get_remote_test_env() else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
const CALL_ID: &str = "remote-sandbox-denial";
|
||||
const CONTENTS: &str = "remote sandbox retry succeeded";
|
||||
|
||||
let server = start_mock_server().await;
|
||||
let test = unified_exec_test(&server).await?;
|
||||
let nonce = SystemTime::now().duration_since(UNIX_EPOCH)?.as_millis();
|
||||
let remote_cwd = PathBuf::from(format!("/tmp/codex-remote-denial-cwd-{nonce}")).abs();
|
||||
let target_path = PathBuf::from(format!("/tmp/codex-remote-denial-target-{nonce}")).abs();
|
||||
let remote_cwd_uri = PathUri::from_host_native_path(&remote_cwd)?;
|
||||
let target_uri = PathUri::from_host_native_path(&target_path)?;
|
||||
test.fs()
|
||||
.create_directory(
|
||||
&remote_cwd_uri,
|
||||
CreateDirectoryOptions { recursive: true },
|
||||
/*sandbox*/ None,
|
||||
)
|
||||
.await?;
|
||||
test.fs()
|
||||
.remove(
|
||||
&target_uri,
|
||||
RemoveOptions {
|
||||
recursive: false,
|
||||
force: true,
|
||||
},
|
||||
/*sandbox*/ None,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let command = format!("printf {CONTENTS:?} > {target_path:?} && cat {target_path:?}");
|
||||
let response_mock = mount_sse_sequence(
|
||||
&server,
|
||||
vec![
|
||||
sse(vec![
|
||||
ev_response_created("resp-remote-denial-1"),
|
||||
ev_function_call(
|
||||
CALL_ID,
|
||||
"exec_command",
|
||||
&json!({
|
||||
"shell": "/bin/sh",
|
||||
"cmd": command,
|
||||
"login": false,
|
||||
"yield_time_ms": 5_000,
|
||||
"environment_id": REMOTE_ENVIRONMENT_ID,
|
||||
})
|
||||
.to_string(),
|
||||
),
|
||||
ev_completed("resp-remote-denial-1"),
|
||||
]),
|
||||
sse(vec![
|
||||
ev_response_created("resp-remote-denial-2"),
|
||||
ev_assistant_message("msg-remote-denial", "done"),
|
||||
ev_completed("resp-remote-denial-2"),
|
||||
]),
|
||||
],
|
||||
)
|
||||
.await;
|
||||
|
||||
submit_turn_with_approval_and_environments(
|
||||
&test,
|
||||
"retry a sandbox-denied command in the remote environment",
|
||||
vec![TurnEnvironmentSelection {
|
||||
environment_id: REMOTE_ENVIRONMENT_ID.to_string(),
|
||||
cwd: PathUri::from_abs_path(&remote_cwd),
|
||||
}],
|
||||
AskForApproval::OnFailure,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let event = wait_for_event(&test.codex, |event| {
|
||||
matches!(
|
||||
event,
|
||||
EventMsg::ExecApprovalRequest(_) | EventMsg::TurnComplete(_)
|
||||
)
|
||||
})
|
||||
.await;
|
||||
let EventMsg::ExecApprovalRequest(approval) = event else {
|
||||
panic!("expected remote sandbox approval before completion: {event:?}");
|
||||
};
|
||||
assert_eq!(approval.call_id, CALL_ID);
|
||||
assert_eq!(
|
||||
approval.environment_id.as_deref(),
|
||||
Some(REMOTE_ENVIRONMENT_ID)
|
||||
);
|
||||
assert_eq!(
|
||||
approval.reason.as_deref(),
|
||||
Some("command failed; retry without sandbox?")
|
||||
);
|
||||
|
||||
test.codex
|
||||
.submit(Op::ExecApproval {
|
||||
id: approval.effective_approval_id(),
|
||||
turn_id: None,
|
||||
decision: ReviewDecision::Approved,
|
||||
})
|
||||
.await?;
|
||||
wait_for_event(&test.codex, |event| {
|
||||
matches!(event, EventMsg::TurnComplete(_))
|
||||
})
|
||||
.await;
|
||||
|
||||
assert!(
|
||||
response_mock
|
||||
.function_call_output_text(CALL_ID)
|
||||
.is_some_and(|output| output.contains(CONTENTS)),
|
||||
"approved retry should return the remote command output"
|
||||
);
|
||||
assert_eq!(
|
||||
test.fs()
|
||||
.read_file_text(&target_uri, /*sandbox*/ None)
|
||||
.await?,
|
||||
CONTENTS
|
||||
);
|
||||
|
||||
test.fs()
|
||||
.remove(
|
||||
&target_uri,
|
||||
RemoveOptions {
|
||||
recursive: false,
|
||||
force: true,
|
||||
},
|
||||
/*sandbox*/ None,
|
||||
)
|
||||
.await?;
|
||||
test.fs()
|
||||
.remove(
|
||||
&remote_cwd_uri,
|
||||
RemoveOptions {
|
||||
recursive: true,
|
||||
force: true,
|
||||
},
|
||||
/*sandbox*/ None,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn deferred_executor_does_not_duplicate_initial_environment_context() -> Result<()> {
|
||||
let server = start_mock_server().await;
|
||||
|
||||
Reference in New Issue
Block a user