// Command provision-org is the genesis bootstrap. It runs as the BYPASSRLS migrator role and calls // the provision_org SECURITY DEFINER function to create an organization, its owner user (invited, MFA // not yet enrolled), and a one time activation link. The app role cannot do this (it has no // organizations INSERT grant and no EXECUTE on provision_org), which keeps org creation off the // public attack surface. // // Env: MM_MIGRATOR_DATABASE_URL (or MM_DATABASE_URL). Flags name the org and owner. The printed // activation token is delivered to the owner out of band (manual at pilot); the owner redeems it at // POST /api/auth/invite/accept to set a password and enroll MFA. package main import ( "context" "flag" "fmt" "log" "os" "time" "github.com/google/uuid" "github.com/jackc/pgx/v5" "github.com/missionworkforce/missionmatch/internal/platform/security" ) func main() { name := flag.String("name", "", "organization name") slug := flag.String("slug", "", "organization slug (unique)") ownerEmail := flag.String("owner-email", "", "owner email") ownerName := flag.String("owner-name", "", "owner full name") expiryHours := flag.Int("expiry-hours", 72, "activation link lifetime in hours") flag.Parse() if *name == "" || *slug == "" || *ownerEmail == "" || *ownerName == "" { log.Fatal("provision-org: -name, -slug, -owner-email, and -owner-name are all required") } dsn := firstNonEmpty(os.Getenv("MM_MIGRATOR_DATABASE_URL"), os.Getenv("MM_DATABASE_URL")) if dsn == "" { log.Fatal("provision-org: set MM_MIGRATOR_DATABASE_URL (the BYPASSRLS migrator DSN)") } token, tokenHash, err := security.NewSessionToken() if err != nil { log.Fatalf("provision-org: generate token: %v", err) } ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second) defer cancel() conn, err := pgx.Connect(ctx, dsn) if err != nil { log.Fatalf("provision-org: connect: %v", err) } defer conn.Close(ctx) var orgID, ownerID, inviteID uuid.UUID err = conn.QueryRow(ctx, `SELECT organization_id, owner_user_id, invite_id FROM provision_org($1,$2,$3,$4,$5,$6)`, *name, *slug, *ownerEmail, *ownerName, tokenHash, *expiryHours*3600). Scan(&orgID, &ownerID, &inviteID) if err != nil { log.Fatalf("provision-org: provision_org: %v", err) } fmt.Printf("organization_id: %s\n", orgID) fmt.Printf("owner_user_id: %s\n", ownerID) fmt.Printf("invite_id: %s\n", inviteID) fmt.Printf("activation_token (deliver to the owner, expires in %dh):\n%s\n", *expiryHours, token) fmt.Printf("\nThe owner redeems it at POST /api/auth/invite/accept with {\"token\":\"...\",\"password\":\"...\"}, then enrolls MFA.\n") } func firstNonEmpty(vals ...string) string { for _, v := range vals { if v != "" { return v } } return "" }