- SSE subscription to ntfy with auto-reconnect - Discord webhook integration with embed formatting - Priority to color mapping, tag to emoji conversion - Native HashiCorp Vault support (Kubernetes + token auth) - Hot reload secrets via fsnotify or Vault polling - Prometheus metrics (/metrics endpoint) - Health/ready endpoints for Kubernetes probes - Comprehensive unit tests and fuzz tests - Multi-stage Docker build (~10MB scratch image) - CI/CD pipeline for Gitea Actions
73 lines
1.4 KiB
Go
73 lines
1.4 KiB
Go
package config
|
|
|
|
import (
|
|
"testing"
|
|
)
|
|
|
|
// FuzzParseTopics tests topic parsing doesn't panic on arbitrary input
|
|
func FuzzParseTopics(f *testing.F) {
|
|
// Normal cases
|
|
f.Add("alerts")
|
|
f.Add("alerts,updates")
|
|
f.Add("alerts, updates, notifications")
|
|
f.Add("")
|
|
|
|
// Edge cases
|
|
f.Add(",,,")
|
|
f.Add(" , , ")
|
|
f.Add("a]topic-with-special_chars.123")
|
|
f.Add("\x00\x00\x00")
|
|
f.Add("topic\nwith\nnewlines")
|
|
|
|
f.Fuzz(func(t *testing.T, input string) {
|
|
// Simulate topic parsing logic
|
|
if input == "" {
|
|
return
|
|
}
|
|
|
|
topics := make([]string, 0)
|
|
for _, topic := range splitAndTrim(input) {
|
|
topics = append(topics, topic)
|
|
}
|
|
|
|
// Accessing results should not panic
|
|
_ = len(topics)
|
|
})
|
|
}
|
|
|
|
// splitAndTrim mimics the topic parsing in Load()
|
|
func splitAndTrim(s string) []string {
|
|
if s == "" {
|
|
return nil
|
|
}
|
|
var result []string
|
|
start := 0
|
|
for i := 0; i < len(s); i++ {
|
|
if s[i] == ',' {
|
|
part := trimSpace(s[start:i])
|
|
if part != "" {
|
|
result = append(result, part)
|
|
}
|
|
start = i + 1
|
|
}
|
|
}
|
|
// Last part
|
|
part := trimSpace(s[start:])
|
|
if part != "" {
|
|
result = append(result, part)
|
|
}
|
|
return result
|
|
}
|
|
|
|
func trimSpace(s string) string {
|
|
start := 0
|
|
end := len(s)
|
|
for start < end && (s[start] == ' ' || s[start] == '\t' || s[start] == '\n' || s[start] == '\r') {
|
|
start++
|
|
}
|
|
for end > start && (s[end-1] == ' ' || s[end-1] == '\t' || s[end-1] == '\n' || s[end-1] == '\r') {
|
|
end--
|
|
}
|
|
return s[start:end]
|
|
}
|