mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-10-27 21:50:36 +00:00
fix(sandbox): clamp negative read_file range bounds (#5655)
* fix(sandbox): clamp a negative start_line in provider read_file LocalSandbox.read_file clamps the start line with max(start_line or 1, 1), but e2b, OpenSandbox and BoxLite used start_line or 1, so a negative value reached Python's negative-index slicing and read from the end of the file instead of the first line. Clamp all three the same way, and pin the boundary cases in their existing range tests: a past-EOF start still returns an empty string, a negative start reads from line 1. Surfaced by the review of #5616 (e2b has the same gap, consistency nit). * fix(sandbox): clamp negative end_line across providers Complete the range-bound consistency fix for e2b, OpenSandbox and BoxLite: clamp a negative end_line to zero like LocalSandbox instead of letting Python's negative-index slicing silently drop trailing lines. Add the symmetric boundary assertion to each provider's existing range test.
This commit is contained in:
parent
3d5cc1efae
commit
55f5d6b629
@ -231,8 +231,10 @@ class BoxliteBox(Sandbox):
|
||||
if start_line is None and end_line is None:
|
||||
return content
|
||||
lines = content.splitlines()
|
||||
start = start_line or 1
|
||||
end = end_line if end_line is not None else len(lines)
|
||||
# Clamp like LocalSandbox.read_file: a negative start would otherwise
|
||||
# wrap around through Python's negative-index slicing.
|
||||
start = max(start_line or 1, 1)
|
||||
end = max(end_line, 0) if end_line is not None else len(lines)
|
||||
return "\n".join(lines[start - 1 : end])
|
||||
|
||||
def write_file(self, path: str, content: str, append: bool = False) -> None:
|
||||
|
||||
@ -234,8 +234,10 @@ class E2BSandbox(Sandbox):
|
||||
return content.decode("utf-8", errors="replace") if isinstance(content, bytes) else content or ""
|
||||
text = content.decode("utf-8", errors="replace") if isinstance(content, bytes) else content or ""
|
||||
lines = text.splitlines()
|
||||
start = start_line or 1
|
||||
end = end_line if end_line is not None else len(lines)
|
||||
# Clamp like LocalSandbox.read_file: a negative start would otherwise
|
||||
# wrap around through Python's negative-index slicing.
|
||||
start = max(start_line or 1, 1)
|
||||
end = max(end_line, 0) if end_line is not None else len(lines)
|
||||
content = "\n".join(lines[start - 1 : end])
|
||||
return content
|
||||
except Exception as e:
|
||||
|
||||
@ -272,8 +272,10 @@ class OpenSandboxSandbox(Sandbox):
|
||||
if start_line is None and end_line is None:
|
||||
return content or ""
|
||||
lines = (content or "").splitlines()
|
||||
start = start_line or 1
|
||||
end = end_line if end_line is not None else len(lines)
|
||||
# Clamp like LocalSandbox.read_file: a negative start would otherwise
|
||||
# wrap around through Python's negative-index slicing.
|
||||
start = max(start_line or 1, 1)
|
||||
end = max(end_line, 0) if end_line is not None else len(lines)
|
||||
return "\n".join(lines[start - 1 : end])
|
||||
|
||||
def write_file(self, path: str, content: str, append: bool = False) -> None:
|
||||
|
||||
@ -204,6 +204,11 @@ def test_read_file_supports_optional_line_ranges(monkeypatch: pytest.MonkeyPatch
|
||||
assert box.read_file("/mnt/user-data/workspace/range.txt", start_line=2, end_line=4) == "line 2\nline 3\nline 4"
|
||||
assert box.read_file("/mnt/user-data/workspace/range.txt", start_line=4) == "line 4\nline 5"
|
||||
assert box.read_file("/mnt/user-data/workspace/range.txt", end_line=2) == "line 1\nline 2"
|
||||
# A start past EOF comes back empty rather than raising, and a negative
|
||||
# start reads from the first line instead of wrapping around.
|
||||
assert box.read_file("/mnt/user-data/workspace/range.txt", start_line=99) == ""
|
||||
assert box.read_file("/mnt/user-data/workspace/range.txt", start_line=-1) == "line 1\nline 2\nline 3\nline 4\nline 5"
|
||||
assert box.read_file("/mnt/user-data/workspace/range.txt", end_line=-1) == ""
|
||||
assert all(call == ("cat", "--", "/mnt/user-data/workspace/range.txt") for call in calls)
|
||||
|
||||
|
||||
|
||||
@ -3550,6 +3550,11 @@ def test_read_file_supports_bounded_ranges():
|
||||
assert sb.read_file("/mnt/user-data/workspace/range.txt", start_line=2, end_line=4) == "line 2\nline 3\nline 4"
|
||||
assert sb.read_file("/mnt/user-data/workspace/range.txt", start_line=4) == "line 4\nline 5"
|
||||
assert sb.read_file("/mnt/user-data/workspace/range.txt", end_line=2) == "line 1\nline 2"
|
||||
# A start past EOF comes back empty rather than raising, and a negative
|
||||
# start reads from the first line instead of wrapping around.
|
||||
assert sb.read_file("/mnt/user-data/workspace/range.txt", start_line=99) == ""
|
||||
assert sb.read_file("/mnt/user-data/workspace/range.txt", start_line=-1) == "line 1\nline 2\nline 3\nline 4\nline 5"
|
||||
assert sb.read_file("/mnt/user-data/workspace/range.txt", end_line=-1) == ""
|
||||
|
||||
resolved_path = "/home/user/workspace/range.txt"
|
||||
assert all(path == resolved_path for path, _fmt in files.read_calls), files.read_calls
|
||||
|
||||
@ -599,6 +599,11 @@ def test_text_binary_append_and_line_ranges() -> None:
|
||||
assert box.read_file(path, 2, 3) == "two\nthree"
|
||||
box.write_file(path, "\nfour", append=True)
|
||||
assert box.read_file(path) == "one\ntwo\nthree\nfour"
|
||||
# A start past EOF comes back empty rather than raising, and a negative
|
||||
# start reads from the first line instead of wrapping around.
|
||||
assert box.read_file(path, 99) == ""
|
||||
assert box.read_file(path, -1) == "one\ntwo\nthree\nfour"
|
||||
assert box.read_file(path, end_line=-1) == ""
|
||||
binary_path = "/mnt/user-data/outputs/blob.bin"
|
||||
box.update_file(binary_path, b"\x00\xffpayload")
|
||||
assert box.download_file(binary_path) == b"\x00\xffpayload"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user