Skip to content

Commit 60dffde

Browse files
committed
Merge remote-tracking branch 'upstream/main'
2 parents d9f5584 + 54dbbb8 commit 60dffde

18 files changed

Lines changed: 577 additions & 124 deletions

codex-rs/Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

codex-rs/core/src/codex_tests.rs

Lines changed: 20 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ use crate::state::TaskKind;
4343
use crate::tasks::SessionTask;
4444
use crate::tasks::SessionTaskContext;
4545
use crate::tools::ToolRouter;
46-
use crate::tools::context::FunctionToolOutput;
4746
use crate::tools::context::ToolInvocation;
4847
use crate::tools::context::ToolPayload;
4948
use crate::tools::handlers::ShellHandler;
@@ -120,12 +119,6 @@ use std::time::Duration as StdDuration;
120119
#[path = "codex_tests_guardian.rs"]
121120
mod guardian_tests;
122121

123-
use codex_protocol::models::function_call_output_content_items_to_text;
124-
125-
fn expect_text_tool_output(output: &FunctionToolOutput) -> String {
126-
function_call_output_content_items_to_text(&output.body).unwrap_or_default()
127-
}
128-
129122
struct InstructionsTestCase {
130123
slug: &'static str,
131124
expects_apply_patch_instructions: bool,
@@ -5348,7 +5341,9 @@ async fn sample_rollout(
53485341
#[tokio::test]
53495342
async fn rejects_escalated_permissions_when_policy_not_on_request() {
53505343
use crate::exec::ExecParams;
5344+
use crate::exec_policy::ExecApprovalRequest;
53515345
use crate::sandboxing::SandboxPermissions;
5346+
use crate::tools::sandboxing::ExecApprovalRequirement;
53525347
use crate::turn_diff_tracker::TurnDiffTracker;
53535348
use codex_protocol::protocol::AskForApproval;
53545349
use codex_protocol::protocol::SandboxPolicy;
@@ -5394,23 +5389,6 @@ async fn rejects_escalated_permissions_when_policy_not_on_request() {
53945389
arg0: None,
53955390
};
53965391

5397-
let params2 = ExecParams {
5398-
sandbox_permissions: SandboxPermissions::UseDefault,
5399-
command: params.command.clone(),
5400-
cwd: params.cwd.clone(),
5401-
expiration: timeout_ms.into(),
5402-
capture_policy: ExecCapturePolicy::ShellTool,
5403-
env: HashMap::new(),
5404-
network: None,
5405-
windows_sandbox_level: turn_context.windows_sandbox_level,
5406-
windows_sandbox_private_desktop: turn_context
5407-
.config
5408-
.permissions
5409-
.windows_sandbox_private_desktop,
5410-
justification: params.justification.clone(),
5411-
arg0: None,
5412-
};
5413-
54145392
let turn_diff_tracker = Arc::new(tokio::sync::Mutex::new(TurnDiffTracker::new()));
54155393

54165394
let tool_name = "shell";
@@ -5448,9 +5426,11 @@ async fn rejects_escalated_permissions_when_policy_not_on_request() {
54485426
);
54495427

54505428
pretty_assertions::assert_eq!(output, expected);
5429+
pretty_assertions::assert_eq!(session.granted_turn_permissions().await, None);
54515430

5452-
// Now retry the same command WITHOUT escalated permissions; should succeed.
5453-
// Force DangerFullAccess to avoid platform sandbox dependencies in tests.
5431+
// The rejection should not poison the non-escalated path for the same
5432+
// command. Force DangerFullAccess so this check stays focused on approval
5433+
// policy rather than platform-specific sandbox behavior.
54545434
let turn_context_mut = Arc::get_mut(&mut turn_context).expect("unique turn context Arc");
54555435
turn_context_mut
54565436
.sandbox_policy
@@ -5461,45 +5441,22 @@ async fn rejects_escalated_permissions_when_policy_not_on_request() {
54615441
turn_context_mut.network_sandbox_policy =
54625442
NetworkSandboxPolicy::from(turn_context_mut.sandbox_policy.get());
54635443

5464-
let resp2 = handler
5465-
.handle(ToolInvocation {
5466-
session: Arc::clone(&session),
5467-
turn: Arc::clone(&turn_context),
5468-
tracker: Arc::clone(&turn_diff_tracker),
5469-
call_id: "test-call-2".to_string(),
5470-
tool_name: tool_name.to_string(),
5471-
tool_namespace: None,
5472-
payload: ToolPayload::Function {
5473-
arguments: serde_json::json!({
5474-
"command": params2.command.clone(),
5475-
"workdir": Some(turn_context.cwd.to_string_lossy().to_string()),
5476-
"timeout_ms": params2.expiration.timeout_ms(),
5477-
"sandbox_permissions": params2.sandbox_permissions,
5478-
"justification": params2.justification.clone(),
5479-
})
5480-
.to_string(),
5481-
},
5444+
let exec_approval_requirement = session
5445+
.services
5446+
.exec_policy
5447+
.create_exec_approval_requirement_for_command(ExecApprovalRequest {
5448+
command: &params.command,
5449+
approval_policy: turn_context.approval_policy.value(),
5450+
sandbox_policy: turn_context.sandbox_policy.get(),
5451+
file_system_sandbox_policy: &turn_context.file_system_sandbox_policy,
5452+
sandbox_permissions: SandboxPermissions::UseDefault,
5453+
prefix_rule: None,
54825454
})
54835455
.await;
5484-
5485-
let output = expect_text_tool_output(&resp2.expect("expected Ok result"));
5486-
5487-
#[derive(Deserialize, PartialEq, Eq, Debug)]
5488-
struct ResponseExecMetadata {
5489-
exit_code: i32,
5490-
}
5491-
5492-
#[derive(Deserialize)]
5493-
struct ResponseExecOutput {
5494-
output: String,
5495-
metadata: ResponseExecMetadata,
5496-
}
5497-
5498-
let exec_output: ResponseExecOutput =
5499-
serde_json::from_str(&output).expect("valid exec output json");
5500-
5501-
pretty_assertions::assert_eq!(exec_output.metadata, ResponseExecMetadata { exit_code: 0 });
5502-
assert!(exec_output.output.contains("hi"));
5456+
assert!(matches!(
5457+
exec_approval_requirement,
5458+
ExecApprovalRequirement::Skip { .. }
5459+
));
55035460
}
55045461
#[tokio::test]
55055462
async fn unified_exec_rejects_escalated_permissions_when_policy_not_on_request() {

codex-rs/core/tests/responses_headers.rs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,14 @@ use pretty_assertions::assert_eq;
2323
use tempfile::TempDir;
2424
use wiremock::matchers::header;
2525

26+
fn normalize_git_remote_url(url: &str) -> String {
27+
let normalized = url.trim().trim_end_matches('/');
28+
normalized
29+
.strip_suffix(".git")
30+
.unwrap_or(normalized)
31+
.to_string()
32+
}
33+
2634
#[tokio::test]
2735
async fn responses_stream_includes_subagent_header_on_review() {
2836
core_test_support::skip_if_no_network!();
@@ -540,13 +548,15 @@ async fn responses_stream_includes_turn_metadata_header_for_git_workspace_e2e()
540548
.and_then(serde_json::Value::as_str),
541549
Some(expected_head.as_str())
542550
);
551+
let actual_origin = workspace
552+
.get("associated_remote_urls")
553+
.and_then(serde_json::Value::as_object)
554+
.and_then(|remotes| remotes.get("origin"))
555+
.and_then(serde_json::Value::as_str)
556+
.expect("origin remote should be present");
543557
assert_eq!(
544-
workspace
545-
.get("associated_remote_urls")
546-
.and_then(serde_json::Value::as_object)
547-
.and_then(|remotes| remotes.get("origin"))
548-
.and_then(serde_json::Value::as_str),
549-
Some(expected_origin.as_str())
558+
normalize_git_remote_url(actual_origin),
559+
normalize_git_remote_url(&expected_origin)
550560
);
551561
assert_eq!(
552562
workspace

codex-rs/core/tests/suite/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ mod request_permissions;
122122
#[cfg(not(target_os = "windows"))]
123123
mod request_permissions_tool;
124124
mod request_user_input;
125+
mod responses_api_proxy_headers;
125126
mod resume;
126127
mod resume_warning;
127128
mod review;

0 commit comments

Comments
 (0)