mirror of
https://github.com/openai/codex.git
synced 2026-11-02 19:43:24 +00:00
## What changed Capture the ID from `response.created` and pass it as `parent_response_id` in Guardian review and classifier request metadata. Clear the current response ID before sampling retries so tool reviews cannot inherit a failed response's ID. Request Guardian credits with `guardian_credits_requested` on eligible parent requests. Remove the ticket protocol, transport attachment, and ticket-specific body redaction. Keep ordinary app-server client `parent_response_id` values inside `x-codex-turn-metadata` rather than promoting them to Guardian request metadata. ## Testing Update coverage for HTTP fallback, WebSocket review reuse, missing response IDs, classifier transport retries, and code-mode yield/resume attribution. Extend app-server tests to verify client metadata placement over HTTP and WebSocket. GitOrigin-RevId: c1665e56382ecec8d260fc2ca0ecd5e20b0b2391
115 lines
3.8 KiB
Rust
115 lines
3.8 KiB
Rust
use super::*;
|
|
use serde_json::json;
|
|
use std::io::Write;
|
|
use std::sync::Arc;
|
|
use std::sync::Mutex;
|
|
use std::time::Duration;
|
|
use tracing_subscriber::Layer;
|
|
use tracing_subscriber::layer::SubscriberExt;
|
|
|
|
#[tokio::test]
|
|
async fn enabled_request_logging_emits_transport_url_and_body() {
|
|
let logs = capture_transport_logs(HttpClient::new(test_reqwest_client())).await;
|
|
|
|
assert!(logs.contains("log capture sentinel"));
|
|
assert!(logs.contains("url-secret"));
|
|
assert!(logs.contains("body-secret"));
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn disabled_request_logging_suppresses_transport_url_and_body() {
|
|
let logs = capture_transport_logs(HttpClient::new_without_request_logging(
|
|
test_reqwest_client(),
|
|
))
|
|
.await;
|
|
|
|
assert!(logs.contains("log capture sentinel"));
|
|
assert!(!logs.contains("url-secret"));
|
|
assert!(!logs.contains("body-secret"));
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn connection_failures_are_classified_without_exposing_request_urls() {
|
|
let unavailable_server =
|
|
std::net::TcpListener::bind(("127.0.0.1", 0)).expect("server port should bind");
|
|
let server_addr = unavailable_server
|
|
.local_addr()
|
|
.expect("server listener should have an address");
|
|
drop(unavailable_server);
|
|
let transport = ReqwestTransport::from_http_client(HttpClient::new(test_reqwest_client()));
|
|
let request = Request::new(
|
|
Method::POST,
|
|
format!("http://{server_addr}/responses?token=url-secret"),
|
|
);
|
|
|
|
let error = match transport.stream(request).await {
|
|
Err(TransportError::Connection(error)) => error,
|
|
Err(error) => panic!("expected a connection failure, got {error}"),
|
|
Ok(_) => panic!("an unavailable server should not return a response"),
|
|
};
|
|
assert!(!error.to_string().contains("url-secret"));
|
|
}
|
|
|
|
fn test_reqwest_client() -> reqwest::Client {
|
|
reqwest::Client::builder()
|
|
.no_proxy()
|
|
.build()
|
|
.expect("HTTP client should build")
|
|
}
|
|
|
|
async fn capture_transport_logs(client: HttpClient) -> String {
|
|
let unavailable_server =
|
|
std::net::TcpListener::bind(("127.0.0.1", 0)).expect("server port should bind");
|
|
let server_addr = unavailable_server
|
|
.local_addr()
|
|
.expect("server listener should have an address");
|
|
drop(unavailable_server);
|
|
let transport = ReqwestTransport::from_http_client(client);
|
|
let log_buffer = Arc::new(Mutex::new(Vec::new()));
|
|
let writer_buffer = Arc::clone(&log_buffer);
|
|
let subscriber = tracing_subscriber::registry().with(
|
|
tracing_subscriber::fmt::layer()
|
|
.with_ansi(false)
|
|
.with_writer(move || TestLogWriter(Arc::clone(&writer_buffer)))
|
|
.with_filter(
|
|
tracing_subscriber::filter::Targets::new()
|
|
.with_target("codex_http_client::transport", tracing::Level::TRACE),
|
|
),
|
|
);
|
|
let _guard = tracing::subscriber::set_default(subscriber);
|
|
tracing::trace!(target: "codex_http_client::transport", "log capture sentinel");
|
|
let mut request = Request::new(
|
|
Method::POST,
|
|
format!("http://{server_addr}/request?token=url-secret"),
|
|
)
|
|
.with_json(&json!({"token": "body-secret"}));
|
|
request.timeout = Some(Duration::from_secs(1));
|
|
|
|
let _ = transport.execute(request).await;
|
|
|
|
String::from_utf8(
|
|
log_buffer
|
|
.lock()
|
|
.expect("log buffer should not be poisoned")
|
|
.clone(),
|
|
)
|
|
.expect("captured logs should be UTF-8")
|
|
}
|
|
|
|
#[derive(Clone)]
|
|
struct TestLogWriter(Arc<Mutex<Vec<u8>>>);
|
|
|
|
impl Write for TestLogWriter {
|
|
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
|
|
self.0
|
|
.lock()
|
|
.map_err(|_| std::io::Error::other("log buffer should not be poisoned"))?
|
|
.extend_from_slice(buf);
|
|
Ok(buf.len())
|
|
}
|
|
|
|
fn flush(&mut self) -> std::io::Result<()> {
|
|
Ok(())
|
|
}
|
|
}
|