From 2fe6d306aa87eae9625d9b35b73f76b0630f8233 Mon Sep 17 00:00:00 2001 From: Andrew Savinykh <658865+AndrewSav@users.noreply.github.com> Date: Sun, 15 Feb 2026 20:36:03 +1300 Subject: [PATCH 1/2] substitute environment variables when loading yaml config --- service/internal/config/config_reloader.go | 9 +++++ .../internal/config/config_reloader_test.go | 34 +++---------------- 2 files changed, 14 insertions(+), 29 deletions(-) diff --git a/service/internal/config/config_reloader.go b/service/internal/config/config_reloader.go index 3bb8ee0..b931e80 100644 --- a/service/internal/config/config_reloader.go +++ b/service/internal/config/config_reloader.go @@ -8,6 +8,7 @@ import ( "sort" "strings" + "github.com/go-viper/mapstructure/v2" "github.com/knadh/koanf/parsers/yaml" "github.com/knadh/koanf/providers/file" "github.com/knadh/koanf/v2" @@ -51,6 +52,14 @@ func AppendSource(cfg *Config, k *koanf.Koanf, configPath string) { func unmarshalRoot(k *koanf.Koanf, cfg *Config) bool { err := k.UnmarshalWithConf("", cfg, koanf.UnmarshalConf{ Tag: "koanf", + DecoderConfig: &mapstructure.DecoderConfig{ + DecodeHook: mapstructure.ComposeDecodeHookFunc( + envDecodeHookFunc, + mapstructure.StringToTimeDurationHookFunc(), + mapstructure.TextUnmarshallerHookFunc(), + ), + WeaklyTypedInput: true, + }, }) if err != nil { diff --git a/service/internal/config/config_reloader_test.go b/service/internal/config/config_reloader_test.go index 5cece40..f96544e 100644 --- a/service/internal/config/config_reloader_test.go +++ b/service/internal/config/config_reloader_test.go @@ -90,26 +90,19 @@ var envConfigTests = []struct { } func TestEnvInConfig(t *testing.T) { - t.Skip("Skipping test in 3k") - for _, tt := range envConfigTests { cfg := DefaultConfig() setIfNotEmpty("INPUT", tt.input) - processed := processYamlWithEnv(tt.yaml) - k, err := loadKoanf(processed) + k := koanf.New(".") + err := k.Load(rawbytes.Provider([]byte(tt.yaml)), yaml.Parser()) if err != nil { t.Errorf("Error loading YAML: %v", err) continue } - - if err := k.UnmarshalWithConf("", cfg, koanf.UnmarshalConf{ - Tag: "koanf", - }); err != nil { - t.Errorf("Error unmarshalling config: %v", err) - continue - } + unmarshalRoot(k, cfg) field := tt.selector(cfg) - assert.Equal(t, tt.output, field, "Unmarshaled config field doesn't match expected value: env=\"%s\"", tt.input) + assert.Equal(t, tt.output, field, + "Unmarshaled config field doesn't match expected value: env=%q", tt.input) os.Unsetenv("INPUT") } } @@ -119,20 +112,3 @@ func setIfNotEmpty(key, val string) { os.Setenv(key, val) } } - -func processYamlWithEnv(content string) string { - return envRegex.ReplaceAllStringFunc(content, func(match string) string { - submatches := envRegex.FindStringSubmatch(match) - key := submatches[1] - val, _ := os.LookupEnv(key) - return val - }) -} - -func loadKoanf(processed string) (*koanf.Koanf, error) { - k := koanf.New(".") - if err := k.Load(rawbytes.Provider([]byte(processed)), yaml.Parser()); err != nil { - return nil, err - } - return k, nil -} From f58eeef49d3a59f314bf69d5eeb176695f82ae5b Mon Sep 17 00:00:00 2001 From: Andrew Savinykh <658865+AndrewSav@users.noreply.github.com> Date: Sun, 15 Feb 2026 21:28:23 +1300 Subject: [PATCH 2/2] check return value from `unmarshalRoot` in test and fail if false Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- service/internal/config/config_reloader_test.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/service/internal/config/config_reloader_test.go b/service/internal/config/config_reloader_test.go index f96544e..39dad61 100644 --- a/service/internal/config/config_reloader_test.go +++ b/service/internal/config/config_reloader_test.go @@ -99,7 +99,10 @@ func TestEnvInConfig(t *testing.T) { t.Errorf("Error loading YAML: %v", err) continue } - unmarshalRoot(k, cfg) + if !unmarshalRoot(k, cfg) { + t.Errorf("Error unmarshalling config for env=%q", tt.input) + continue + } field := tt.selector(cfg) assert.Equal(t, tt.output, field, "Unmarshaled config field doesn't match expected value: env=%q", tt.input)