Add a bounded V8 runtime for UI plugin processes (#57508)

## What changed

- Add `--codex-ui-plugin-process` to `codex-code-mode-host` and a typed protocol for initializing, invoking, and closing UI plugin isolates.
- Support persistent module state and string results from synchronous or promise-based exports across up to 32 isolates in one helper process.
- Require sandbox-enabled V8 with JIT disabled, restrict executable loading and globals, and enforce execution deadlines and per-instance queue, source, result, and promise limits.
- Close affected isolates on script failures, cancellation, or overload, and return bounded script diagnostics.
- Bump the helper handshake to version 3 and increase the maximum frame size to 1 MiB.

## Testing

Add wire-level integration tests and runtime unit tests covering promise settlement, cancellation, loading restrictions, diagnostics, failure isolation, capacity reuse, transport bounds, and watchdog synchronization. Add CLI tests for argument validation before helper startup.

GitOrigin-RevId: bad6a57c84d9197c1fd76a78cf060502c5bc8bb8
This commit is contained in:
Joe Savona
2026-10-27 16:36:32 +00:00
committed by copyberry
parent a43fffca74
commit 2d1984b9f7
22 changed files with 1856 additions and 6 deletions
+16 -2
View File
@@ -18,6 +18,13 @@ const OTEL_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(/*secs*/ 5);
#[derive(Debug, Parser)]
struct Cli {
#[arg(
long,
hide = true,
conflicts_with_all = ["listen", "otel_trace_listen", "otel_trace_exporter"]
)]
codex_ui_plugin_process: bool,
/// Transport endpoint: `stdio`, `stdio://`, `grpc+stdio://`, or `grpc://IP:PORT`.
#[arg(
long,
@@ -37,8 +44,7 @@ struct Cli {
}
#[tokio::main(flavor = "current_thread")]
async fn main() -> anyhow::Result<()> {
let cli = Cli::parse();
async fn run(cli: Cli) -> anyhow::Result<()> {
let mut trace_transport = if let Some(trace_listen) = cli.otel_trace_listen.as_deref() {
Some(TraceWebSocket::start(trace_listen).await?)
} else {
@@ -88,6 +94,14 @@ async fn main() -> anyhow::Result<()> {
result
}
fn main() -> anyhow::Result<()> {
let cli = Cli::parse();
if cli.codex_ui_plugin_process {
return codex_code_mode_runtime::run_ui_sandbox().map_err(Into::into);
}
run(cli)
}
fn build_trace_provider(endpoint: &str) -> anyhow::Result<OtelProvider> {
OtelProvider::try_new(&OtelSettings {
http_client_factory: codex_http_client::HttpClientFactory::new(