mirror of
https://github.com/openai/codex.git
synced 2026-04-24 14:45:27 +00:00
remove sandbox denied swallowing code for being bad
This commit is contained in:
@@ -1869,20 +1869,10 @@ async fn handle_sandbox_error(
|
||||
// include additional metadata on the command to indicate whether non-zero
|
||||
// exit codes merit a retry.
|
||||
|
||||
// For now, we categorically ask the user to retry without sandbox.
|
||||
//
|
||||
// The raw error for a sandbox denial includes full stdout/stderr which can be very long.
|
||||
// Emit a compressed background event to keep the transcript readable.
|
||||
match &error {
|
||||
SandboxErr::Denied(exit_code, stdout, stderr) => {
|
||||
let summary = summarize_sandbox_denied_streams(*exit_code, stdout, stderr);
|
||||
sess.notify_background_event(&sub_id, summary).await;
|
||||
}
|
||||
_ => {
|
||||
sess.notify_background_event(&sub_id, format!("Execution failed: {error}"))
|
||||
.await;
|
||||
}
|
||||
}
|
||||
// For now, we categorically ask the user to retry without sandbox and
|
||||
// emit the raw error as a background event.
|
||||
sess.notify_background_event(&sub_id, format!("Execution failed: {error}"))
|
||||
.await;
|
||||
|
||||
let rx_approve = sess
|
||||
.request_command_approval(
|
||||
@@ -1975,78 +1965,6 @@ async fn handle_sandbox_error(
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a compact, human-friendly summary for sandbox-denied executions.
|
||||
///
|
||||
/// This avoids dumping potentially thousands of characters of stdout/stderr in
|
||||
/// the background event stream by:
|
||||
/// - limiting the number of lines shown per stream
|
||||
/// - collapsing consecutive duplicate lines into a single line with a repeat count
|
||||
/// - truncating overly long lines
|
||||
fn summarize_sandbox_denied_streams(exit_code: i32, stdout: &str, stderr: &str) -> String {
|
||||
const MAX_LINES_PER_STREAM: usize = 8;
|
||||
const MAX_LINE_LEN: usize = 160;
|
||||
|
||||
fn summarize_stream(label: &str, s: &str) -> String {
|
||||
if s.trim().is_empty() {
|
||||
return format!("{label}: <empty>");
|
||||
}
|
||||
|
||||
let total_lines = s.lines().count();
|
||||
let mut lines = Vec::new();
|
||||
let mut iter = s.lines().peekable();
|
||||
let mut consumed_lines = 0usize;
|
||||
while lines.len() < MAX_LINES_PER_STREAM {
|
||||
let line = match iter.next() {
|
||||
Some(l) => l,
|
||||
None => break,
|
||||
};
|
||||
// Count consecutive duplicates so we can collapse noisy spam.
|
||||
let mut repeat = 1usize;
|
||||
while let Some(&next) = iter.peek() {
|
||||
if next == line {
|
||||
repeat += 1;
|
||||
iter.next();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
consumed_lines += repeat;
|
||||
|
||||
let mut display = if line.len() > MAX_LINE_LEN {
|
||||
// Truncate long lines to keep the summary compact.
|
||||
let mut truncated = line.chars().take(MAX_LINE_LEN).collect::<String>();
|
||||
truncated.push('…');
|
||||
truncated
|
||||
} else {
|
||||
line.to_string()
|
||||
};
|
||||
if repeat > 1 {
|
||||
display.push_str(&format!(" (repeated {repeat} times)"));
|
||||
}
|
||||
lines.push(display);
|
||||
}
|
||||
|
||||
let omitted = total_lines.saturating_sub(consumed_lines);
|
||||
if omitted > 0 {
|
||||
lines.push(format!("… +{omitted} more lines omitted"));
|
||||
}
|
||||
format!("{label}:\n{}", lines.join("\n"))
|
||||
}
|
||||
|
||||
// Prefer stderr as it usually contains the failure context.
|
||||
let mut parts = Vec::with_capacity(3);
|
||||
parts.push(format!(
|
||||
"Execution failed in sandbox: exit code {exit_code}"
|
||||
));
|
||||
if !stderr.is_empty() {
|
||||
parts.push(summarize_stream("stderr", stderr));
|
||||
}
|
||||
if !stdout.is_empty() {
|
||||
parts.push(summarize_stream("stdout", stdout));
|
||||
}
|
||||
parts.join("\n")
|
||||
}
|
||||
|
||||
/// Exec output is a pre-serialized JSON payload
|
||||
fn format_exec_output(output: &str, exit_code: i32, duration: Duration) -> String {
|
||||
#[derive(Serialize)]
|
||||
|
||||
Reference in New Issue
Block a user