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:
Blizzard
2026-07-02 09:19:52 +08:00
parent 30e80c0eed
commit 16c67dcb4f
7 changed files with 122 additions and 9 deletions
+27
View File
@@ -0,0 +1,27 @@
package store
import "context"
// AppendAudit 追加一条审计留痕(best-effort:审计失败不应影响主流程,调用方忽略返回)。
func (p *Postgres) AppendAudit(ctx context.Context, a *AuditLog) error {
if p.db == nil || a == nil {
return errStoreDisabled
}
return p.db.WithContext(ctx).Create(a).Error
}
// ListAudit 倒序列出审计留痕(管理端审计流;limit 限流、offset 翻页)。
func (p *Postgres) ListAudit(ctx context.Context, limit, offset int) ([]AuditLog, error) {
if p.db == nil {
return nil, errStoreDisabled
}
if limit <= 0 || limit > 200 {
limit = 50
}
if offset < 0 {
offset = 0
}
var out []AuditLog
err := p.db.WithContext(ctx).Order("created_at desc").Limit(limit).Offset(offset).Find(&out).Error
return out, err
}
+15
View File
@@ -42,3 +42,18 @@ type Eval struct {
}
func (Eval) TableName() string { return "sundynix_eval" }
// AuditLog 是一条敏感操作留痕(改模型/密钥/激活 prompt/审批 等)。
// 由 Audit 中间件在请求收尾时 best-effort 写入;只增不改,供运维溯源。
type AuditLog struct {
BaseModel
Actor string `gorm:"size:64;index"` // 操作者 uid(未登录/系统留空)
Action string `gorm:"size:8"` // HTTP 方法:POST / PUT / DELETE
Route string `gorm:"size:128"` // 路由模式,如 /api/v1/admin/models/:id
Path string `gorm:"size:256"` // 实际请求路径
Status int // HTTP 响应状态码
IP string `gorm:"size:64"`
Detail string `gorm:"type:text"` // 备注(可选,如目标名/关键参数)
}
func (AuditLog) TableName() string { return "sundynix_audit_log" }
+1 -1
View File
@@ -66,7 +66,7 @@ func OpenPostgres(dsn string) *Postgres {
migrateLegacyIntIDs(db)
migrateDocLinkToID(db)
if err := db.AutoMigrate(&User{}, &Task{}, &Eval{}, &LLMModel{}, &KB{}, &Doc{}, &Agent{}, &DocLink{}, &Pricing{}, &Prompt{}); err != nil {
if err := db.AutoMigrate(&User{}, &Task{}, &Eval{}, &LLMModel{}, &KB{}, &Doc{}, &Agent{}, &DocLink{}, &Pricing{}, &Prompt{}, &AuditLog{}); err != nil {
log.Printf("[store] postgres AutoMigrate 失败,降级运行: %v", err)
return &Postgres{}
}