Files
Blizzard 466959d3c3 fix: 静默吞错横扫 —— 数据落库/配置广播/审计失败不再无声
把检索链路那次的做法推到同类位置。判据是"丢了这个 error 的代价",只改代价
高的,不动刻意的 fire-and-forget。

改(丢了就是数据永久丢失或行为不可解释):
  - task_handler: 任务**输出**与**执行轨迹**的收尾落库。这是唯一的持久副本
    (Redis 流 10min TTL),失败则永远无法复盘,界面上只显示"这次运行没有
    轨迹"。轨迹的 json.Marshal 失败分支同样是静默跳过,一并补上。
  - admin.broadcastActive: 模型配置热更新广播。失败 = dispatcher/mcp-go 仍用
    旧配置,症状是"控制台改了模型却不生效",而操作者这边一切正常——正是今天
    排查半天的那类问题。
  - middleware/audit: 审计留痕写入。不阻断主流程是对的(业务已完成),但静默
    失败意味着敏感操作没有记录,且没人知道记录缺了,这是合规缺口。

不改(确认过是合理的):
  - dispatcher 的 PublishToken/PublishExec:往前端推流,丢一帧是 UI 瑕疵,
    且按 token 打日志会刷屏;
  - 计量回写 PublishUsage:本来就检查 error 并打日志,钱的路径是干净的。

另修一处误导文案:任务下钻的轨迹空态原本把原因说死为"早于该功能上线",
现在"落库失败"也是已知原因,文案改为并列并指向日志里的 [task] 告警。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 15:49:13 +08:00

46 lines
1.4 KiB
Go

package middleware
import (
"context"
"log"
"time"
"github.com/gin-gonic/gin"
"github.com/sundynix/sundynix-gateway/internal/store"
)
// Audit 记录敏感操作留痕:仅对变更类请求(POST/PUT/DELETE)在收尾时 best-effort 落库。
// 挂在受保护/管理组上即可自动覆盖模型/密钥/prompt/审批等变更,无需在每个 handler 里手写。
// 写库用独立超时 context(不受请求取消影响),失败静默——审计不能拖垮主流程。
func Audit(db *store.Postgres) gin.HandlerFunc {
return func(c *gin.Context) {
c.Next() // 先跑 handler,拿到最终状态码
switch c.Request.Method {
case "POST", "PUT", "DELETE", "PATCH":
default:
return // 只审计变更类操作
}
actor, _ := c.Get(CtxUserID)
uid, _ := actor.(string)
entry := &store.AuditLog{
Actor: uid,
Action: c.Request.Method,
Route: c.FullPath(),
Path: c.Request.URL.Path,
Status: c.Writer.Status(),
IP: c.ClientIP(),
}
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
// best-effort:审计失败不阻断主流程(业务已经做完了),但必须留痕 ——
// 静默失败意味着敏感操作没有记录,而没人知道记录缺了。
if err := db.AppendAudit(ctx, entry); err != nil {
log.Printf("[audit] ⚠️ 审计留痕写入失败 actor=%s %s %s: %v", entry.Actor, entry.Action, entry.Path, err)
}
}
}