第23章 添加工具系统与权限控制 —— Mini-Harness 的安全升级

上一篇我们从零构建了 Mini-Harness。本章我们添加工具系统与权限控制——提升安全性。

为什么需要权限控制

Mini-Harness 的安全风险

图表 代码
graph TB
    subgraph SecurityRisks["Mini-Harness 安全风险"]
        R1[无权限检查
所有操作自动执行] R2[危险命令执行
Bash可执行任意命令] R3[文件覆盖风险
Write可覆盖任意文件] R4[系统文件删除
可能删除关键文件] end style SecurityRisks fill:#FFE0E0
graph TB
    subgraph SecurityRisks["Mini-Harness 安全风险"]
        R1[无权限检查
所有操作自动执行] R2[危险命令执行
Bash可执行任意命令] R3[文件覆盖风险
Write可覆盖任意文件] R4[系统文件删除
可能删除关键文件] end style SecurityRisks fill:#FFE0E0
graph TB
    subgraph SecurityRisks["Mini-Harness 安全风险"]
        R1[无权限检查
所有操作自动执行] R2[危险命令执行
Bash可执行任意命令] R3[文件覆盖风险
Write可覆盖任意文件] R4[系统文件删除
可能删除关键文件] end style SecurityRisks fill:#FFE0E0
graph TB
    subgraph SecurityRisks["Mini-Harness 安全风险"]
        R1[无权限检查<br/>所有操作自动执行]
        R2[危险命令执行<br/>Bash可执行任意命令]
        R3[文件覆盖风险<br/>Write可覆盖任意文件]
        R4[系统文件删除<br/>可能删除关键文件]
    end
    
    style SecurityRisks fill:#FFE0E0
风险说明示例
无权限检查所有操作自动执行无需用户确认
危险命令执行Bash 可执行 rm -rf /系统崩溃
文件覆盖风险Write 可覆盖任意文件覆盖 .env 文件
系统文件删除可能删除关键系统文件删除 /bin/bash

权限控制的好处

图表 代码
graph TB
    subgraph PermissionBenefits["权限控制的好处"]
        B1[安全保护
危险操作需审批] B2[用户控制
用户决定是否执行] B3[风险降低
防止误操作] B4[信任建立
用户信任Agent] end style PermissionBenefits fill:#E0FFE0
graph TB
    subgraph PermissionBenefits["权限控制的好处"]
        B1[安全保护
危险操作需审批] B2[用户控制
用户决定是否执行] B3[风险降低
防止误操作] B4[信任建立
用户信任Agent] end style PermissionBenefits fill:#E0FFE0
graph TB
    subgraph PermissionBenefits["权限控制的好处"]
        B1[安全保护
危险操作需审批] B2[用户控制
用户决定是否执行] B3[风险降低
防止误操作] B4[信任建立
用户信任Agent] end style PermissionBenefits fill:#E0FFE0
graph TB
    subgraph PermissionBenefits["权限控制的好处"]
        B1[安全保护<br/>危险操作需审批]
        B2[用户控制<br/>用户决定是否执行]
        B3[风险降低<br/>防止误操作]
        B4[信任建立<br/>用户信任Agent]
    end
    
    style PermissionBenefits fill:#E0FFE0
好处说明价值
安全保护危险操作需用户审批系统安全
用户控制用户决定是否执行用户主导
风险降低防止误操作防止损失
信任建立用户信任 Agent期使用

权限系统设计

三级权限模式

图表 代码
graph LR
    A[工具调用请求] --> B{权限检查}
    B -->|deny| C[❌ 禁止执行]
    B -->|ask| D[⚠️ 请求审批]
    B -->|allow| E[✅ 自动执行]
    
    D -->|批准| E
    D -->|拒绝| C
graph LR
    A[工具调用请求] --> B{权限检查}
    B -->|deny| C[❌ 禁止执行]
    B -->|ask| D[⚠️ 请求审批]
    B -->|allow| E[✅ 自动执行]
    
    D -->|批准| E
    D -->|拒绝| C
graph LR
    A[工具调用请求] --> B{权限检查}
    B -->|deny| C[❌ 禁止执行]
    B -->|ask| D[⚠️ 请求审批]
    B -->|allow| E[✅ 自动执行]
    
    D -->|批准| E
    D -->|拒绝| C
graph LR
    A[工具调用请求] --> B{权限检查}
    B -->|deny| C[❌ 禁止执行]
    B -->|ask| D[⚠️ 请求审批]
    B -->|allow| E[✅ 自动执行]
    
    D -->|批准| E
    D -->|拒绝| C
权限模式行为适用场景示例
deny禁止执行,返回错误极危险操作rm -rf /
ask请求用户审批,等待确认中等风险git push
allow自动执行,无需用户干预安全操作Read 文件

权限规则配置

{
  "permissions": {
    "deny": [
      {"tool": "Bash", "command": "rm -rf /"},
      {"tool": "Bash", "command": "sudo"},
      {"tool": "Read", "file_path": ".env"}
    ],
    "ask": [
      {"tool": "Bash", "command": "git push"},
      {"tool": "Bash", "command": "npm install"},
      {"tool": "Write"},
      {"tool": "Edit"}
    ],
    "allow": [
      {"tool": "Read"},
      {"tool": "Glob"},
      {"tool": "Grep"}
    ]
  }
}

Step 1:权限检查模块

实现目标

一句话定义:检查工具调用是否匹配 deny/ask/allow 规则。

图表 代码
graph LR
    ToolCall[工具调用] --> MatchDeny{匹配 deny?}
    MatchDeny -->|匹配| Deny[返回 deny]
    MatchDeny -->|不匹配| MatchAsk{匹配 ask?}
    MatchAsk -->|匹配| Ask[返回 ask]
    MatchAsk -->|不匹配| MatchAllow{匹配 allow?}
    MatchAllow -->|匹配| Allow[返回 allow]
    MatchAllow -->|不匹配| Default[默认 ask]
graph LR
    ToolCall[工具调用] --> MatchDeny{匹配 deny?}
    MatchDeny -->|匹配| Deny[返回 deny]
    MatchDeny -->|不匹配| MatchAsk{匹配 ask?}
    MatchAsk -->|匹配| Ask[返回 ask]
    MatchAsk -->|不匹配| MatchAllow{匹配 allow?}
    MatchAllow -->|匹配| Allow[返回 allow]
    MatchAllow -->|不匹配| Default[默认 ask]
graph LR
    ToolCall[工具调用] --> MatchDeny{匹配 deny?}
    MatchDeny -->|匹配| Deny[返回 deny]
    MatchDeny -->|不匹配| MatchAsk{匹配 ask?}
    MatchAsk -->|匹配| Ask[返回 ask]
    MatchAsk -->|不匹配| MatchAllow{匹配 allow?}
    MatchAllow -->|匹配| Allow[返回 allow]
    MatchAllow -->|不匹配| Default[默认 ask]
graph LR
    ToolCall[工具调用] --> MatchDeny{匹配 deny?}
    MatchDeny -->|匹配| Deny[返回 deny]
    MatchDeny -->|不匹配| MatchAsk{匹配 ask?}
    MatchAsk -->|匹配| Ask[返回 ask]
    MatchAsk -->|不匹配| MatchAllow{匹配 allow?}
    MatchAllow -->|匹配| Allow[返回 allow]
    MatchAllow -->|不匹配| Default[默认 ask]

实现代码

# 权限检查模块

import re

class PermissionSystem:
    """
    权限检查系统
    """
    
    def __init__(self, config=None):
        """
        初始化权限系统
        
        参数:
            config: 权限规则配置
        """
        self.config = config or self.default_config()
    
    def default_config(self):
        """默认权限配置"""
        return {
            "deny": [
                {"tool": "Bash", "command": "rm -rf /"},
                {"tool": "Bash", "command": "rm -rf /*"},
                {"tool": "Bash", "command": "sudo"},
                {"tool": "Read", "file_path": ".env"},
                {"tool": "Read", "file_path": "*credentials*"}
            ],
            "ask": [
                {"tool": "Bash", "command": "git push"},
                {"tool": "Bash", "command": "npm install"},
                {"tool": "Bash", "command": "pip install"},
                {"tool": "Write"},
                {"tool": "Edit"}
            ],
            "allow": [
                {"tool": "Read"},
                {"tool": "Glob"},
                {"tool": "Grep"}
            ]
        }
    
    def check_permission(self, tool_name, tool_params):
        """
        检查权限
        
        参数:
            tool_name: 工具名称
            tool_params: 工具参数
        
        返回:
            permission: "deny" / "ask" / "allow"
            reason: 原因说明
        """
        # 1. 检查 deny 规则
        for rule in self.config["deny"]:
            if self.match_rule(tool_name, tool_params, rule):
                return "deny", rule
        
        # 2. 检查 ask 规则
        for rule in self.config["ask"]:
            if self.match_rule(tool_name, tool_params, rule):
                return "ask", rule
        
        # 3. 检查 allow 规则
        for rule in self.config["allow"]:
            if self.match_rule(tool_name, tool_params, rule):
                return "allow", None
        
        # 4. 无匹配时默认 ask(保守策略)
        return "ask", {"reason": "默认需要审批"}
    
    def match_rule(self, tool_name, tool_params, rule):
        """
        匹配规则
        
        参数:
            tool_name: 工具名称
            tool_params: 工具参数
            rule: 权限规则
        
        返回:
            matched: 是否匹配
        """
        # 1. 工具名称匹配
        if rule.get("tool") and rule["tool"] != tool_name:
            return False
        
        # 2. 命令匹配(Bash 工具)
        if rule.get("command") and tool_name == "Bash":
            command = tool_params.get("command", "")
            # 模式匹配(支持通配符)
            if not self.pattern_match(command, rule["command"]):
                return False
        
        # 3. 文件路径匹配(Read/Write/Edit)
        if rule.get("file_path") and tool_name in ["Read", "Write", "Edit"]:
            file_path = tool_params.get("file_path", "")
            # 模式匹配(支持通配符)
            if not self.pattern_match(file_path, rule["file_path"]):
                return False
        
        return True
    
    def pattern_match(self, value, pattern):
        """
        模式匹配(支持通配符)
        
        参数:
            value: 实际值
            pattern: 匹配模式
        
        返回:
            matched: 是否匹配
        """
        # 转换通配符为正则
        regex_pattern = pattern.replace("*", ".*")
        regex_pattern = regex_pattern.replace("?", ".")
        
        # 正则匹配
        return re.match(regex_pattern, value) is not None


# 测试权限检查
def test_permission_system():
    perm = PermissionSystem()
    
    # 测试 deny
    result = perm.check_permission("Bash", {"command": "rm -rf /"})
    print(f"rm -rf /: {result}")
    
    # 测试 ask
    result = perm.check_permission("Bash", {"command": "git push"})
    print(f"git push: {result}")
    
    # 测试 allow
    result = perm.check_permission("Read", {"file_path": "app.ts"})
    print(f"Read app.ts: {result}")
    
    # 测试默认 ask
    result = perm.check_permission("Bash", {"command": "ls -la"})
    print(f"ls -la: {result}")


# 运行测试
test_permission_system()

测试输出

rm -rf /: ('deny', {'tool': 'Bash', 'command': 'rm -rf /'})
git push: ('ask', {'tool': 'Bash', 'command': 'git push'})
Read app.ts: ('allow', None)
ls -la: ('ask', {'reason': '默认需要审批'})

Step 2:用户审批模块

实现目标

一句话定义:ask 权限触发用户审批,等待用户确认。

图表 代码
graph LR
    Ask[触发 ask] --> Pause[暂停执行]
    Pause --> Prompt[提示用户]
    Prompt --> Wait{等待响应}
    Wait -->|批准| Approve[批准执行]
    Wait -->|拒绝| Reject[拒绝执行]
    
    Approve --> Execute[执行工具]
    Reject --> Return[返回拒绝信息]
graph LR
    Ask[触发 ask] --> Pause[暂停执行]
    Pause --> Prompt[提示用户]
    Prompt --> Wait{等待响应}
    Wait -->|批准| Approve[批准执行]
    Wait -->|拒绝| Reject[拒绝执行]
    
    Approve --> Execute[执行工具]
    Reject --> Return[返回拒绝信息]
graph LR
    Ask[触发 ask] --> Pause[暂停执行]
    Pause --> Prompt[提示用户]
    Prompt --> Wait{等待响应}
    Wait -->|批准| Approve[批准执行]
    Wait -->|拒绝| Reject[拒绝执行]
    
    Approve --> Execute[执行工具]
    Reject --> Return[返回拒绝信息]
graph LR
    Ask[触发 ask] --> Pause[暂停执行]
    Pause --> Prompt[提示用户]
    Prompt --> Wait{等待响应}
    Wait -->|批准| Approve[批准执行]
    Wait -->|拒绝| Reject[拒绝执行]
    
    Approve --> Execute[执行工具]
    Reject --> Return[返回拒绝信息]

实现代码

# 用户审批模块

class ApprovalSystem:
    """
    用户审批系统
    """
    
    def __init__(self):
        self.pending_requests = []
    
    def request_approval(self, tool_name, tool_params, reason):
        """
        请求用户审批
        
        参数:
            tool_name: 工具名称
            tool_params: 工具参数
            reason: 原因
        
        返回:
            approved: 是否批准
        """
        # 显示审批提示
        prompt = self.format_approval_prompt(tool_name, tool_params, reason)
        
        print(prompt)
        
        # 等待用户输入
        response = input("是否批准? (y/n): ").strip().lower()
        
        approved = response == 'y'
        
        return approved
    
    def format_approval_prompt(self, tool_name, tool_params, reason):
        """
        格式化审批提示
        
        参数:
            tool_name: 工具名称
            tool_params: 工具参数
            reason: 原因
        
        返回:
            prompt: 审批提示文本
        """
        reason_text = reason.get("reason", reason.get("command", "需要审批"))
        
        prompt = f"""
⚠️ 权限审批请求

工具: {tool_name}
参数: {self.format_params(tool_params)}
原因: {reason_text}

是否批准执行?
[y] 批准  [n] 拒绝
"""
        
        return prompt
    
    def format_params(self, params):
        """格式化参数"""
        if not params:
            return "无参数"
        
        formatted = []
        for key, value in params.items():
            if len(str(value)) > 50:
                value = str(value)[:50] + "..."
            formatted.append(f"{key}: {value}")
        
        return "\n    " + "\n    ".join(formatted)


# 测试审批系统
def test_approval_system():
    approval = ApprovalSystem()
    
    # 模拟请求审批
    approved = approval.request_approval(
        "Bash",
        {"command": "git push origin main"},
        {"tool": "Bash", "command": "git push"}
    )
    
    print(f"用户响应: {approved}")


# 运行测试(实际交互)
# test_approval_system()

审批提示示例

⚠️ 权限审批请求

工具: Bash
参数: 
    command: git push origin main
原因: git push

是否批准执行?
[y] 批准  [n] 拒绝

Step 3:集成到 Mini-Harness

完整实现

# Mini-Harness + 权限控制完整实现

import os
import subprocess
import re

class MiniHarnessWithPermissions:
    """
    Mini-Harness + 权限控制
    """
    
    def __init__(self, permission_config=None):
        """
        初始化
        
        参数:
            permission_config: 权限配置
        """
        self.system_prompt = self.default_system_prompt()
        self.tools = self.create_tools()
        self.permission_system = PermissionSystem(permission_config)
        self.approval_system = ApprovalSystem()
        self.state = None
    
    def default_system_prompt(self):
        """默认 System Prompt"""
        return """
你是代码助手 Agent。你可以使用以下工具:

工具列表:
- Read: 读取文件(参数:file_path)
- Write: 写入文件(参数:file_path, content)
- Edit: 编辑文件(参数:file_path, old_string, new_string)
- Bash: 执行命令(参数:command)
- Glob: 搜索文件(参数:pattern)
- Grep: 搜索内容(参数:pattern, path)

约束:
- 每次只调用一个工具
- 工具调用后等待结果
- 完成任务后返回 end_turn
"""
    
    def create_tools(self):
        """创建工具映射"""
        return {
            "Read": self.tool_read,
            "Write": self.tool_write,
            "Edit": self.tool_edit,
            "Bash": self.tool_bash,
            "Glob": self.tool_glob,
            "Grep": self.tool_grep
        }
    
    # 工具实现(略,与上一篇相同)
    
    def tool_read(self, params):
        """Read 工具"""
        file_path = params.get("file_path")
        if not file_path:
            return "错误:缺少 file_path 参数"
        if not os.path.exists(file_path):
            return f"错误:文件 {file_path} 不存在"
        try:
            with open(file_path, 'r', encoding='utf-8') as f:
                content = f.read()
            return f"文件内容:\n{content}"
        except Exception as e:
            return f"错误:读取文件失败 - {str(e)}"
    
    def tool_write(self, params):
        """Write 工具"""
        file_path = params.get("file_path")
        content = params.get("content")
        if not file_path or not content:
            return "错误:缺少 file_path 或 content 参数"
        try:
            os.makedirs(os.path.dirname(file_path), exist_ok=True)
            with open(file_path, 'w', encoding='utf-8') as f:
                f.write(content)
            return f"成功:文件 {file_path} 已写入"
        except Exception as e:
            return f"错误:写入文件失败 - {str(e)}"
    
    def tool_edit(self, params):
        """Edit 工具"""
        file_path = params.get("file_path")
        old_string = params.get("old_string")
        new_string = params.get("new_string")
        
        if not file_path or not old_string or not new_string:
            return "错误:缺少必要参数"
        
        try:
            with open(file_path, 'r', encoding='utf-8') as f:
                content = f.read()
            
            if old_string not in content:
                return "错误:old_string 未找到"
            
            # 替换(简单实现,只替换第一个匹配)
            new_content = content.replace(old_string, new_string, 1)
            
            with open(file_path, 'w', encoding='utf-8') as f:
                f.write(new_content)
            
            return f"成功:文件 {file_path} 已编辑"
        except Exception as e:
            return f"错误:编辑文件失败 - {str(e)}"
    
    def tool_bash(self, params):
        """Bash 工具"""
        command = params.get("command")
        if not command:
            return "错误:缺少 command 参数"
        try:
            result = subprocess.run(
                command,
                shell=True,
                capture_output=True,
                text=True,
                timeout=30
            )
            if result.returncode == 0:
                return f"命令输出:\n{result.stdout}"
            else:
                return f"错误:命令执行失败\n{result.stderr}"
        except subprocess.TimeoutExpired:
            return "错误:命令执行超时(30秒)"
        except Exception as e:
            return f"错误:执行命令失败 - {str(e)}"
    
    def tool_glob(self, params):
        """Glob 工具"""
        pattern = params.get("pattern")
        if not pattern:
            return "错误:缺少 pattern 参数"
        import glob
        files = glob.glob(pattern, recursive=True)
        return f"匹配文件:\n{chr(10).join(files)}"
    
    def tool_grep(self, params):
        """Grep 工具"""
        pattern = params.get("pattern")
        path = params.get("path", ".")
        if not pattern:
            return "错误:缺少 pattern 参数"
        try:
            result = subprocess.run(
                f"grep -r {pattern} {path}",
                shell=True,
                capture_output=True,
                text=True
            )
            return f"搜索结果:\n{result.stdout}"
        except Exception as e:
            return f"错误:搜索失败 - {str(e)}"
    
    def initialize(self, prompt):
        """初始化"""
        self.state = {
            "messages": [
                {"role": "system", "content": self.system_prompt},
                {"role": "user", "content": prompt}
            ],
            "loops": 0,
            "tool_calls": 0,
            "denied": 0,
            "approved": 0
        }
        return self.state
    
    def agent_loop(self, model_api):
        """Agent Loop + 权限检查"""
        while True:
            messages = self.state["messages"]
            
            # Model 推理
            response = model_api(messages)
            
            stop_reason = response.get("stop_reason", "end_turn")
            
            if stop_reason == "end_turn":
                return response
            
            elif stop_reason == "tool_use":
                tool_use = self.extract_tool_use(response)
                
                tool_name = tool_use["name"]
                tool_params = tool_use["parameters"]
                
                # 权限检查
                permission, reason = self.permission_system.check_permission(
                    tool_name, tool_params
                )
                
                if permission == "deny":
                    # 禁止执行
                    tool_result = f"权限拒绝:{reason}"
                    self.state["denied"] += 1
                
                elif permission == "ask":
                    # 请求审批
                    approved = self.approval_system.request_approval(
                        tool_name, tool_params, reason
                    )
                    
                    if approved:
                        # 执行工具
                        tool_result = self.tools[tool_name](tool_params)
                        self.state["approved"] += 1
                    else:
                        # 拒绝执行
                        tool_result = "用户拒绝执行"
                        self.state["denied"] += 1
                
                elif permission == "allow":
                    # 自动执行
                    tool_result = self.tools[tool_name](tool_params)
                
                else:
                    # 默认 ask
                    approved = self.approval_system.request_approval(
                        tool_name, tool_params, {"reason": "默认需要审批"}
                    )
                    
                    if approved:
                        tool_result = self.tools[tool_name](tool_params)
                    else:
                        tool_result = "用户拒绝执行"
                
                # 追加结果
                self.state["messages"].append({
                    "role": "assistant",
                    "content": response["content"]
                })
                
                self.state["messages"].append({
                    "role": "user",
                    "content": tool_result
                })
                
                # 更新状态
                self.state["loops"] += 1
                self.state["tool_calls"] += 1
                
                # 循环限制
                if self.state["loops"] > 20:
                    print("警告:循环超过 20 次,强制结束")
                    return response
    
    def extract_tool_use(self, response):
        """提取 tool_use"""
        content = response.get("content", "")
        
        import json
        
        json_match = re.search(r'\{[^}]+\}', content)
        if json_match:
            tool_info = json.loads(json_match.group())
            return {
                "name": tool_info.get("tool", "unknown"),
                "parameters": tool_info.get("params", {})
            }
        
        return {"name": "unknown", "parameters": {}}
    
    def run(self, prompt, model_api):
        """完整运行"""
        self.initialize(prompt)
        response = self.agent_loop(model_api)
        
        return {
            "response": response,
            "loops": self.state["loops"],
            "tool_calls": self.state["tool_calls"],
            "denied": self.state["denied"],
            "approved": self.state["approved"],
            "messages": self.state["messages"]
        }


# PermissionSystem 和 ApprovalSystem 类(前面已定义)

# 测试 Mini-Harness + 权限控制
def test_mini_harness_with_permissions():
    harness = MiniHarnessWithPermissions()
    
    prompt = "执行 git push 命令"
    
    # 模拟 model_api(返回 git push 工具调用)
    def mock_model_api(messages):
        return {
            "content": "决定执行 git push。{\"tool\": \"Bash\", \"params\": {\"command\": \"git push\"}}",
            "stop_reason": "tool_use"
        }
    
    result = harness.run(prompt, mock_model_api)
    
    print("运行完成:")
    print(f"- 循环次数: {result['loops']}")
    print(f"- 工具调用次数: {result['tool_calls']}")
    print(f"- 拒绝次数: {result['denied']}")
    print(f"- 批准次数: {result['approved']}")


# 运行测试
test_mini_harness_with_permissions()

权限系统的最佳实践

推荐配置

保守配置(推荐生产环境):

{
  "deny": [
    {"tool": "Bash", "command": "rm -rf /"},
    {"tool": "Bash", "command": "rm -rf /*"},
    {"tool": "Bash", "command": "sudo"},
    {"tool": "Bash", "command": "chmod 777"},
    {"tool": "Read", "file_path": ".env"},
    {"tool": "Read", "file_path": "*credentials*"},
    {"tool": "Read", "file_path": "*secret*"},
    {"tool": "Write", "file_path": "/bin/*"},
    {"tool": "Write", "file_path": "/usr/*"}
  ],
  "ask": [
    {"tool": "Bash", "command": "git push"},
    {"tool": "Bash", "command": "npm install"},
    {"tool": "Bash", "command": "pip install"},
    {"tool": "Bash", "command": "rm"},
    {"tool": "Write"},
    {"tool": "Edit"}
  ],
  "allow": [
    {"tool": "Read"},
    {"tool": "Glob"},
    {"tool": "Grep"},
    {"tool": "Bash", "command": "ls"},
    {"tool": "Bash", "command": "cat"}
  ]
}

权限设计原则

图表 代码
graph TB
    subgraph DesignPrinciples["权限设计原则"]
        D1[默认 deny
未知操作默认禁止] D2[最小权限
只授予必要权限] D3[信任边界
区分可信/不可信] D4[透明审批
审批信息清晰] end
graph TB
    subgraph DesignPrinciples["权限设计原则"]
        D1[默认 deny
未知操作默认禁止] D2[最小权限
只授予必要权限] D3[信任边界
区分可信/不可信] D4[透明审批
审批信息清晰] end
graph TB
    subgraph DesignPrinciples["权限设计原则"]
        D1[默认 deny
未知操作默认禁止] D2[最小权限
只授予必要权限] D3[信任边界
区分可信/不可信] D4[透明审批
审批信息清晰] end
graph TB
    subgraph DesignPrinciples["权限设计原则"]
        D1[默认 deny<br/>未知操作默认禁止]
        D2[最小权限<br/>只授予必要权限]
        D3[信任边界<br/>区分可信/不可信]
        D4[透明审批<br/>审批信息清晰]
    end
原则说明实现方式
默认 deny未知操作默认禁止无匹配时返回 ask
最小权限只授予必要权限精确匹配规则
信任边界区分可信/不可信操作分级权限模式
透明审批审批信息清晰完整显示工具、参数、原因

权限系统的扩展方向

扩展功能

扩展功能说明实现难度
批量审批连续多个 ask 批量审批⭐⭐ 中等
权限审计记录所有权限决策⭐ 简单
配置级别全局/项目/临时配置⭐⭐ 中等
动态规则根据上下文调整规则⭐⭐⭐ 复杂

本章小结

  • 权限控制必要性:Mini-Harness 无安全检查,存在危险风险
  • 三级权限模式:deny(禁止)、ask(审批)、allow(自动)
  • 权限检查模块:检查工具调用是否匹配 deny/ask/allow 规则
  • 用户审批模块:ask 权限触发用户审批,等待确认
  • 集成到 Mini-Harness:在工具执行前插入权限检查
  • 匹配规则:工具名称、命令模式、文件路径模式匹配
  • 审批流程:触发 ask → 暂停执行 → 提示用户 → 等待响应 → 执行或拒绝
  • 推荐配置:保守配置适合生产环境,deny 极危险操作,ask 中等风险,allow 安全操作
  • 设计原则:默认 deny、最小权限、信任边界、透明审批

预告:下一篇我们添加 MCP 与多智能体支持,扩展 Mini-Harness 能力。



相关内容

如果这篇文章对你有帮助,欢迎请我喝杯咖啡 ☕
Cygnus Yang 支付宝支付宝
Cygnus Yang 微信微信