From 78e7825a47675b2c0dd6261ef4b3906cc1da26f1 Mon Sep 17 00:00:00 2001 From: jgershen-oai Date: Wed, 16 Sep 2026 22:07:10 +0000 Subject: [PATCH] Tighten request handling in Guardian approval tests (#46041) ## What changed - Wait for a request tagged with `x-openai-subagent: guardian` before triggering cancellation, disconnection, or timeout in network approval tests. - Read the last yielded parent request in the tool cancellation test, with an explicit error if no request was captured. - Disable WebSockets in the issuing-step permissions test to use its HTTP mock server. GitOrigin-RevId: 35c021e3931ff4a66ca3970f8e39e1d20257be88 --- .../core/src/session/tests/guardian_tests.rs | 1 + .../suite/guardian_review_cancellation.rs | 3 ++- codex-rs/core/tests/suite/network_approval.rs | 21 ++++++++++++++++--- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/codex-rs/core/src/session/tests/guardian_tests.rs b/codex-rs/core/src/session/tests/guardian_tests.rs index 371a1ba0db..e559848910 100644 --- a/codex-rs/core/src/session/tests/guardian_tests.rs +++ b/codex-rs/core/src/session/tests/guardian_tests.rs @@ -332,6 +332,7 @@ async fn request_permissions_uses_issuing_step_policy_and_reviewer() { config.permissions.approval_policy = Constrained::allow_any(AskForApproval::Never); config.approvals_reviewer = ApprovalsReviewer::User; config.model_provider.base_url = Some(format!("{}/v1", server.uri())); + config.model_provider.supports_websockets = false; config .features .enable(Feature::GuardianApproval) diff --git a/codex-rs/core/tests/suite/guardian_review_cancellation.rs b/codex-rs/core/tests/suite/guardian_review_cancellation.rs index 323a627e36..aac131c6b7 100644 --- a/codex-rs/core/tests/suite/guardian_review_cancellation.rs +++ b/codex-rs/core/tests/suite/guardian_review_cancellation.rs @@ -178,7 +178,8 @@ async fn cancelling_tool_aborts_its_guardian_review(cancellation: Cancellation) }) .await; let output = yielded_parent - .single_request() + .last_request() + .context("missing yielded parent request")? .custom_tool_call_output("reviewed-tool"); let output = &output["output"]; let header = output diff --git a/codex-rs/core/tests/suite/network_approval.rs b/codex-rs/core/tests/suite/network_approval.rs index dce430e5b7..33f1e98e7a 100644 --- a/codex-rs/core/tests/suite/network_approval.rs +++ b/codex-rs/core/tests/suite/network_approval.rs @@ -398,7 +398,7 @@ async fn cancelled_guardian_network_review_fails_closed_without_rewriting_turn_s AskForApproval::OnRequest, ) .await?; - wait_for_response_request(&pending_guardian).await; + wait_for_guardian_request(&pending_guardian).await; test.codex.submit(Op::Interrupt).await?; let mut saw_turn_aborted = false; let mut saw_guardian_aborted = false; @@ -533,7 +533,7 @@ PY"# AskForApproval::OnRequest, ) .await?; - wait_for_response_request(&pending_guardian).await; + wait_for_guardian_request(&pending_guardian).await; wait_for_response_request(&parent_poll).await; fs::write(test.config.cwd.join("disconnect-now"), "close")?; wait_for_completion_without_network_prompt(&test).await; @@ -643,7 +643,7 @@ async fn timed_out_guardian_network_review_uses_timeout_outcome_without_user_fal AskForApproval::OnRequest, ) .await?; - wait_for_response_request(&pending_guardian).await; + wait_for_guardian_request(&pending_guardian).await; tokio::time::pause(); tokio::time::advance(Duration::from_secs(91)).await; tokio::time::resume(); @@ -3034,6 +3034,21 @@ async fn wait_for_completion_without_network_prompt(test: &TestCodex) { } } +async fn wait_for_guardian_request(responses: &ResponseMock) { + tokio::time::timeout(Duration::from_secs(10), async { + loop { + if responses.requests().iter().any(|request| { + request.body_json()["client_metadata"]["x-openai-subagent"] == "guardian" + }) { + return; + } + tokio::time::sleep(Duration::from_millis(10)).await; + } + }) + .await + .expect("timed out waiting for Guardian request"); +} + async fn wait_for_response_request(responses: &ResponseMock) { tokio::time::timeout(Duration::from_secs(10), async { loop {