Skip to content

core: add stdin-backed sandboxed fs writes#15187

Open
bolinfest wants to merge 1 commit intopr15213from
pr15187
Open

core: add stdin-backed sandboxed fs writes#15187
bolinfest wants to merge 1 commit intopr15213from
pr15187

Conversation

@bolinfest
Copy link
Collaborator

@bolinfest bolinfest commented Mar 19, 2026

Why

The first PR introduces a read-only sandbox-backed filesystem helper so view_image can stop reading files in-process. We still need the corresponding write/stdin plumbing so future filesystem operations can go through the same sandbox boundary instead of falling back to host-side std::fs calls.

What changed

  • extended codex-fs-ops with a write command and write-path tests
  • added ExecStdin plumbing through core/src/exec.rs, core/src/spawn.rs, and core/src/sandboxing/mod.rs
  • updated the Windows sandbox capture paths to optionally forward stdin bytes into the sandboxed child
  • exposed sandboxed_fs::write_file() on top of that shared stdin path
  • added a focused regression test proving exec can stream stdin bytes into a child process

Testing

  • cargo test -p codex-fs-ops
  • cargo test -p codex-core --lib exec::tests::exec_passes_stdin_bytes_to_child -- --exact
  • cargo test -p codex-core --test all view_image

Stack created with Sapling. Best reviewed with ReviewStack.

Copy link
Contributor

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a02c347a59

ℹ️ 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".

Comment on lines +1126 to +1130
if let Some(stdin_task) = stdin_task {
match stdin_task.await {
Ok(Ok(())) => {}
Ok(Err(err)) => return Err(CodexErr::Io(err)),
Err(join_err) => return Err(CodexErr::Io(io::Error::other(join_err))),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Don't fail exec when the child closes stdin early

When ExecStdin::Bytes is used with the direct exec() path, commands that stop reading before draining all input (for example head -c 1, parsers that only consume a header, or a child that exits immediately) now come back as I/O errors even if the process itself exits successfully. In that case child_stdin.write_all() returns BrokenPipe, and this block converts it into CodexErr::Io after we've already collected the child's exit status, so partial stdin consumers become unusable through the new API.

Useful? React with 👍 / 👎.

Comment on lines 240 to +243
mut env,
expiration,
network,
stdin: _stdin,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve stdin when building sandboxed exec requests

build_exec_request() drops the new ExecParams.stdin field here, and SandboxManager::transform() still initializes ExecRequest.stdin to ExecStdin::Closed in core/src/sandboxing/mod.rs. That means any caller that goes through process_exec_tool_call/build_exec_request will always send EOF, so the stdin support added in this commit only works for the direct exec() path covered by the new unit test.

Useful? React with 👍 / 👎.

Comment on lines +394 to +401
if let Some(stdin_bytes) = stdin_bytes {
write_frame(
&mut pipe_write,
&FramedMessage {
version: 1,
message: Message::Stdin {
payload: crate::ipc_framed::StdinPayload {
data_b64: crate::ipc_framed::encode_bytes(&stdin_bytes),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Chunk stdin frames before sending them to the elevated runner

On the elevated Windows backend this sends the entire stdin buffer as one Message::Stdin frame. windows-sandbox-rs/src/elevated/ipc_framed.rs caps a frame at 8 MiB, and base64 expansion means the raw stdin limit is only about 6 MiB. Any larger sandboxed write will therefore fail deterministically on elevated Windows even though the helper itself is streaming stdin to disk.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant