diff --git a/app/agent/prompt/__init__.py b/app/agent/prompt/__init__.py index 72b768a5..0507c478 100644 --- a/app/agent/prompt/__init__.py +++ b/app/agent/prompt/__init__.py @@ -315,8 +315,6 @@ class PromptManager: "项目根目录": settings.ROOT_PATH, "配置目录": settings.CONFIG_PATH, "临时目录": settings.TEMP_PATH, - "日志目录": settings.LOG_PATH, - "主日志文件": settings.LOG_PATH / "moviepilot.log", } return [f" - {label}: `{path}`" for label, path in paths.items()] diff --git a/app/agent/tools/base.py b/app/agent/tools/base.py index 051cdb68..2667b56b 100644 --- a/app/agent/tools/base.py +++ b/app/agent/tools/base.py @@ -425,7 +425,6 @@ class MoviePilotTool(BaseTool, metaclass=ABCMeta): """ roots = [ settings.CONFIG_PATH / "agent", - settings.LOG_PATH, ] resolved_roots = [] for root in roots: @@ -461,7 +460,7 @@ class MoviePilotTool(BaseTool, metaclass=ABCMeta): allowed_text = "、".join(str(root) for root in allowed_roots) return ( resolved_path, - f"抱歉,普通用户只能{operation}Agent配置目录和日志目录内的文件或目录:{allowed_text}", + f"抱歉,普通用户只能{operation}Agent配置目录内的文件或目录:{allowed_text}", ) async def _check_local_storage_access( @@ -483,7 +482,7 @@ class MoviePilotTool(BaseTool, metaclass=ABCMeta): return None, None return ( None, - f"抱歉,普通用户只能{operation}本地配置目录、Agent记忆目录和日志目录,不能访问远程存储。", + f"抱歉,普通用户只能{operation}本地Agent配置目录,不能访问远程存储。", ) return await self._check_local_file_access(path=path, operation=operation) diff --git a/app/agent/tools/impl/edit_file.py b/app/agent/tools/impl/edit_file.py index 581d0e34..ce1d0b2b 100644 --- a/app/agent/tools/impl/edit_file.py +++ b/app/agent/tools/impl/edit_file.py @@ -28,7 +28,7 @@ class EditFileTool(MoviePilotTool): description: str = ( "Edit a local text file by replacing specific old text with new text. " "Non-admin users can only edit files inside the MoviePilot Agent config " - "and log directories." + "directory." ) args_schema: Type[BaseModel] = EditFileInput diff --git a/app/agent/tools/impl/write_file.py b/app/agent/tools/impl/write_file.py index b6a73205..0e57f14f 100644 --- a/app/agent/tools/impl/write_file.py +++ b/app/agent/tools/impl/write_file.py @@ -26,7 +26,7 @@ class WriteFileTool(MoviePilotTool): ] description: str = ( "Write full content to a local text file. Non-admin users can only write " - "inside the MoviePilot Agent config and log directories." + "inside the MoviePilot Agent config directory." ) args_schema: Type[BaseModel] = WriteFileInput diff --git a/tests/test_agent_prompt_secrets.py b/tests/test_agent_prompt_secrets.py index 269d8365..d57afab6 100644 --- a/tests/test_agent_prompt_secrets.py +++ b/tests/test_agent_prompt_secrets.py @@ -21,10 +21,12 @@ def test_moviepilot_info_does_not_expose_api_token_or_database_password(monkeypa assert "db.example.local" not in moviepilot_info assert str(settings.CONFIG_PATH) in moviepilot_info assert str(settings.TEMP_PATH) in moviepilot_info - assert str(settings.LOG_PATH) in moviepilot_info - assert str(settings.LOG_PATH / "moviepilot.log") in moviepilot_info + assert str(settings.LOG_PATH) not in moviepilot_info + assert str(settings.LOG_PATH / "moviepilot.log") not in moviepilot_info assert str(settings.LOG_PATH / "moviepilot.stdout.log") not in moviepilot_info assert str(settings.LOG_PATH / "moviepilot.frontend.stdout.log") not in moviepilot_info + assert "日志目录" not in moviepilot_info + assert "主日志文件" not in moviepilot_info assert str(settings.CONFIG_PATH / "agent") not in moviepilot_info assert str(settings.CONFIG_PATH / "agent" / "memory") not in moviepilot_info assert str(settings.CONFIG_PATH / "agent" / "skills") not in moviepilot_info diff --git a/tests/test_agent_resource_flow_permissions.py b/tests/test_agent_resource_flow_permissions.py index 0fbd9cd5..8fea3337 100644 --- a/tests/test_agent_resource_flow_permissions.py +++ b/tests/test_agent_resource_flow_permissions.py @@ -187,7 +187,7 @@ def test_non_admin_file_tools_can_access_config_directory(tmp_path, monkeypatch) def test_non_admin_file_tools_block_paths_outside_allowed_roots( tmp_path, monkeypatch ): - """普通用户不能通过文件工具访问配置、记忆和日志目录外的路径。""" + """普通用户不能通过文件工具访问 Agent 配置目录外的路径。""" config_path = tmp_path / "config" outside_path = tmp_path / "outside.txt" outside_path.write_text("secret", encoding="utf-8") @@ -208,10 +208,47 @@ def test_non_admin_file_tools_block_paths_outside_allowed_roots( assert "普通用户只能写入" in write_result assert "普通用户只能编辑" in edit_result assert "普通用户只能列出" in list_result + assert "日志目录" not in read_result + assert "日志目录" not in write_result + assert "日志目录" not in edit_result + assert "日志目录" not in list_result assert outside_path.read_text(encoding="utf-8") == "secret" list_directory.assert_not_called() +def test_non_admin_file_tools_block_log_directory(tmp_path, monkeypatch): + """普通用户不能通过文件工具读写运行日志目录。""" + config_path = tmp_path / "config" + monkeypatch.setattr(settings, "CONFIG_DIR", str(config_path)) + log_path = settings.LOG_PATH / "moviepilot.log" + log_path.parent.mkdir(parents=True) + log_path.write_text("secret log", encoding="utf-8") + + read_tool = ReadFileTool(session_id="session-1", user_id="10001") + write_tool = WriteFileTool(session_id="session-1", user_id="10001") + edit_tool = EditFileTool(session_id="session-1", user_id="10001") + list_tool = ListDirectoryTool(session_id="session-1", user_id="10001") + + read_result = asyncio.run(read_tool.run(str(log_path))) + write_result = asyncio.run(write_tool.run(str(log_path), "changed")) + edit_result = asyncio.run(edit_tool.run(str(log_path), "secret log", "changed")) + with patch.object( + ListDirectoryTool, "_list_directory_sync", return_value="listed" + ) as list_directory: + list_result = asyncio.run(list_tool.run(str(settings.LOG_PATH))) + + assert "普通用户只能读取" in read_result + assert "普通用户只能写入" in write_result + assert "普通用户只能编辑" in edit_result + assert "普通用户只能列出" in list_result + assert "日志目录" not in read_result + assert "日志目录" not in write_result + assert "日志目录" not in edit_result + assert "日志目录" not in list_result + assert log_path.read_text(encoding="utf-8") == "secret log" + list_directory.assert_not_called() + + def test_admin_file_tool_can_access_paths_outside_allowed_roots( tmp_path, monkeypatch ):