Skip to content

Feat/tool permission#8617

Draft
lingyun14beta wants to merge 18 commits into
AstrBotDevs:masterfrom
lingyun14beta:feat/tool-permission
Draft

Feat/tool permission#8617
lingyun14beta wants to merge 18 commits into
AstrBotDevs:masterfrom
lingyun14beta:feat/tool-permission

Conversation

@lingyun14beta
Copy link
Copy Markdown
Contributor

@lingyun14beta lingyun14beta commented Jun 6, 2026

Related #8511 短期实现

Modifications / 改动点

  • astrbot/core/agent/tool.pyFunctionTool 新增 require_admin: bool = False 字段,默认值保持向后兼容
  • astrbot/core/provider/func_tool_manager.py:新增 set_tool_require_admin() 持久化权限配置(存储为 map,仅覆盖用户明确配置的工具);新增 _restore_tool_permissions() 恢复权限状态;在 init_mcp_clients() 末尾和 _init_mcp_client() 末尾分别调用,覆盖批量初始化和动态启动/重连场景
  • astrbot/core/star/star_manager.pyload() 末尾调用 _restore_tool_permissions(),确保插件工具注册完成后权限正确恢复(含热重载)
  • astrbot/core/astr_agent_tool_exec.py_build_handoff_toolset() 两个分支均加入 require_admin 过滤,覆盖 Handoff 子 Agent 路径(该路径绕过主对话的组装流程)
  • astrbot/core/astr_main_agent.py:新增 _filter_tools_by_role(),在 _plugin_tool_fix 之后、AgentRunner.reset() 之前过滤非管理员无权调用的工具,LLM 不会感知受限工具的存在
  • astrbot/core/agent/runners/tool_loop_agent_runner.py_handle_function_tools()execute() 前插入权限二次拦截,作为兜底保障
  • astrbot/dashboard/routes/tools.pyget_tool_list 返回 require_admin 字段;新增 POST /tools/set-permission 接口,内置工具不可修改
  • dashboard/src/components/extension/componentPanel/components/ToolTable.vue:函数工具列表新增"权限"列,readonly 工具显示 -,其他工具显示可点击下拉,与指令管理页风格一致
  • dashboard/src/components/extension/componentPanel/index.vue:新增 handleUpdateToolPermission,绑定 @update-permission 事件
  • dashboard/src/components/extension/componentPanel/types.tsToolItem 新增 require_admin?: boolean
  • dashboard/src/i18n/locales/zh-CN/features/tool-use.json:新增权限相关翻译 key
  • dashboard/src/i18n/locales/en-US/features/tool-use.json:新增权限相关翻译 key
  • dashboard/src/i18n/locales/ru-RU/features/tool-use.json:新增权限相关翻译 key
  • This is NOT a breaking change. / 这不是一个破坏性变更。

Screenshots or Test Results / 运行截图或测试结果

image

Checklist / 检查清单

  • 😊 If there are new features added in the PR, I have discussed it with the authors through issues/emails, etc.
    / 如果 PR 中有新加入的功能,已经通过 Issue / 邮件等方式和作者讨论过。

  • 👀 My changes have been well-tested, and "Verification Steps" and "Screenshots" have been provided above.
    / 我的更改经过了良好的测试,并已在上方提供了“验证步骤”和“运行截图”

  • 🤓 I have ensured that no new dependencies are introduced, OR if new dependencies are introduced, they have been added to the appropriate locations in requirements.txt and pyproject.toml.
    / 我确保没有引入新依赖库,或者引入了新依赖库的同时将其添加到 requirements.txtpyproject.toml 文件相应位置。

  • 😮 My changes do not introduce malicious code.
    / 我的更改没有引入恶意代码。

Summary by Sourcery

Introduce role-based tool permissions that restrict certain tools to admin users and expose permission management in the web dashboard.

New Features:

  • Allow marking individual function tools as admin-only and persist their permission state across restarts.
  • Add server-side APIs and web UI controls to view and update each tool's permission (admin-only vs everyone) from the dashboard.
  • Hide admin-only tools from non-admin users during tool selection and execution, with centralized permission checks blocking unauthorized tool calls.

Enhancements:

  • Restore tool permission configuration after MCP and plugin tools are initialized to keep runtime state consistent.
  • Extend tool metadata and localization to surface tool permission information in the dashboard tool table.

@dosubot dosubot Bot added size:L This PR changes 100-499 lines, ignoring generated files. area:core The bug / feature is about astrbot's core, backend area:webui The bug / feature is about webui(dashboard) of astrbot. labels Jun 6, 2026
Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 2 issues, and left some high level feedback:

  • The permission filtering logic for require_admin is now implemented in multiple places (_filter_tools_by_role, _build_handoff_toolset, and the tool loop runner); consider extracting a shared helper or central check to avoid divergence of behavior over time.
  • In ToolTable.vue, getPermissionColor and getPermissionLabel accept permission: string even though only 'admin' | 'everyone' are valid; tightening the type and reusing the require_admin boolean directly would improve type-safety and reduce conversion logic.
  • In the Web UI handler handleUpdateToolPermission, tool.require_admin is optimistically mutated before the request; to avoid intermediate inconsistent state in the UI, consider cloning/updating local state after a successful response instead of mutating the original object preemptively.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The permission filtering logic for `require_admin` is now implemented in multiple places (`_filter_tools_by_role`, `_build_handoff_toolset`, and the tool loop runner); consider extracting a shared helper or central check to avoid divergence of behavior over time.
- In `ToolTable.vue`, `getPermissionColor` and `getPermissionLabel` accept `permission: string` even though only `'admin' | 'everyone'` are valid; tightening the type and reusing the `require_admin` boolean directly would improve type-safety and reduce conversion logic.
- In the Web UI handler `handleUpdateToolPermission`, `tool.require_admin` is optimistically mutated before the request; to avoid intermediate inconsistent state in the UI, consider cloning/updating local state after a successful response instead of mutating the original object preemptively.

## Individual Comments

### Comment 1
<location path="astrbot/dashboard/routes/tools.py" line_range="579" />
<code_context>
+                    .__dict__
+                )
+
+            ok = self.tool_mgr.set_tool_require_admin(tool_name, bool(require_admin))
+            if ok:
+                return Response().ok(None, "Permission updated.").__dict__
</code_context>
<issue_to_address>
**🚨 issue (security):** Avoid using bool() coercion on `require_admin` to prevent accepting truthy strings

`bool(require_admin)` will treat any non-empty string (including `'false'` or `'0'`) as `True`, which can incorrectly grant or revoke admin permissions if a client sends a string. Instead, validate the type (e.g., `isinstance(require_admin, bool)`) or explicitly parse allowed values and reject anything else, rather than coercing.
</issue_to_address>

### Comment 2
<location path="astrbot/core/agent/runners/tool_loop_agent_runner.py" line_range="1063-1071" />
<code_context>
+                            getattr(_caller_event, "role", "?"),
+                            sender_id,
+                        )
+                        _append_tool_call_result(
+                            func_tool_id,
+                            f"error: Permission denied. "
+                            f"Tool '{func_tool_name}' requires admin privileges. "
+                            f"Your user ID is {sender_id}. "
+                            "Ask the AstrBot admin to grant access via "
+                            "WebUI → 管理行为 → 函数工具 → 权限列.",
+                        )
+                        continue
</code_context>
<issue_to_address>
**🚨 suggestion (security):** Reconsider exposing sender_id and hard-coded UI path in tool error message

This message currently exposes `sender_id` and a hard-coded Chinese navigation path. Depending on how `sender_id` maps to user data, returning it to the LLM may disclose unnecessary identifiers; it should likely be kept in logs only. Also, the UI path is language- and layout-specific and may not be valid across locales. Consider removing `sender_id` from the user-facing text and replacing the path with a generic, localized description of how to request access.

```suggestion
                        _append_tool_call_result(
                            func_tool_id,
                            "error: Permission denied. "
                            f"Tool '{func_tool_name}' requires admin privileges. "
                            "Please ask your AstrBot administrator to grant you "
                            "access to this tool through the appropriate "
                            "management interface.",
                        )
                        continue
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

.__dict__
)

ok = self.tool_mgr.set_tool_require_admin(tool_name, bool(require_admin))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚨 issue (security): Avoid using bool() coercion on require_admin to prevent accepting truthy strings

bool(require_admin) will treat any non-empty string (including 'false' or '0') as True, which can incorrectly grant or revoke admin permissions if a client sends a string. Instead, validate the type (e.g., isinstance(require_admin, bool)) or explicitly parse allowed values and reject anything else, rather than coercing.

Comment thread astrbot/core/agent/runners/tool_loop_agent_runner.py
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a permission management system for function tools, allowing specific tools to be restricted to admin users only. It includes backend enforcement to block execution and hide restricted tools from non-admin users, persistence of these settings, and WebUI support for configuring permissions. The review comments identify a critical security vulnerability where restoring permissions from a simple list can silently downgrade tools that default to admin-only in code to everyone-accessible. The reviewer suggests using a dictionary map to preserve code-defined defaults.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread astrbot/core/provider/func_tool_manager.py Outdated
Comment thread astrbot/core/provider/func_tool_manager.py Outdated
@lingyun14beta lingyun14beta marked this pull request as draft June 6, 2026 04:53
@lingyun14beta lingyun14beta reopened this Jun 6, 2026
@lingyun14beta
Copy link
Copy Markdown
Contributor Author

/gemini review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a role-based permission system for tools, allowing administrators to restrict specific tools to admin-only access. It includes backend enforcement, persistence of permissions, and a dashboard UI to toggle these settings. The review feedback highlights critical security issues where permissions are bypassed for tools passed directly as 'FunctionTool' instances, and when MCP servers are dynamically started without restoring permissions. Additionally, an improvement is suggested to clean up the persistent storage map when a tool's admin requirement is disabled.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread astrbot/core/provider/func_tool_manager.py
Comment thread astrbot/core/astr_agent_tool_exec.py
Comment thread astrbot/core/provider/func_tool_manager.py
@lingyun14beta
Copy link
Copy Markdown
Contributor Author

/gemini review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request implements a role-based permission system for tools, allowing administrators to restrict certain tools to admin-only access. It includes backend logic to hide restricted tools from non-admin users, block unauthorized tool execution, and persist permission settings, as well as frontend updates to manage these permissions via the dashboard. The review feedback identifies potential AttributeError risks when accessing the event object in tool_loop_agent_runner.py and astr_main_agent.py if the event is null, and suggests adding unit tests to cover the new permission management features.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread astrbot/core/agent/runners/tool_loop_agent_runner.py Outdated
Comment on lines +973 to +979
if getattr(tool, "require_admin", False):
logger.debug(
"Hiding tool '%s' from non-admin user (sender_id=%s).",
tool.name,
event.get_sender_id(),
)
continue
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

If event is None (e.g., in some unit tests or system-initiated runs), calling event.get_sender_id() will raise an AttributeError. We should use defensive programming to handle cases where event might be None.

Suggested change
if getattr(tool, "require_admin", False):
logger.debug(
"Hiding tool '%s' from non-admin user (sender_id=%s).",
tool.name,
event.get_sender_id(),
)
continue
if getattr(tool, "require_admin", False):
sender_id = event.get_sender_id() if event else "unknown"
logger.debug(
"Hiding tool '%s' from non-admin user (sender_id=%s).",
tool.name,
sender_id,
)
continue

return True
return False

def set_tool_require_admin(self, name: str, require: bool) -> bool:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The new tool permission functionality (setting, restoring, and checking require_admin permissions) should be accompanied by corresponding unit tests to ensure correctness and prevent regressions.

References
  1. New functionality, such as handling attachments, should be accompanied by corresponding unit tests.

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
@lingyun14beta
Copy link
Copy Markdown
Contributor Author

细细阅读了一下pr #8512 ,本pr目前存在同名工具冲突的问题:(

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:core The bug / feature is about astrbot's core, backend area:webui The bug / feature is about webui(dashboard) of astrbot. size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant