Files
LLMGuardX Dev 58535fda7b 0.11.7: 代码审查查缺补漏(安全/并发/前端三轮审查修复)
安全:
- 渠道 webhook 入站强制令牌鉴权(恒定时间比较+统一文案),企微签名官方算法;
- 报表/概览/systemInfo 端点按 usage:read/audit:read/system:manage 授权;
- sso_error 固定错误码;个人渠道令牌仅请求头;工具出站 Dialer.Control 消除
  DNS rebinding TOCTOU;新增 channel:read/manage 权限;限流倍数上限 10。

并发/一致性:
- 任务上报单条条件 UPDATE 防重放双提交;认领回收过期 claimed 任务;
- 审批改先开通后落记录(幂等,无嵌套事务);聊天消息单事务落库;
- 会话列表校验 AuthVersion;吊销先 Del 后 SRem;删工具保护调用历史;
- rejected 冷却 24h;限流被拒补偿;maintenance 清理限流窗口。

前端/菜单:
- 修复 gatewayChildren late-append 导致 reports/tenants/channels 菜单不可见;
- 聊天改名 PUT 对齐;渠道编辑清空凭据防串写+启用开关;
- 聊天响应防串扰;报表本地时区日期。
2026-08-13 15:22:19 +08:00

59 lines
2.0 KiB
Go

package main
import (
"context"
"log/slog"
"os"
"os/signal"
"syscall"
"time"
"aigateway.local/core/internal/audit"
"aigateway.local/core/internal/platform/config"
"aigateway.local/core/internal/platform/database"
)
func main() {
logger := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelInfo}))
cfg, err := config.Load()
if err != nil {
logger.Error("invalid configuration", "error", err)
os.Exit(1)
}
if cfg.Database.URL == "" {
logger.Error("DATABASE_URL is required")
os.Exit(1)
}
ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
defer stop()
db, err := database.Open(ctx, cfg.Database)
if err != nil {
logger.Error("database initialization failed", "error", err)
os.Exit(1)
}
defer db.Close()
maintenance := audit.NewMaintenance(db, cfg.Audit.Retention, cfg.Audit.UsageRetention, cfg.Audit.TraceRetention, cfg.Audit.PartitionMonthsAhead)
ticker := time.NewTicker(cfg.Audit.MaintenanceInterval)
defer ticker.Stop()
for {
result, runErr := maintenance.Run(ctx, time.Now())
if runErr != nil && ctx.Err() == nil {
logger.Error("audit maintenance failed", "error", runErr)
} else if runErr == nil {
logger.Info("audit maintenance complete", "created_partitions", result.CreatedPartitions, "dropped_partitions", result.DroppedPartitions, "deleted_audit_rows", result.DeletedAuditRows, "deleted_usage_rows", result.DeletedUsageRows, "deleted_trace_rows", result.DeletedTraceRows)
}
// 清理工具限流固定窗口:保留 2 天,防止 tool_rate_usage 无限膨胀。
if tag, cleanupErr := db.Exec(ctx, `DELETE FROM gateway.tool_rate_usage WHERE window_start < clock_timestamp()-interval '2 days'`); cleanupErr != nil {
logger.Warn("tool rate window cleanup failed", "error", cleanupErr)
} else if tag.RowsAffected() > 0 {
logger.Info("tool rate windows cleaned", "rows", tag.RowsAffected())
}
select {
case <-ctx.Done():
logger.Info("maintenance worker stopped")
return
case <-ticker.C:
}
}
}