Skip to content

Fix Docker sandbox filesystem tool fallback#1105

Open
penso wants to merge 1 commit into
mainfrom
shining-roof
Open

Fix Docker sandbox filesystem tool fallback#1105
penso wants to merge 1 commit into
mainfrom
shining-roof

Conversation

@penso

@penso penso commented Jun 5, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Add regression coverage for sandboxed Read/Write/Edit/MultiEdit on /home/sandbox and workspace/data paths
  • Fall back from translated Docker host paths to container copy when the gateway process cannot access the host mount
  • Improve empty docker/OCI copy failure diagnostics and clarify sandbox path guidance in fs tool descriptions
  • Closes [Bug]: Read/Write/Edit tools don't work in Docker #1096

Validation

Completed

  • cargo test -p moltis-tools fs::contract_tests::sandbox_
  • cargo test -p moltis-tools sandbox::tests::core::test_docker_write_file_falls_back_to_container_copy_when_host_mount_is_inaccessible
  • cargo test -p moltis-tools sandbox::tests::core::test_docker_read_file_uses_mounted_workspace_path
  • cargo test -p moltis-tools sandbox::tests::core::test_docker_write_file_uses_mounted_workspace_path
  • cargo test -p moltis-tools sandbox::file_system::tests::oci_copy_failure_detail_is_not_empty_when_stderr_is_empty
  • cargo fmt --all -- --check

Remaining

  • Full just lint / just test not run locally

Manual QA

  • Not run locally; Docker-in-Docker behavior is covered with a fake OCI CLI regression test that forces host mount access failure and verifies fallback to container copy.

@greptile-apps

greptile-apps Bot commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes the Docker sandbox filesystem fallback so that write_file and list_files catch host-mount access errors and retry via container copy, and updates read_file to fall back on PermissionDenied/NotRegularFile host results in addition to NotFound. It also improves OCI copy error messages when stderr is empty and adds sandbox path guidance to all four fs tool descriptions.

  • Write/list fallback: native_host_write_file and native_host_list_files errors are now caught and logged; execution falls through to the container path instead of propagating. A fake-CLI test verifies the write path; list_files has no equivalent regression test yet.
  • Read fallback condition: Condition changed from !NotFound → return to Ok | TooLarge → return, so PermissionDenied and NotRegularFile host results also fall through to the container read.
  • Diagnostics: New container_copy_failure_detail helper produces a non-empty message when the OCI CLI exits with no stderr output, fixing silent/blank error strings.

Confidence Score: 4/5

Safe to merge; the fallback logic is correct and the new tests cover the primary regression cases.

The write and list fallbacks are well-implemented and the write path has a focused regression test. The read path relies implicitly on native_host_read_file never returning Err for file-access failures, creating a silent coupling that differs from the write/list pattern. The list_files fallback branch is also untested.

crates/tools/src/sandbox/docker.rs — the read_file error-propagation asymmetry and the untested list_files fallback branch both warrant a second look.

Important Files Changed

Filename Overview
crates/tools/src/sandbox/docker.rs Adds error-catching fallback to write_file and list_files when host-mount access fails; changes read_file condition from !NotFound to explicit Ok
crates/tools/src/sandbox/file_system.rs Adds container_copy_failure_detail helper to produce non-empty error messages when OCI cp exits with no stderr; logic and test are correct.
crates/tools/src/sandbox/tests/core.rs Adds write-fallback regression test using a fake CLI script; no equivalent test for list_files fallback.
crates/tools/src/fs/contract_tests.rs Adds four new sandbox contract tests covering /home/sandbox/ and workspace paths for Write, Read+Write, Edit, and MultiEdit through MockSandbox.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[fs operation] --> B{mounted_host_path?}
    B -- None --> G[container op]
    B -- Some --> C[native_host_* call]
    C -- read Ok/TooLarge --> D[return host result]
    C -- read NotFound/PermissionDenied/NotRegularFile --> F[debug log, fallback]
    C -- read Err via ? --> E[return Err, no fallback]
    C -- write Ok --> D
    C -- write Err --> F
    C -- list Ok --> H[remap and return]
    C -- list Err --> F
    F --> G
    G --> I[return container result]
    style E fill:#f99,stroke:#c00
    style F fill:#ffe,stroke:#cc0
Loading

Comments Outside Diff (1)

  1. crates/tools/src/sandbox/docker.rs, line 766-772 (link)

    P2 Read-path error not caught by fallback

    write_file and list_files now explicitly catch errors from their respective native_host_* helpers and fall back to container operations. read_file still uses .await?, so any Err from native_host_read_file propagates immediately without attempting the container fallback. This works today because native_host_read_file converts every IO error into an Ok(SandboxReadResult::…) variant rather than returning Err. If that mapping ever gains an error path, the read fallback will silently break while write and list continue to work.

    Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Reviews (1): Last reviewed commit: "fix(sandbox): route docker fs tools thro..." | Re-trigger Greptile

Comment on lines 822 to 843
async fn list_files(&self, id: &SandboxId, root: &str) -> Result<SandboxListFilesResult> {
if let Some(host_path) = self.mounted_host_path(id, root) {
let host_files = native_host_list_files(
let host_result = native_host_list_files(
host_path
.to_str()
.ok_or_else(|| Error::message("mounted host path contains invalid UTF-8"))?,
)
.await?;
return remap_host_list_result_to_guest(root, &host_path, host_files);
.await;
match host_result {
Ok(host_files) => {
return remap_host_list_result_to_guest(root, &host_path, host_files);
},
Err(error) => {
debug!(
guest_path = root,
host_path = %host_path.display(),
%error,
"mounted host list failed; falling back to container list"
);
},
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 No test for list_files host-mount fallback

The analogous write_file fallback has a dedicated regression test (test_docker_write_file_falls_back_to_container_copy_when_host_mount_is_inaccessible), but the list_files fallback added here has no corresponding test. native_host_list_files returns Err on non-NotFound IO errors (e.g., permission denied on the directory), so a similar fake-CLI test that sets host_data_dir to a non-existent path and asserts the container list_files call is reached would cover the new branch.

@codecov

codecov Bot commented Jun 5, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@codspeed-hq

codspeed-hq Bot commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 39 untouched benchmarks
⏩ 5 skipped benchmarks1


Comparing shining-roof (36be45e) with main (a568a3c)

Open in CodSpeed

Footnotes

  1. 5 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

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.

[Bug]: Read/Write/Edit tools don't work in Docker

1 participant