diff --git a/pkg/channels/manager_channel.go b/pkg/channels/manager_channel.go index 9dbd35cab..b6b407c59 100644 --- a/pkg/channels/manager_channel.go +++ b/pkg/channels/manager_channel.go @@ -17,7 +17,7 @@ func toChannelHashes(cfg *config.Config) map[string]string { _ = json.Unmarshal(marshal, &channelConfig) for key, value := range channelConfig { - if !value["enabled"].(bool) { + if enabled, ok := value["enabled"].(bool); !ok || !enabled { continue } hiddenValues(key, value, ch.Get(key)) @@ -94,7 +94,15 @@ func hiddenValues(key string, value map[string]any, ch *config.Channel) { vv := value["webhooks"] webhooks := make(map[string]string) if vv != nil { - webhooks = vv.(map[string]string) + if m, ok := vv.(map[string]string); ok { + webhooks = m + } else if m, ok := vv.(map[string]any); ok { + for k, w := range m { + if s, ok := w.(string); ok { + webhooks[k] = s + } + } + } } if settings, ok := v.(*config.TeamsWebhookSettings); ok { for name, target := range settings.Webhooks { diff --git a/pkg/channels/manager_channel_test.go b/pkg/channels/manager_channel_test.go index b991e58d6..9d0373299 100644 --- a/pkg/channels/manager_channel_test.go +++ b/pkg/channels/manager_channel_test.go @@ -151,3 +151,57 @@ func TestToChannelHashes_RealWorldChannel(t *testing.T) { assert.Equal(t, 1, len(h)) assert.Contains(t, h, "telegram") } + +func TestToChannelHashes_MissingEnabledKey(t *testing.T) { + cfg := config.DefaultConfig() + cfg.Channels["test"] = &config.Channel{ + Settings: config.RawNode(`{"key":"value"}`), + } + + // Should not panic — the ok check safely handles the missing/false case + assert.NotPanics(t, func() { + _ = toChannelHashes(cfg) + }) + h := toChannelHashes(cfg) + assert.Equal(t, 0, len(h), "channel with Enabled=false (default) skipped") +} + +func TestToChannelHashes_EnabledNotBool(t *testing.T) { + cfg := config.DefaultConfig() + cfg.Channels["test"] = &config.Channel{ + Enabled: false, + Settings: config.RawNode(`{"enabled":"yes","boolField":true}`), + } + + // Should not panic — string "enabled" won't match bool assertion, ok=false + assert.NotPanics(t, func() { + _ = toChannelHashes(cfg) + }) + h := toChannelHashes(cfg) + assert.Equal(t, 0, len(h), "string enabled not treated as true") +} + +func TestToChannelHashes_TeamsWebhookWithWebhooks(t *testing.T) { + cfg := config.DefaultConfig() + // teams_webhook with configured webhooks — this is the real-world + // scenario where the map type from JSON unmarshal (map[string]any) + // would cause a panic on the old unchecked vv.(map[string]string) + settings, _ := json.Marshal(map[string]any{ + "enabled": true, + "webhooks": map[string]any{ + "hook1": "https://example.com/webhook", + }, + }) + cfg.Channels["teams_webhook"] = &config.Channel{ + Enabled: true, + Type: config.ChannelTeamsWebHook, + Settings: config.RawNode(settings), + } + + assert.NotPanics(t, func() { + _ = toChannelHashes(cfg) + }) + h := toChannelHashes(cfg) + assert.Equal(t, 1, len(h)) + assert.Contains(t, h, "teams_webhook") +}