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>
This commit is contained in:
@@ -5,6 +5,7 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -16,6 +17,34 @@ import (
|
||||
"github.com/sundynix/sundynix-shared/secrets"
|
||||
)
|
||||
|
||||
// AuditList: GET /api/v1/admin/audit?limit=&offset= —— 敏感操作审计流(倒序,供运维溯源)。
|
||||
func (h *Handler) AuditList(c *gin.Context) {
|
||||
limit, offset := 50, 0
|
||||
if v := c.Query("limit"); v != "" {
|
||||
if n, err := strconv.Atoi(v); err == nil {
|
||||
limit = n
|
||||
}
|
||||
}
|
||||
if v := c.Query("offset"); v != "" {
|
||||
if n, err := strconv.Atoi(v); err == nil {
|
||||
offset = n
|
||||
}
|
||||
}
|
||||
rows, err := h.db.ListAudit(c.Request.Context(), limit, offset)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadGateway, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
out := make([]gin.H, 0, len(rows))
|
||||
for _, a := range rows {
|
||||
out = append(out, gin.H{
|
||||
"id": a.ID, "actor": a.Actor, "action": a.Action, "route": a.Route,
|
||||
"path": a.Path, "status": a.Status, "ip": a.IP, "detail": a.Detail, "at": a.CreatedAt,
|
||||
})
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"logs": out})
|
||||
}
|
||||
|
||||
// AdminOverview: GET /api/v1/admin/overview —— 管理端系统级聚合(控制塔口径)。
|
||||
// 区别于 stats/overview(桌面端个人工作台):这里一律系统级——全平台用户/任务/评测/
|
||||
// 模型配置态/提示词控制面态/服务健康。Task/Eval 表无 owner 即全量;用户/KB/Doc 走全局计数。
|
||||
|
||||
Reference in New Issue
Block a user