Files
Agent-System/internal/auth/bootstrap.go
T
weichenandCursor c7aba86376 fix(test): stabilize PG seed users and CI short test suite.
Reactivate dev seed users after auth PG tests, use unique session tokens, fix import guard and coordinator assertions, and skip flaky E2E in short mode; add pg_restore CI drill job.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-13 02:50:23 +00:00

140 lines
3.9 KiB
Go

package auth
import (
"context"
"fmt"
"github.com/jackc/pgx/v5/pgxpool"
"chat-agent-system/internal/config"
)
// BootstrapAdminFromConfig 确保配置的管理员账户在 PG 中存在且具备 role-admin。
func BootstrapAdminFromConfig(ctx context.Context, store AuthStore, cfg *config.Config) error {
if store == nil || cfg == nil {
return nil
}
adminUser := cfg.AdminUsername
adminPass := cfg.AdminPassword
if adminUser == "" {
adminUser = "admin"
}
if adminPass == "" {
return nil
}
existing, err := store.GetUserByUsername(ctx, adminUser)
if err == nil && existing != nil {
if existing.RoleID != "role-admin" {
_, _ = store.UpdateUserRole(ctx, existing.ID, "role-admin", "系统管理员")
}
if existing.PasswordHash == "" {
hash, hashErr := HashPassword(adminPass)
if hashErr != nil {
return hashErr
}
_, err = store.UpdateUserPassword(ctx, existing.ID, hash, false)
return err
}
return nil
}
hash, err := HashPassword(adminPass)
if err != nil {
return fmt.Errorf("bootstrap admin hash: %w", err)
}
_, err = store.CreateUser(ctx, &UserAccount{
Username: adminUser,
Name: "系统管理员",
PasswordHash: hash,
Status: StatusActive,
MustChangePassword: false,
RoleID: "role-admin",
Position: "系统管理员",
Department: "系统运维部",
EmployeeID: "SYS-000",
})
return err
}
// BootstrapDevSeedUsers 在 dev/test 环境补齐演示账号(与 MemoryStore 种子对齐)。
func BootstrapDevSeedUsers(ctx context.Context, store AuthStore, cfg *config.Config) error {
if store == nil || cfg == nil {
return nil
}
if cfg.Env != "dev" && cfg.Env != "test" && cfg.Env != "" {
return nil
}
seeds := []struct {
username string
name string
roleID string
position string
dept string
empID string
}{
{"zhanggong", "张工", "role-engineer", "方案工程师", "骨科耗材研发组", "RD-001"},
{"lizhuguan", "李主管", "role-tech-lead", "技术主管", "骨科耗材研发组", "RD-002"},
{"wangzong", "王总监", "role-director", "研发总监", "研发中心", "RD-003"},
{"guest", "访客", "role-guest", "待指派", "外协中心", "EXT-999"},
}
passHash, err := HashPassword("123456")
if err != nil {
return err
}
for _, su := range seeds {
if _, err := store.GetUserByUsername(ctx, su.username); err == nil {
continue
}
_, err := store.CreateUser(ctx, &UserAccount{
Username: su.username,
Name: su.name,
PasswordHash: passHash,
Status: StatusActive,
RoleID: su.roleID,
Position: su.position,
Department: su.dept,
EmployeeID: su.empID,
})
if err != nil {
return fmt.Errorf("seed user %s: %w", su.username, err)
}
}
return nil
}
// ReactivateDevSeedUsers 将 dev/test 演示账号恢复为 active(集成测试可能临时停用)。
func ReactivateDevSeedUsers(ctx context.Context, store AuthStore, cfg *config.Config) error {
if store == nil || cfg == nil {
return nil
}
if cfg.Env != "dev" && cfg.Env != "test" && cfg.Env != "" {
return nil
}
for _, username := range []string{"zhanggong", "lizhuguan", "wangzong", "guest"} {
user, err := store.GetUserByUsername(ctx, username)
if err != nil || user == nil {
continue
}
if user.Status != StatusActive {
if _, err := store.UpdateUserStatus(ctx, user.ID, StatusActive); err != nil {
return fmt.Errorf("reactivate %s: %w", username, err)
}
}
}
return nil
}
// BootstrapIAM 在 PG IAM 就绪后执行管理员与 dev 种子初始化。
func BootstrapIAM(ctx context.Context, pool *pgxpool.Pool, store AuthStore, cfg *config.Config) error {
if !IAMTablesReady(ctx, pool) {
return nil
}
if err := BootstrapAdminFromConfig(ctx, store, cfg); err != nil {
return err
}
if err := BootstrapDevSeedUsers(ctx, store, cfg); err != nil {
return err
}
return ReactivateDevSeedUsers(ctx, store, cfg)
}