feat(security): 启动时自动迁移并持久化JWT密钥

- 新增 security_secrets 表及 Ent schema 用于存储系统级密钥
- 启动阶段支持无 jwt.secret 配置并在数据库中自动生成持久化
- 在 Ent 初始化后补齐密钥并执行完整配置校验
- 增加并发与异常分支单元测试,覆盖密钥引导核心路径

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
yangjianbo
2026-02-12 11:41:20 +08:00
parent 6533a4647d
commit 6b36992d34
27 changed files with 3350 additions and 9 deletions

View File

@@ -5,6 +5,7 @@ package repository
import (
"context"
"database/sql"
"fmt"
"time"
"github.com/Wei-Shaw/sub2api/ent"
@@ -66,6 +67,18 @@ func InitEnt(cfg *config.Config) (*ent.Client, *sql.DB, error) {
// 创建 Ent 客户端,绑定到已配置的数据库驱动。
client := ent.NewClient(ent.Driver(drv))
// 启动阶段:从配置或数据库中确保系统密钥可用。
if err := ensureBootstrapSecrets(migrationCtx, client, cfg); err != nil {
_ = client.Close()
return nil, nil, err
}
// 在密钥补齐后执行完整配置校验,避免空 jwt.secret 导致服务运行时失败。
if err := cfg.Validate(); err != nil {
_ = client.Close()
return nil, nil, fmt.Errorf("validate config after secret bootstrap: %w", err)
}
// SIMPLE 模式:启动时补齐各平台默认分组。
// - anthropic/openai/gemini: 确保存在 <platform>-default
// - antigravity: 仅要求存在 >=2 个未软删除分组(用于 claude/gemini 混合调度场景)