Files
Blizzard 16c67dcb4f feat(gateway): 敏感操作审计日志(T4.B)
- store.AuditLog 表(sundynix_audit_log) + AppendAudit/ListAudit
- middleware.Audit(db):只审计变更类(POST/PUT/DELETE/PATCH),收尾 best-effort
  落库(独立超时 ctx,失败静默不拖垮主流程);挂管理组 + prompt 激活/撤销 + HITL 审批
- GET /api/v1/admin/audit:倒序审计流(limit/offset 翻页)
- live:PUT pricing / POST prompts/deactivate 留痕(actor/path/status/ip),GET 不记
- DEPTH_ROADMAP T4.B:overview + audit 打勾

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 09:19:52 +08:00

41 lines
1.1 KiB
Go

package middleware
import (
"context"
"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()
_ = db.AppendAudit(ctx, entry)
}
}