feat: Phase 6.2 宿主机安全操控 — 沙箱执行 + 文件系统隔离 + 进程管理

- host.Sandbox: 命令白名单 + 目录限制 + 超时控制 + 环境变量过滤
- host.Manager: 文件读写列表 + 系统信息查询 + 路径验证
- 3个新工具: host_exec (沙箱命令执行), host_file (文件操作), host_system (系统信息)
- 后台思考器自主工具策略已更新,允许安全使用主机工具
- host_exec 标记为高风险工具,受频率限制

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-23 22:23:45 +08:00
parent 313f41633a
commit 38b36fc5ad
5 changed files with 662 additions and 3 deletions
@@ -0,0 +1,214 @@
package tools
import (
"context"
"encoding/json"
"fmt"
"time"
"github.com/yourname/cyrene-ai/ai-core/internal/host"
)
// HostExecTool allows the AI to execute commands in a sandboxed environment.
type HostExecTool struct {
manager *host.Manager
}
// NewHostExecTool creates a new host exec tool.
func NewHostExecTool(manager *host.Manager) *HostExecTool {
return &HostExecTool{manager: manager}
}
func (t *HostExecTool) Definition() ToolDefinition {
return ToolDefinition{
Name: "host_exec",
Description: "在安全沙箱中执行系统命令。支持运行脚本、编译代码、管理文件等操作。超时默认30秒,最大300秒。",
Parameters: map[string]interface{}{
"type": "object",
"properties": map[string]interface{}{
"command": map[string]interface{}{
"type": "string",
"description": "要执行的命令,例如 'dir C:\\Projects' 或 'python script.py'",
},
"work_dir": map[string]interface{}{
"type": "string",
"description": "工作目录。不指定则使用默认目录。",
},
"timeout_sec": map[string]interface{}{
"type": "integer",
"description": "超时时间(秒),默认30秒,最大300秒。",
},
},
"required": []string{"command"},
},
}
}
func (t *HostExecTool) Execute(ctx context.Context, args map[string]interface{}) (*ToolResult, error) {
cmd, _ := args["command"].(string)
if cmd == "" {
return &ToolResult{
ToolName: "host_exec",
Success: false,
Error: "command 参数不能为空",
}, nil
}
workDir, _ := args["work_dir"].(string)
timeoutSec := 30
if v, ok := args["timeout_sec"].(float64); ok {
timeoutSec = int(v)
}
timeout := time.Duration(timeoutSec) * time.Second
result, err := t.manager.Exec(ctx, cmd, workDir, timeout)
if err != nil && result == nil {
return &ToolResult{
ToolName: "host_exec",
Success: false,
Error: err.Error(),
}, nil
}
data, _ := json.Marshal(map[string]interface{}{
"command": cmd,
"exit_code": result.ExitCode,
"duration": result.Duration,
"timed_out": result.TimedOut,
"stdout": result.Stdout,
"stderr": result.Stderr,
})
success := result.ExitCode == 0 && !result.TimedOut
return &ToolResult{
ToolName: "host_exec",
Success: success,
Data: string(data),
}, nil
}
// HostFileTool provides controlled file system access.
type HostFileTool struct {
manager *host.Manager
}
// NewHostFileTool creates a new host file tool.
func NewHostFileTool(manager *host.Manager) *HostFileTool {
return &HostFileTool{manager: manager}
}
func (t *HostFileTool) Definition() ToolDefinition {
return ToolDefinition{
Name: "host_file",
Description: "在允许的目录中读取、写入或列出文件。支持 read/write/list 三种操作。",
Parameters: map[string]interface{}{
"type": "object",
"properties": map[string]interface{}{
"action": map[string]interface{}{
"type": "string",
"description": "操作类型: read, write, list",
"enum": []string{"read", "write", "list"},
},
"path": map[string]interface{}{
"type": "string",
"description": "文件或目录路径",
},
"content": map[string]interface{}{
"type": "string",
"description": "写入内容 (仅 write 操作需要)",
},
},
"required": []string{"action", "path"},
},
}
}
func (t *HostFileTool) Execute(ctx context.Context, args map[string]interface{}) (*ToolResult, error) {
action, _ := args["action"].(string)
path, _ := args["path"].(string)
if action == "" || path == "" {
return &ToolResult{
ToolName: "host_file",
Success: false,
Error: "action 和 path 参数不能为空",
}, nil
}
switch action {
case "read":
content, err := t.manager.ReadFile(path, 1024*1024)
if err != nil {
return &ToolResult{ToolName: "host_file", Success: false, Error: err.Error()}, nil
}
data, _ := json.Marshal(map[string]interface{}{
"path": path,
"content": content,
"size": len(content),
})
return &ToolResult{ToolName: "host_file", Success: true, Data: string(data)}, nil
case "write":
content, _ := args["content"].(string)
if err := t.manager.WriteFile(path, content, 1024*1024); err != nil {
return &ToolResult{ToolName: "host_file", Success: false, Error: err.Error()}, nil
}
data, _ := json.Marshal(map[string]interface{}{
"path": path,
"written": len(content),
"status": "ok",
})
return &ToolResult{ToolName: "host_file", Success: true, Data: string(data)}, nil
case "list":
entries, err := t.manager.ListDir(path)
if err != nil {
return &ToolResult{ToolName: "host_file", Success: false, Error: err.Error()}, nil
}
data, _ := json.Marshal(map[string]interface{}{
"path": path,
"entries": entries,
"count": len(entries),
})
return &ToolResult{ToolName: "host_file", Success: true, Data: string(data)}, nil
default:
return &ToolResult{ToolName: "host_file", Success: false, Error: fmt.Sprintf("不支持的操作: %s", action)}, nil
}
}
// HostSystemTool provides system information.
type HostSystemTool struct {
manager *host.Manager
}
// NewHostSystemTool creates a new system info tool.
func NewHostSystemTool(manager *host.Manager) *HostSystemTool {
return &HostSystemTool{manager: manager}
}
func (t *HostSystemTool) Definition() ToolDefinition {
return ToolDefinition{
Name: "host_system",
Description: "获取主机系统信息,包括操作系统、CPU、内存等。",
Parameters: map[string]interface{}{
"type": "object",
"properties": map[string]interface{}{
"query": map[string]interface{}{
"type": "string",
"description": "查询类型: info(完整信息), memory(内存), cpu(CPU), disk(磁盘)",
"enum": []string{"info", "memory", "cpu", "disk"},
},
},
},
}
}
func (t *HostSystemTool) Execute(ctx context.Context, args map[string]interface{}) (*ToolResult, error) {
info := t.manager.SystemInfo()
data, _ := json.Marshal(info)
return &ToolResult{
ToolName: "host_system",
Success: true,
Data: string(data),
}, nil
}