From 1ba99f27ba23a81c75d1b159c4ed644835c193f9 Mon Sep 17 00:00:00 2001 From: Vojtech Vitek Date: Tue, 21 Apr 2026 17:56:15 +0200 Subject: [PATCH 1/2] Add test case for maps --- hydrate_test.go | 47 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 36 insertions(+), 11 deletions(-) diff --git a/hydrate_test.go b/hydrate_test.go index 4eeb7e0..7bc9bf9 100644 --- a/hydrate_test.go +++ b/hydrate_test.go @@ -12,11 +12,17 @@ import ( ) type config struct { - DB db - Analytics analytics - Pass string - JWTSecrets []string - Services map[string]service + DB db + Analytics analytics + Pass string + JWTSecrets []string + Services map[string]service + InboundWebhooks InboundWebhooksConfig +} + +type InboundWebhooksConfig struct { + Secrets map[string]string `toml:"secrets"` + MaxBodySize int64 `toml:"max_body_size"` } type db struct { @@ -152,12 +158,15 @@ func TestHydrate(t *testing.T) { { name: "successful_replacement", storage: map[string]string{ - "dbPassword": "changethissecret", - "analyticsPassword": "AuthTokenSecret", - "pass": "secret", - "jwtSecretV1": "some-old-secret", - "jwtSecretV2": "changeme-now", - "auth": "auth-secret", + "dbPassword": "changethissecret", + "analyticsPassword": "AuthTokenSecret", + "pass": "secret", + "jwtSecretV1": "some-old-secret", + "jwtSecretV2": "changeme-now", + "auth": "auth-secret", + "inbound_webhook_foo": "foo-secret", + "inbound_webhook_bar": "bar-secret", + "inbound_webhook_baz": "baz-secret", }, conf: &config{ Pass: "$SECRET:pass", @@ -178,6 +187,14 @@ func TestHydrate(t *testing.T) { Auth: "$SECRET:auth", }, }, + InboundWebhooks: InboundWebhooksConfig{ + Secrets: map[string]string{ + "foo": "$SECRET:inbound_webhook_foo", + "bar": "$SECRET:inbound_webhook_bar", + "baz": "$SECRET:inbound_webhook_baz", + }, + MaxBodySize: 1024, + }, }, wantErr: false, wantConf: &config{ @@ -202,6 +219,14 @@ func TestHydrate(t *testing.T) { Auth: "auth-secret", }, }, + InboundWebhooks: InboundWebhooksConfig{ + Secrets: map[string]string{ + "foo": "foo-secret", + "bar": "bar-secret", + "baz": "baz-secret", + }, + MaxBodySize: 1024, + }, }, }, { From 439dfea43697562e6a71d6595446f5d98bfa2ad6 Mon Sep 17 00:00:00 2001 From: Vojtech Vitek Date: Tue, 21 Apr 2026 17:56:53 +0200 Subject: [PATCH 2/2] Fix setting secrets in map values --- replacer.go | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/replacer.go b/replacer.go index bbb7556..f0517bd 100644 --- a/replacer.go +++ b/replacer.go @@ -66,15 +66,14 @@ func (r *replacer) replaceSecrets(v reflect.Value, path string) { for _, key := range v.MapKeys() { item := v.MapIndex(key) - if item.Kind() == reflect.Struct { - // If the value is a struct, create a pointer to it, update the value and reassign the map. - ptr := reflect.New(item.Type()) - ptr.Elem().Set(item) - r.replaceSecrets(ptr, fmt.Sprintf("%v[%v]", path, key)) - v.SetMapIndex(key, ptr.Elem()) - } else { - r.replaceSecrets(item, fmt.Sprintf("%v[%v]", path, key)) - } + // Map values returned by MapIndex are not addressable and therefore + // not settable via reflect (this applies to strings, structs, and + // any other value kind). Copy the value into an addressable pointer, + // mutate it via recursion, and write the updated value back. + ptr := reflect.New(item.Type()) + ptr.Elem().Set(item) + r.replaceSecrets(ptr.Elem(), fmt.Sprintf("%v[%v]", path, key)) + v.SetMapIndex(key, ptr.Elem()) } case reflect.String: