58535fda7b
安全: - 渠道 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 对齐;渠道编辑清空凭据防串写+启用开关; - 聊天响应防串扰;报表本地时区日期。
59 lines
2.0 KiB
Go
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:
|
|
}
|
|
}
|
|
}
|