mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-05-23 16:35:59 +00:00
fix(uploads): unconditionally adjust file permissions for sandbox access
The conditional check meant uploaded files retained 0o600 permissions in some Docker sandbox configurations, preventing the sandbox process (UID 1000) from reading them. Always add group/other read bits so every sandbox setup can access uploaded content. Also add read bits to the sync-path writable helper as defense in depth.
This commit is contained in:
@@ -69,7 +69,7 @@ def _make_file_sandbox_writable(file_path: os.PathLike[str] | str) -> None:
|
|||||||
logger.warning("Skipping sandbox chmod for symlinked upload path: %s", file_path)
|
logger.warning("Skipping sandbox chmod for symlinked upload path: %s", file_path)
|
||||||
return
|
return
|
||||||
|
|
||||||
writable_mode = stat.S_IMODE(file_stat.st_mode) | stat.S_IWUSR | stat.S_IWGRP | stat.S_IWOTH
|
writable_mode = stat.S_IMODE(file_stat.st_mode) | stat.S_IWUSR | stat.S_IWGRP | stat.S_IWOTH | stat.S_IRGRP | stat.S_IROTH
|
||||||
chmod_kwargs = {"follow_symlinks": False} if os.chmod in os.supports_follow_symlinks else {}
|
chmod_kwargs = {"follow_symlinks": False} if os.chmod in os.supports_follow_symlinks else {}
|
||||||
os.chmod(file_path, writable_mode, **chmod_kwargs)
|
os.chmod(file_path, writable_mode, **chmod_kwargs)
|
||||||
|
|
||||||
@@ -295,14 +295,15 @@ async def upload_files(
|
|||||||
_cleanup_uploaded_paths(written_paths)
|
_cleanup_uploaded_paths(written_paths)
|
||||||
raise HTTPException(status_code=500, detail=f"Failed to upload {file.filename}: {str(e)}")
|
raise HTTPException(status_code=500, detail=f"Failed to upload {file.filename}: {str(e)}")
|
||||||
|
|
||||||
# When the sandbox uses bind-mounted thread data directories (e.g. AIO with
|
# Uploaded files are created with 0o600 permissions (owner read/write only).
|
||||||
# LocalContainerBackend), uploaded files are visible inside the container but
|
# In Docker sandbox deployments the gateway writes as root but the sandbox
|
||||||
# retain the 0o600 permissions set by the gateway. The sandbox process runs
|
# process runs as a non-root user (typically UID 1000). Without group/other
|
||||||
# as a different user and cannot read them. Adjust permissions to add
|
# read bits the sandbox cannot access the files — whether the uploads
|
||||||
# group/other read bits so the sandbox can access the files.
|
# directory is bind-mounted into the container or synced via
|
||||||
if not sync_to_sandbox and getattr(sandbox_provider, "needs_upload_permission_adjustment", True):
|
# sandbox.update_file. Always add group/other read bits so every sandbox
|
||||||
for file_path in written_paths:
|
# configuration can read the uploaded content.
|
||||||
_make_file_sandbox_readable(file_path)
|
for file_path in written_paths:
|
||||||
|
_make_file_sandbox_readable(file_path)
|
||||||
|
|
||||||
if sync_to_sandbox:
|
if sync_to_sandbox:
|
||||||
for file_path, virtual_path in sandbox_sync_targets:
|
for file_path, virtual_path in sandbox_sync_targets:
|
||||||
|
|||||||
@@ -236,7 +236,10 @@ def test_upload_files_does_not_adjust_permissions_for_local_sandbox(tmp_path):
|
|||||||
|
|
||||||
assert result.success is True
|
assert result.success is True
|
||||||
make_writable.assert_not_called()
|
make_writable.assert_not_called()
|
||||||
make_readable.assert_not_called()
|
# Readable adjustment is now always applied regardless of sandbox type
|
||||||
|
make_readable.assert_called_once()
|
||||||
|
called_path = make_readable.call_args[0][0]
|
||||||
|
assert called_path.name == "notes.txt"
|
||||||
|
|
||||||
|
|
||||||
def test_upload_files_acquires_non_local_sandbox_before_writing(tmp_path):
|
def test_upload_files_acquires_non_local_sandbox_before_writing(tmp_path):
|
||||||
|
|||||||
Reference in New Issue
Block a user