package main import ( "context" "flag" "fmt" "strings" "time" "apps/backend/internal/config" "github.com/zeromicro/go-zero/core/conf" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" "golang.org/x/crypto/bcrypt" ) // seeder is intentionally explicit: a deployment must provide its own admin // password rather than receiving a committed default credential. func main() { configFile := flag.String("f", "etc/gateway.yaml", "config file") flag.Parse() var c config.Config conf.MustLoad(*configFile, &c) c.ApplyEnv() password := c.Seed.AdminPassword if len(password) < 12 || strings.Contains(password, "REPLACE_WITH") { panic("Seed.AdminPassword in gateway.yaml must be at least 12 characters") } ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second) defer cancel() client, err := mongo.Connect(ctx, options.Client().ApplyURI(c.Mongo.URI)) if err != nil { panic(err) } defer client.Disconnect(context.Background()) hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) if err != nil { panic(err) } now := time.Now().UTC().UnixNano() admin := bson.M{ "uid": int64(1_000_000), "tenant_id": "default", "email": "admin@haixun.local", "display_name": "Harbor Admin", "roles": []string{"admin", "member"}, "status": "active", "email_verified": true, "email_verified_at": now, "invite_code": "SEEDADMIN", "password_hash": string(hash), "timezone": "Asia/Taipei", "created_at": now, "updated_at": now, } db := client.Database(c.Mongo.Database) _, err = db.Collection("members").UpdateOne(ctx, bson.M{"uid": admin["uid"]}, bson.M{"$setOnInsert": admin}, options.Update().SetUpsert(true)) if err != nil { panic(err) } _, err = db.Collection("counters").UpdateOne(ctx, bson.M{"_id": "member_uid"}, bson.M{"$setOnInsert": bson.M{"seq": int64(1_000_000)}}, options.Update().SetUpsert(true)) if err != nil { panic(err) } fmt.Printf("seeded admin %s\n", strings.TrimSpace(admin["email"].(string))) }