package main import ( "baron-sso-backend/internal/domain" "baron-sso-backend/internal/service" "context" "flag" "fmt" "log" ) func main() { dryRun := flag.Bool("dry-run", true, "변경 대상만 출력하고 Kratos identity를 수정하지 않습니다") maintenanceWindow := flag.Bool("maintenance-window", false, "승인된 정비 시간에만 실제 변경을 허용합니다") markMirrorStale := flag.Bool("mark-mirror-stale", false, "실행 전 Redis identity mirror를 stale로 표시했음을 확인합니다") flag.Parse() if !*dryRun && (!*maintenanceWindow || !*markMirrorStale) { log.Fatal("refusing to update Kratos identities: pass --dry-run=false --maintenance-window --mark-mirror-stale after marking identity mirror stale") } kratosAdmin := service.NewKratosAdminService() ctx := context.Background() identities, err := kratosAdmin.ListIdentities(ctx) if err != nil { log.Fatalf("Failed to list identities: %v", err) } count := 0 for _, id := range identities { traits := id.Traits changed := false if r, ok := traits["role"].(string); ok { norm := domain.NormalizeRole(r) if norm != r && norm == domain.RoleUser { traits["role"] = norm changed = true } } else if g, ok := traits["grade"].(string); ok { if norm, ok := domain.NormalizeRoleAlias(g); ok { traits["role"] = norm delete(traits, "grade") changed = true } } if changed { if *dryRun { count++ fmt.Printf("Would update %s\n", id.ID) continue } _, err := kratosAdmin.UpdateIdentity(ctx, id.ID, traits, id.State) if err != nil { log.Printf("Failed to update %s: %v", id.ID, err) } else { count++ fmt.Printf("Updated %s\n", id.ID) } } } if *dryRun { fmt.Printf("Total candidates: %d\n", count) } else { fmt.Printf("Total updated: %d\n", count) fmt.Println("Identity mirror was marked stale before maintenance; run full mirror refresh and drift report before trusting cached user lists.") } }