XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet
公开
关注 0 Fork 0 Star 1
返回提交历史

XFEstudio/gpt4free

Address code review: improve type hints, security docs, FileListTool skipped count, dynamic _TOOL_COUNT

Agent-Logs-Url: https://github.com/xtekky/gpt4free/sessions/1b3f481e-143f-4c30-9982-1063c0338ec3 Co-authored-by: hlohaus <983577+hlohaus@users.noreply.github.com>

0501738d
copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
提交于

代码差异

3 个文件 +31 -5
Modified etc/unittest/mcp.py +2 -2
@@ -19,8 +19,8 @@ try:
19 19 except ImportError:
20 20 has_requirements = False
21 21
22 # Total number of tools registered in MCPServer
23 _TOOL_COUNT = 10
22 # Total number of tools registered in MCPServer (derived at import time)
23 _TOOL_COUNT = len(MCPServer().tools)
24 24
25 25
26 26 class TestMCPServer(unittest.IsolatedAsyncioTestCase):
Modified g4f/mcp/pa_provider.py +23 -2
@@ -11,6 +11,27 @@ A ``.pa.py`` file is a plain Python file that is executed inside a sandbox.
11 11 Inside that sandbox the code may only import from the *whitelisted* module set
12 12 and may only access the file-system through a workspace-scoped ``open()``.
13 13
14 Security model
15 --------------
16 The sandbox mitigates the following vectors:
17
18 * **Arbitrary module imports** — only modules in :data:`SAFE_MODULES` may be
19 imported. The built-in ``__import__`` is replaced with a wrapper that raises
20 ``ImportError`` for any top-level name not in the allowlist. Relative imports
21 are unconditionally blocked.
22 * **Filesystem escape** — ``open()`` is replaced with a workspace-scoped version
23 that resolves symlinks and checks that the canonical path starts with the
24 workspace root. Direct ``os``/``pathlib`` access is blocked because those
25 modules are not in the allowlist.
26 * **Code injection** — ``exec``, ``eval``, ``compile``, and ``input`` are removed
27 from the sandbox built-ins so code in the sandbox cannot spawn secondary
28 execution contexts.
29
30 Known limitations: the sandbox does not enforce CPU/memory limits or wall-clock
31 timeouts. Callers that need to bound execution time should wrap
32 :func:`execute_safe_code` with a ``asyncio.wait_for`` or ``concurrent.futures``
33 timeout.
34
14 35 Typical layout of a ``.pa.py`` file::
15 36
16 37 from aiohttp import ClientSession
@@ -40,7 +61,7 @@ import contextlib
40 61 import traceback
41 62 import builtins as _builtins
42 63 from pathlib import Path
43 from typing import Any, Dict, FrozenSet, List, Optional
64 from typing import Any, Dict, FrozenSet, List, Optional, Type
44 65
45 66 # ---------------------------------------------------------------------------
46 67 # Workspace directory
@@ -251,7 +272,7 @@ def execute_safe_code(
251 272 # .pa.py provider loader
252 273 # ---------------------------------------------------------------------------
253 274
254 def load_pa_provider(file_path: "str | Path") -> Optional[Any]:
275 def load_pa_provider(file_path: "str | Path") -> Optional[Type]:
255 276 """Load a ``.pa.py`` file and return the provider class it defines.
256 277
257 278 The file is executed inside the safe sandbox. The module is expected to
Modified g4f/mcp/tools.py +6 -1
@@ -689,6 +689,7 @@ class FileListTool(MCPTool):
689 689 return {"error": f"Path is not a directory: {rel_path}"}
690 690
691 691 entries = []
692 skipped = 0
692 693 iterator = target.rglob("*") if recursive else target.iterdir()
693 694 for entry in sorted(iterator):
694 695 try:
@@ -701,14 +702,18 @@ class FileListTool(MCPTool):
701 702 info["size"] = entry.stat().st_size
702 703 entries.append(info)
703 704 except Exception:
705 skipped += 1
704 706 continue
705 707
706 return {
708 result: Dict[str, Any] = {
707 709 "workspace": str(workspace),
708 710 "path": rel_path or "/",
709 711 "entries": entries,
710 712 "count": len(entries),
711 713 }
714 if skipped:
715 result["skipped"] = skipped
716 return result
712 717 except Exception as exc:
713 718 return {"error": f"List failed: {exc}"}
714 719