error on RPC env var for non-existing coin to prevent misconfig

This commit is contained in:
pragmaxim
2026-01-15 12:44:06 +01:00
parent cf2fb62447
commit 82a0827009

View File

@@ -10,6 +10,8 @@ import (
"path/filepath"
"reflect"
"runtime"
"sort"
"strings"
"text/template"
"time"
)
@@ -124,6 +126,71 @@ func generateRPCAuth(user, pass string) (string, error) {
return out.String(), nil
}
func validateRPCEnvVars(configsDir string) error {
// Use config filenames as the source of truth so typos fail before templating.
validAliases, err := loadCoinAliases(configsDir)
if err != nil {
return err
}
unknown := collectUnknownRPCEnvVars(validAliases, rpcEnvPrefixes())
if len(unknown) == 0 {
return nil
}
sort.Strings(unknown)
return fmt.Errorf("BB_RPC_* env vars reference unknown coin aliases: %s", strings.Join(unknown, ", "))
}
func loadCoinAliases(configsDir string) (map[string]struct{}, error) {
coinsDir := filepath.Join(configsDir, "coins")
entries, err := os.ReadDir(coinsDir)
if err != nil {
return nil, fmt.Errorf("read coins directory for BB_RPC_* validation: %w", err)
}
validAliases := make(map[string]struct{}, len(entries))
for _, entry := range entries {
if entry.IsDir() {
continue
}
name := entry.Name()
if !strings.HasSuffix(name, ".json") {
continue
}
alias := strings.TrimSuffix(name, ".json")
if alias != "" {
validAliases[alias] = struct{}{}
}
}
return validAliases, nil
}
func rpcEnvPrefixes() []string {
return []string{"BB_RPC_URL_", "BB_RPC_BIND_HOST_", "BB_RPC_ALLOW_IP_"}
}
func collectUnknownRPCEnvVars(validAliases map[string]struct{}, prefixes []string) []string {
var unknown []string
for _, env := range os.Environ() {
key, _, _ := strings.Cut(env, "=")
for _, prefix := range prefixes {
if !strings.HasPrefix(key, prefix) {
continue
}
alias := strings.TrimPrefix(key, prefix)
if alias == "" {
unknown = append(unknown, fmt.Sprintf("(empty alias from %s)", key)) // Empty suffix is always invalid.
break
}
if _, ok := validAliases[alias]; !ok {
unknown = append(unknown, fmt.Sprintf("%s (from %s)", alias, key))
}
break
}
}
return unknown
}
// ParseTemplate parses the template
func (c *Config) ParseTemplate() *template.Template {
templates := map[string]string{
@@ -165,6 +232,11 @@ func copyNonZeroBackendFields(toValue *Backend, fromValue *Backend) {
func LoadConfig(configsDir, coin string) (*Config, error) {
config := new(Config)
// Fail fast if BB_RPC_* variables reference coins that do not exist in configs/coins.
if err := validateRPCEnvVars(configsDir); err != nil {
return nil, err
}
f, err := os.Open(filepath.Join(configsDir, "coins", coin+".json"))
if err != nil {
return nil, err