diff --git a/backend/packages/harness/deerflow/uploads/manager.py b/backend/packages/harness/deerflow/uploads/manager.py index 4f3334c62..3b4046d18 100644 --- a/backend/packages/harness/deerflow/uploads/manager.py +++ b/backend/packages/harness/deerflow/uploads/manager.py @@ -387,7 +387,12 @@ def delete_file_safe(base_dir: Path, filename: str) -> dict: safe_name = normalize_filename(filename) if safe_name != filename: raise PathTraversalError("Path traversal detected") - base_dir = _validate_upload_directory(Path(base_dir)) + try: + base_dir = _validate_upload_directory(Path(base_dir)) + except UnsafeUploadPathError as exc: + if isinstance(exc.__cause__, FileNotFoundError): + raise FileNotFoundError(f"File not found: {filename}") from exc + raise file_path = base_dir / safe_name try: file_stat = os.lstat(file_path) diff --git a/backend/tests/test_uploads_manager.py b/backend/tests/test_uploads_manager.py index 04af37de2..6f2612233 100644 --- a/backend/tests/test_uploads_manager.py +++ b/backend/tests/test_uploads_manager.py @@ -362,6 +362,10 @@ class TestDeleteFileSafe: with pytest.raises(FileNotFoundError): delete_file_safe(tmp_path, "nope.txt") + def test_delete_from_nonexistent_directory_raises_file_not_found(self, tmp_path): + with pytest.raises(FileNotFoundError, match="ghost.txt"): + delete_file_safe(tmp_path / "missing-uploads", "ghost.txt") + def test_delete_traversal_raises(self, tmp_path): with pytest.raises(PathTraversalError, match="traversal"): delete_file_safe(tmp_path, "../outside.txt")