LoadConfig reads configuration with priority: flags > env > config file > defaults.
()
| 159 | |
| 160 | // LoadConfig reads configuration with priority: flags > env > config file > defaults. |
| 161 | func LoadConfig() Config { |
| 162 | var configFile string |
| 163 | flag.StringVar(&configFile, "config", "", "Path to config file (buggregator.yaml)") |
| 164 | |
| 165 | cfg := Config{} |
| 166 | |
| 167 | flag.StringVar(&cfg.Server.Addr, "http-addr", "", "HTTP listen address") |
| 168 | flag.StringVar(&cfg.Database.DSN, "db", "", "SQLite DSN") |
| 169 | flag.StringVar(&cfg.TCP.SMTP.Addr, "smtp-addr", "", "SMTP listen address") |
| 170 | flag.StringVar(&cfg.TCP.Monolog.Addr, "monolog-addr", "", "Monolog TCP listen address") |
| 171 | flag.StringVar(&cfg.TCP.VarDumper.Addr, "vardumper-addr", "", "VarDumper TCP listen address") |
| 172 | flag.Parse() |
| 173 | |
| 174 | fileCfg := loadConfigFile(configFile) |
| 175 | |
| 176 | // Merge: flag > env > file > default. |
| 177 | cfg.Server.Addr = coalesce(cfg.Server.Addr, os.Getenv("HTTP_ADDR"), fileCfg.Server.Addr, ":8000") |
| 178 | cfg.Database.DSN = coalesce(cfg.Database.DSN, os.Getenv("DATABASE_DSN"), fileCfg.Database.DSN, ":memory:") |
| 179 | cfg.Database.Driver = coalesce(fileCfg.Database.Driver, "sqlite") |
| 180 | cfg.TCP.SMTP.Addr = coalesce(cfg.TCP.SMTP.Addr, os.Getenv("SMTP_ADDR"), fileCfg.TCP.SMTP.Addr, ":1025") |
| 181 | cfg.TCP.Monolog.Addr = coalesce(cfg.TCP.Monolog.Addr, os.Getenv("MONOLOG_ADDR"), fileCfg.TCP.Monolog.Addr, ":9913") |
| 182 | cfg.TCP.VarDumper.Addr = coalesce(cfg.TCP.VarDumper.Addr, os.Getenv("VAR_DUMPER_ADDR"), fileCfg.TCP.VarDumper.Addr, ":9912") |
| 183 | cfg.TCP.Proxy.Addr = coalesce(os.Getenv("PROXY_ADDR"), fileCfg.TCP.Proxy.Addr, ":8080") |
| 184 | |
| 185 | // Storage. |
| 186 | cfg.Storage.Mode = coalesce(os.Getenv("STORAGE_MODE"), fileCfg.Storage.Mode, "memory") |
| 187 | cfg.Storage.Path = coalesce(os.Getenv("STORAGE_PATH"), fileCfg.Storage.Path, "./storage") |
| 188 | |
| 189 | // Metrics. |
| 190 | cfg.Metrics.Enabled = fileCfg.Metrics.Enabled || os.Getenv("METRICS_ENABLED") == "true" |
| 191 | cfg.Metrics.Addr = coalesce(os.Getenv("METRICS_ADDR"), fileCfg.Metrics.Addr) |
| 192 | |
| 193 | // MCP. |
| 194 | cfg.MCP.Enabled = fileCfg.MCP.Enabled || os.Getenv("MCP_ENABLED") == "true" |
| 195 | cfg.MCP.Transport = coalesce(os.Getenv("MCP_TRANSPORT"), fileCfg.MCP.Transport, "socket") |
| 196 | cfg.MCP.SocketPath = coalesce(os.Getenv("MCP_SOCKET_PATH"), fileCfg.MCP.SocketPath, "/tmp/buggregator-mcp.sock") |
| 197 | cfg.MCP.Addr = coalesce(os.Getenv("MCP_ADDR"), fileCfg.MCP.Addr, ":8001") |
| 198 | cfg.MCP.AuthToken = coalesce(os.Getenv("MCP_AUTH_TOKEN"), fileCfg.MCP.AuthToken) |
| 199 | |
| 200 | // Auth. |
| 201 | cfg.Auth.Enabled = fileCfg.Auth.Enabled || os.Getenv("AUTH_ENABLED") == "true" |
| 202 | cfg.Auth.Provider = coalesce(os.Getenv("AUTH_PROVIDER"), fileCfg.Auth.Provider, "oidc") |
| 203 | cfg.Auth.ProviderURL = coalesce(os.Getenv("AUTH_PROVIDER_URL"), fileCfg.Auth.ProviderURL) |
| 204 | cfg.Auth.ClientID = coalesce(os.Getenv("AUTH_CLIENT_ID"), fileCfg.Auth.ClientID) |
| 205 | cfg.Auth.ClientSecret = coalesce(os.Getenv("AUTH_CLIENT_SECRET"), fileCfg.Auth.ClientSecret) |
| 206 | cfg.Auth.CallbackURL = coalesce(os.Getenv("AUTH_CALLBACK_URL"), fileCfg.Auth.CallbackURL) |
| 207 | cfg.Auth.Scopes = coalesce(os.Getenv("AUTH_SCOPES"), fileCfg.Auth.Scopes, "openid,email,profile") |
| 208 | cfg.Auth.JWTSecret = coalesce(os.Getenv("AUTH_JWT_SECRET"), fileCfg.Auth.JWTSecret) |
| 209 | |
| 210 | // CORS origins. |
| 211 | cfg.Server.CORSOrigins = fileCfg.Server.CORSOrigins |
| 212 | if env := os.Getenv("CORS_ORIGINS"); env != "" { |
| 213 | cfg.Server.CORSOrigins = strings.Split(env, ",") |
| 214 | } |
| 215 | if len(cfg.Server.CORSOrigins) == 0 { |
| 216 | cfg.Server.CORSOrigins = []string{"*"} |
| 217 | } |
| 218 |
no test coverage detected