Add exec-server exec RPC implementation#15090
Conversation
This adds the standalone exec-server stdio JSON-RPC crate and its smoke tests without wiring it into the CLI or unified-exec yet. Co-authored-by: Codex <noreply@openai.com>
Document the standalone exec-server crate, its stdio JSON-RPC transport, and the current request/response and notification payloads. Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
Keep only the standalone handshake transport in the first PR. Leave exec RPC behavior unimplemented here so the working process implementation can land in a separate follow-up.\n\nCo-authored-by: Codex <noreply@openai.com>
Move process-oriented client helpers and exports into the exec follow-up. Keep the first PR focused on spawning the stub server and running the initialize handshake.\n\nCo-authored-by: Codex <noreply@openai.com>
|
I have read the CLA Document and I hereby sign the CLA You can retrigger this bot by commenting recheck in this Pull Request. Posted by the CLA Assistant Lite bot. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 79b46e346d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if let Some(process) = processes.get_mut(&process_id) { | ||
| process.exit_code = Some(exit_code); | ||
| } |
There was a problem hiding this comment.
Remove exited processes from the process map
watch_exit only sets exit_code and never evicts the RunningProcess entry. Each finished process keeps retained output (up to RETAINED_OUTPUT_BYTES_PER_PROCESS) and session state until connection shutdown, so long-lived connections that run many short-lived processes can accumulate unbounded memory/state.
Useful? React with 👍 / 👎.
| if let Some(process) = process_map.get(¶ms.process_id) { | ||
| process.session.terminate(); | ||
| true | ||
| } else { |
There was a problem hiding this comment.
Return running=false for already exited processes
terminate returns running: true whenever process_id exists in the map, without checking whether the process has already exited. Since exited entries are retained, terminate can claim a process is running when it is not, which breaks caller logic that relies on this flag.
Useful? React with 👍 / 👎.
| loop { | ||
| let (stream, peer_addr) = listener.accept().await?; | ||
| tokio::spawn(async move { | ||
| match accept_async(stream).await { | ||
| Ok(websocket) => { | ||
| run_connection(JsonRpcConnection::from_websocket( | ||
| websocket, |
There was a problem hiding this comment.
Require authentication on websocket exec transport
The websocket listener accepts any incoming peer and immediately starts a JSON-RPC exec session. Combined with unauthenticated initialize flow, binding to non-loopback addresses allows arbitrary remote clients to call process/start and execute commands (unauthenticated RCE).
Useful? React with 👍 / 👎.
Introduce API-agnostic server envelope parsing/encoding and a tiny method-registration router in the initialize-only exec-server slice. Co-authored-by: Codex <noreply@openai.com>
79b46e3 to
c5071a9
Compare
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
c5071a9 to
84a6cbe
Compare
| stream, | ||
| chunk: chunk.clone(), | ||
| }); | ||
| while process.retained_bytes > RETAINED_OUTPUT_BYTES_PER_PROCESS { |
There was a problem hiding this comment.
unified exec needs the tail. we might need the same "drop middle strategy" as used in core.
Stacked PR 2/3, based on the stub PR.
Adds the exec RPC implementation and process/event flow in exec-server only.