mirror of
https://github.com/GlueOps/autoglue.git
synced 2026-02-13 21:00:06 +01:00
195 lines
4.9 KiB
Go
195 lines
4.9 KiB
Go
package config
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
"sync"
|
|
|
|
"github.com/joho/godotenv"
|
|
"github.com/spf13/viper"
|
|
"gopkg.in/yaml.v3"
|
|
)
|
|
|
|
type Config struct {
|
|
DbURL string
|
|
Port string
|
|
Host string
|
|
JWTIssuer string
|
|
JWTAudience string
|
|
JWTPrivateEncKey string
|
|
OAuthRedirectBase string
|
|
GoogleClientID string
|
|
GoogleClientSecret string
|
|
GithubClientID string
|
|
GithubClientSecret string
|
|
|
|
UIDev bool
|
|
Env string
|
|
Debug bool
|
|
Swagger bool
|
|
}
|
|
|
|
var (
|
|
once sync.Once
|
|
cached Config
|
|
loadErr error
|
|
)
|
|
|
|
func Load() (Config, error) {
|
|
once.Do(func() {
|
|
_ = godotenv.Load()
|
|
|
|
// Use a private viper to avoid global mutation/races
|
|
v := viper.New()
|
|
|
|
// Defaults
|
|
v.SetDefault("bind.address", "127.0.0.1")
|
|
v.SetDefault("bind.port", "8080")
|
|
v.SetDefault("database.url", "postgres://user:pass@localhost:5432/db?sslmode=disable")
|
|
|
|
v.SetDefault("ui.dev", false)
|
|
v.SetDefault("env", "development")
|
|
v.SetDefault("debug", false)
|
|
v.SetDefault("swagger", false)
|
|
|
|
// Env setup and binding
|
|
v.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
|
|
v.AutomaticEnv()
|
|
|
|
keys := []string{
|
|
"bind.address",
|
|
"bind.port",
|
|
"database.url",
|
|
"jwt.issuer",
|
|
"jwt.audience",
|
|
"jwt.private.enc.key",
|
|
"oauth.redirect.base",
|
|
"google.client.id",
|
|
"google.client.secret",
|
|
"github.client.id",
|
|
"github.client.secret",
|
|
"ui.dev",
|
|
"env",
|
|
"debug",
|
|
"swagger",
|
|
}
|
|
for _, k := range keys {
|
|
_ = v.BindEnv(k)
|
|
}
|
|
|
|
// Build config
|
|
cfg := Config{
|
|
DbURL: v.GetString("database.url"),
|
|
Port: v.GetString("bind.port"),
|
|
Host: v.GetString("bind.address"),
|
|
JWTIssuer: v.GetString("jwt.issuer"),
|
|
JWTAudience: v.GetString("jwt.audience"),
|
|
JWTPrivateEncKey: v.GetString("jwt.private.enc.key"),
|
|
OAuthRedirectBase: v.GetString("oauth.redirect.base"),
|
|
GoogleClientID: v.GetString("google.client.id"),
|
|
GoogleClientSecret: v.GetString("google.client.secret"),
|
|
GithubClientID: v.GetString("github.client.id"),
|
|
GithubClientSecret: v.GetString("github.client.secret"),
|
|
|
|
UIDev: v.GetBool("ui.dev"),
|
|
Env: v.GetString("env"),
|
|
Debug: v.GetBool("debug"),
|
|
Swagger: v.GetBool("swagger"),
|
|
}
|
|
|
|
// Validate
|
|
if err := validateConfig(cfg); err != nil {
|
|
loadErr = err
|
|
return
|
|
}
|
|
|
|
cached = cfg
|
|
})
|
|
return cached, loadErr
|
|
}
|
|
|
|
func validateConfig(cfg Config) error {
|
|
var errs []string
|
|
|
|
// Required general settings
|
|
req := map[string]string{
|
|
"jwt.issuer": cfg.JWTIssuer,
|
|
"jwt.audience": cfg.JWTAudience,
|
|
"jwt.private.enc.key": cfg.JWTPrivateEncKey,
|
|
"oauth.redirect.base": cfg.OAuthRedirectBase,
|
|
}
|
|
for k, v := range req {
|
|
if strings.TrimSpace(v) == "" {
|
|
errs = append(errs, fmt.Sprintf("missing required config key %q (env %s)", k, envNameFromKey(k)))
|
|
}
|
|
}
|
|
|
|
// OAuth provider requirements:
|
|
googleOK := strings.TrimSpace(cfg.GoogleClientID) != "" && strings.TrimSpace(cfg.GoogleClientSecret) != ""
|
|
githubOK := strings.TrimSpace(cfg.GithubClientID) != "" && strings.TrimSpace(cfg.GithubClientSecret) != ""
|
|
|
|
// If partially configured, report what's missing for each
|
|
if !googleOK && (cfg.GoogleClientID != "" || cfg.GoogleClientSecret != "") {
|
|
if cfg.GoogleClientID == "" {
|
|
errs = append(errs, fmt.Sprintf("google.client.id is missing (env %s) while google.client.secret is set", envNameFromKey("google.client.id")))
|
|
}
|
|
if cfg.GoogleClientSecret == "" {
|
|
errs = append(errs, fmt.Sprintf("google.client.secret is missing (env %s) while google.client.id is set", envNameFromKey("google.client.secret")))
|
|
}
|
|
}
|
|
if !githubOK && (cfg.GithubClientID != "" || cfg.GithubClientSecret != "") {
|
|
if cfg.GithubClientID == "" {
|
|
errs = append(errs, fmt.Sprintf("github.client.id is missing (env %s) while github.client.secret is set", envNameFromKey("github.client.id")))
|
|
}
|
|
if cfg.GithubClientSecret == "" {
|
|
errs = append(errs, fmt.Sprintf("github.client.secret is missing (env %s) while github.client.id is set", envNameFromKey("github.client.secret")))
|
|
}
|
|
}
|
|
|
|
// Enforce minimum: at least one full provider
|
|
if !googleOK && !githubOK {
|
|
errs = append(errs, "at least one OAuth provider must be fully configured: either Google (google.client.id + google.client.secret) or GitHub (github.client.id + github.client.secret)")
|
|
}
|
|
|
|
if len(errs) > 0 {
|
|
return errors.New(strings.Join(errs, "; "))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func envNameFromKey(key string) string {
|
|
return strings.ToUpper(strings.ReplaceAll(key, ".", "_"))
|
|
}
|
|
|
|
func DebugPrintConfig() {
|
|
cfg, _ := Load()
|
|
b, err := yaml.Marshal(cfg)
|
|
if err != nil {
|
|
fmt.Println("error marshalling config:", err)
|
|
return
|
|
}
|
|
fmt.Println("Loaded configuration:")
|
|
fmt.Println(string(b))
|
|
}
|
|
|
|
func IsUIDev() bool {
|
|
cfg, _ := Load()
|
|
return cfg.UIDev
|
|
}
|
|
|
|
func IsDev() bool {
|
|
cfg, _ := Load()
|
|
return strings.EqualFold(cfg.Env, "development")
|
|
}
|
|
|
|
func IsDebug() bool {
|
|
cfg, _ := Load()
|
|
return cfg.Debug
|
|
}
|
|
|
|
func IsSwaggerEnabled() bool {
|
|
cfg, _ := Load()
|
|
return cfg.Swagger
|
|
}
|