Files
opsxdb/server/internal/aitools/audit.go
T
logan 0b68c8344d feat(mcp): P0 只读 MCP tool runtime + opsxdb-mcp stdio
- aitools 共用 runtime:list/describe/schema/query/redis(纯只读,无写确认)
- 白名单 ~/.opsxdb/mcp.json;审计 mcp-audit.jsonl;复用 danger.go
- 桌面 connections 双写 ~/.opsxdb/connections.json(ox1. 解码)
- Cursor 配置示例与任务书验收勾选更新;写操作与 Agent UI 留 P1
2026-10-15 11:14:08 +08:00

57 lines
1.2 KiB
Go

package aitools
import (
"encoding/json"
"os"
"path/filepath"
"sync"
"time"
)
// AuditEntry MCP/Agent 工具审计;不含密码与大结果全文。 // Logan.Li
type AuditEntry struct {
Time string `json:"time"`
Tool string `json:"tool"`
ConnectionID string `json:"connection_id,omitempty"`
Mode string `json:"mode"`
OK bool `json:"ok"`
Summary string `json:"summary,omitempty"`
Error string `json:"error,omitempty"`
}
var auditMu sync.Mutex
func AuditPath() (string, error) {
dir, err := opsxdbDir()
if err != nil {
return "", err
}
return filepath.Join(dir, "logs", "mcp-audit.jsonl"), nil
}
// AppendAudit 追加一行 JSONL;失败静默(不影响工具主路径)。
func AppendAudit(e AuditEntry) {
if e.Time == "" {
e.Time = time.Now().Format(time.RFC3339)
}
path, err := AuditPath()
if err != nil {
return
}
auditMu.Lock()
defer auditMu.Unlock()
if err := os.MkdirAll(filepath.Dir(path), 0700); err != nil {
return
}
b, err := json.Marshal(e)
if err != nil {
return
}
f, err := os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0600)
if err != nil {
return
}
defer f.Close()
_, _ = f.Write(append(b, '\n'))
}