feat: backend service
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"galaxy/backend/internal/config"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
// Bootstrap inserts the seed admin row when the env-driven
|
||||
// `BACKEND_ADMIN_BOOTSTRAP_USER` / `BACKEND_ADMIN_BOOTSTRAP_PASSWORD`
|
||||
// values are supplied and no row with that username exists yet. The
|
||||
// insert is idempotent across restarts so operators can leave the env
|
||||
// vars set after the first deploy without re-creating the row on
|
||||
// every boot.
|
||||
//
|
||||
// Bootstrap runs *before* `Cache.Warm` so the warm read picks up the
|
||||
// seed row. Errors are returned to the caller; the boot path in
|
||||
// `cmd/backend/main.go` aborts startup if Bootstrap fails (a missing
|
||||
// admin would lock the surface out anyway, so failing fast is the
|
||||
// safer default).
|
||||
//
|
||||
// When both env vars are empty the function logs "skipped" and
|
||||
// returns nil. `config.Validate()` already enforces that the username
|
||||
// and password are set together, so by the time Bootstrap runs the
|
||||
// remaining "user set without password" combination is impossible.
|
||||
func Bootstrap(ctx context.Context, store *Store, cfg config.AdminBootstrapConfig, logger *zap.Logger) error {
|
||||
if logger == nil {
|
||||
logger = zap.NewNop()
|
||||
}
|
||||
logger = logger.Named("admin.bootstrap")
|
||||
|
||||
if cfg.User == "" {
|
||||
logger.Info("skipped (no env vars)")
|
||||
return nil
|
||||
}
|
||||
|
||||
hash, err := bcrypt.GenerateFromPassword([]byte(cfg.Password), bootstrapBcryptCost)
|
||||
if err != nil {
|
||||
return fmt.Errorf("admin bootstrap: hash password: %w", err)
|
||||
}
|
||||
|
||||
inserted, err := store.BootstrapInsert(ctx, cfg.User, hash)
|
||||
if err != nil {
|
||||
return fmt.Errorf("admin bootstrap: %w", err)
|
||||
}
|
||||
if inserted {
|
||||
logger.Info("inserted seed admin", zap.String("admin_username", cfg.User))
|
||||
} else {
|
||||
logger.Info("skipped (admin exists)", zap.String("admin_username", cfg.User))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user