mirror of
https://github.com/openai/codex.git
synced 2026-10-28 18:58:46 +00:00
## Why Reloading an evicted sub-agent disabled its rollout tracing, leaving later turns out of the trace. Replacement Code Mode sessions could also reuse cell IDs from earlier sessions. ## What changed - Reattach reloaded children to the root rollout trace and emit `ThreadResumed` without duplicating `ThreadStarted`. - Reopen existing threads during replay, preserving their identity and history while clearing stale runtime cell and terminal process mappings. - Allocate Code Mode cell generations across sessions for both gRPC and stdio hosts to prevent ID reuse after reload. - Record an aborted trace when session startup fails before the session loop begins. ## Testing Add regression coverage for child eviction and reload, including a failed reload, continued inference tracing, distinct cell IDs, and preserved mail and follow-up context. Extend replay tests for history preservation and reused runtime handles, and host tests for cell IDs across session replacement and reconnection. GitOrigin-RevId: 6c146c04b5cda9295afb7d973c0d5474b363a822
101 lines
3.2 KiB
Rust
101 lines
3.2 KiB
Rust
//! Destination admission and account revocation cover the gRPC request lifetime.
|
|
|
|
use codex_http_client::DestinationPolicy;
|
|
use codex_http_client::HttpClientFactory;
|
|
use codex_http_client::NetworkPolicyController;
|
|
use codex_http_client::OutboundProxyPolicy;
|
|
use pretty_assertions::assert_eq;
|
|
|
|
use super::*;
|
|
|
|
#[tokio::test]
|
|
async fn restricted_destination_is_rejected_before_connecting_to_the_code_mode_host() -> Result<()>
|
|
{
|
|
let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await?;
|
|
let controller = NetworkPolicyController::default();
|
|
assert!(controller.publish(
|
|
controller.policy().revision(),
|
|
DestinationPolicy::Restricted {
|
|
allowed_hosts: ["allowed.example".into()].into()
|
|
}
|
|
));
|
|
let provider = Arc::new(GrpcCodeModeSessionProvider::with_http_client_factory(
|
|
format!("https://{}", listener.local_addr()?),
|
|
HttpClientFactory::new(OutboundProxyPolicy::ReqwestDefault)
|
|
.with_network_policy(controller.policy()),
|
|
));
|
|
let Err(error) = provider.create_session().await else {
|
|
anyhow::bail!("restricted endpoint created a session")
|
|
};
|
|
assert!(
|
|
error.contains("destination denied by application network policy"),
|
|
"{error}"
|
|
);
|
|
assert!(
|
|
timeout(Duration::from_millis(/*millis*/ 50), listener.accept())
|
|
.await
|
|
.is_err()
|
|
);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn account_change_revokes_active_rpc_and_renews_the_cached_client() -> Result<()> {
|
|
let host = HostHarness::start("grpc://127.0.0.1:0").await?;
|
|
let controller = NetworkPolicyController::default();
|
|
assert!(controller.publish(
|
|
controller.policy().revision(),
|
|
DestinationPolicy::Unrestricted
|
|
));
|
|
let provider = GrpcCodeModeSessionProvider::with_http_client_factory(
|
|
host.endpoint.clone(),
|
|
HttpClientFactory::new(OutboundProxyPolicy::ReqwestDefault)
|
|
.with_network_policy(controller.policy()),
|
|
);
|
|
let session = provider
|
|
.create_session()
|
|
.await
|
|
.map_err(anyhow::Error::msg)?;
|
|
let mut pending = request("await new Promise(() => {});");
|
|
pending.yield_time_ms = Some(60_000);
|
|
let started = session
|
|
.execute(
|
|
pending,
|
|
Arc::new(NoopCodeModeSessionDelegate),
|
|
/*preempt*/ None,
|
|
)
|
|
.await
|
|
.map_err(anyhow::Error::msg)?;
|
|
|
|
controller.policy().invalidate();
|
|
assert!(
|
|
timeout(TEST_TIMEOUT, started.initial_response())
|
|
.await
|
|
.context("account revocation did not interrupt the active RPC")?
|
|
.is_err()
|
|
);
|
|
assert!(controller.publish(
|
|
controller.policy().revision(),
|
|
DestinationPolicy::Unrestricted
|
|
));
|
|
|
|
let replacement = provider
|
|
.create_session()
|
|
.await
|
|
.map_err(anyhow::Error::msg)?;
|
|
let response = execute(
|
|
&replacement,
|
|
request(r#"text("replacement")"#),
|
|
Arc::new(NoopCodeModeSessionDelegate),
|
|
)
|
|
.await?;
|
|
assert_eq!(
|
|
response,
|
|
text_response("g2:1", "replacement", response.code_mode_host_duration())
|
|
);
|
|
session.shutdown().await.map_err(anyhow::Error::msg)?;
|
|
replacement.shutdown().await.map_err(anyhow::Error::msg)?;
|
|
Ok(())
|
|
}
|