This commit is contained in:
2026-08-13 21:38:42 +02:00
parent db1f341784
commit 260fe28ac0
6 changed files with 134 additions and 11 deletions
+11 -6
View File
@@ -11,7 +11,9 @@
// -password 'choose-a-strong-password' \
// -confirm
//
// Env aliases: PLATFORM_ADMIN_EMAIL, PLATFORM_ADMIN_PASSWORD, DATABASE_URL.
// Env aliases: none for credentials — pass -email / -password (or use
// `npm run seed:platform-admin -- --email … --password …`). DATABASE_URL may
// come from the shell or monorepo-root .env via config.LoadDotEnv.
//
// -promote-only grants admin on an existing user without changing the password
// (-password is ignored). Always requires -confirm.
@@ -28,15 +30,18 @@ import (
"time"
"github.com/descrybe/descrybe-v2/apps/api/internal/auth"
"github.com/descrybe/descrybe-v2/apps/api/internal/config"
"github.com/google/uuid"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgxpool"
)
func main() {
config.LoadDotEnv()
postgresURL := flag.String("postgres", os.Getenv("DATABASE_URL"), "Postgres URL")
email := flag.String("email", os.Getenv("PLATFORM_ADMIN_EMAIL"), "Platform admin email")
password := flag.String("password", os.Getenv("PLATFORM_ADMIN_PASSWORD"), "Password (min 8; ignored with -promote-only)")
email := flag.String("email", "", "Platform admin email (required; do not put in .env)")
password := flag.String("password", "", "Password (min 8; ignored with -promote-only; do not put in .env)")
name := flag.String("name", "", "Display name (defaults to email local-part)")
promoteOnly := flag.Bool("promote-only", false, "Grant platform admin on an existing user; do not set password")
confirm := flag.Bool("confirm", false, "Required: acknowledge this writes is_platform_admin + staff_role=admin")
@@ -93,11 +98,11 @@ func parseOptions(postgresURL, email, password, name string, promoteOnly, confir
}
pg := strings.TrimSpace(postgresURL)
if pg == "" {
return options{}, fmt.Errorf("-postgres / DATABASE_URL is required")
return options{}, fmt.Errorf("-postgres / DATABASE_URL is required (export it, pass -postgres, or put DATABASE_URL in monorepo-root .env — the API loads .env, your shell may not)")
}
emailNorm := strings.ToLower(strings.TrimSpace(email))
if emailNorm == "" || !strings.Contains(emailNorm, "@") {
return options{}, fmt.Errorf("-email / PLATFORM_ADMIN_EMAIL is required")
return options{}, fmt.Errorf("-email is required (pass on the CLI; do not store admin credentials in .env)")
}
if err := rejectLocalDemoAccount(emailNorm, appEnv); err != nil {
return options{}, err
@@ -122,7 +127,7 @@ func parseOptions(postgresURL, email, password, name string, promoteOnly, confir
}
pass := password // keep as provided (do not trim interior spaces)
if len(pass) < 8 {
return options{}, fmt.Errorf("-password / PLATFORM_ADMIN_PASSWORD must be at least 8 characters")
return options{}, fmt.Errorf("-password must be at least 8 characters (pass on the CLI; do not store in .env)")
}
if err := rejectDemoPassword(pass, appEnv); err != nil {
return options{}, err
@@ -5,6 +5,14 @@ import (
"testing"
)
func TestParseOptionsRequiresPostgres(t *testing.T) {
t.Parallel()
_, err := parseOptions("", "a@b.com", "password1", "", false, true, "development")
if err == nil || !strings.Contains(err.Error(), "DATABASE_URL") {
t.Fatalf("err = %v, want DATABASE_URL required", err)
}
}
func TestParseOptionsRequiresConfirm(t *testing.T) {
t.Parallel()
_, err := parseOptions("postgres://x", "a@b.com", "password1", "", false, false, "development")