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) } } }