Skip to content

Commit

Permalink
fix: config parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
gi8lino committed Aug 7, 2023
1 parent c0e4ca7 commit 5bbed18
Show file tree
Hide file tree
Showing 6 changed files with 125 additions and 8 deletions.
2 changes: 1 addition & 1 deletion cmd/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ the configuration if changes are detected.
viper.OnConfigChange(func(e fsnotify.Event) {
log.Infof("Config file changed: %s", e.Name)

if err := viper.ReadInConfig(); err != nil {
if err := config.ReadConfigFile(viper.ConfigFileUsed(), &config.App); err != nil {
log.Fatalf("Unable to read config: %s", err)
}

Expand Down
1 change: 1 addition & 0 deletions internal/config/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ func ParseConfig(app *Config) (err error) {

for idx, cert := range app.Certs {
if cert.Enabled != nil && !*cert.Enabled {
app.Certs[idx] = cert // update the certificate in the slice (maybe has changed from enabled to disabled)
log.Debugf("Skip certificate '%s' because is disabled", cert.Name)
continue
}
Expand Down
4 changes: 2 additions & 2 deletions internal/config/structs.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ type Pushgateway struct {

// Auth represents the pushgateway auth config
type Auth struct {
Basic Basic `json:"basic,omitempty" yaml:"enabled,omitempty"`
Bearer Bearer `json:"bearer,omitempty" yaml:"enabled,omitempty"`
Basic Basic `json:"basic,omitempty" yaml:"basic,omitempty"`
Bearer Bearer `json:"bearer,omitempty" yaml:"bearer,omitempty"`
}

// Basic represents the pushgateway basic auth config
Expand Down
22 changes: 17 additions & 5 deletions internal/handlers/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package handlers
import (
"bytes"
"certalert/internal/config"
"certalert/internal/utils"
"net/http"
"strings"

Expand All @@ -27,16 +28,27 @@ func ConfigHandler(w http.ResponseWriter, r *http.Request) {
// copy config and remove sensitive data
configCopy := config.App

configCopy.Pushgateway.Address = redactVariable(configCopy.Pushgateway.Address)
configCopy.Pushgateway.Auth.Basic.Username = redactVariable(configCopy.Pushgateway.Auth.Basic.Username)
configCopy.Pushgateway.Auth.Basic.Password = redactVariable(configCopy.Pushgateway.Auth.Basic.Password)
configCopy.Pushgateway.Auth.Bearer.Token = redactVariable(configCopy.Pushgateway.Auth.Bearer.Token)
if utils.HasKey(configCopy.Pushgateway, "Address") {
configCopy.Pushgateway.Address = redactVariable(configCopy.Pushgateway.Address)
}

if utils.HasKey(configCopy.Pushgateway, "Basic.Username") {
configCopy.Pushgateway.Auth.Basic.Username = redactVariable(configCopy.Pushgateway.Auth.Basic.Username)
}

if utils.HasKey(configCopy.Pushgateway, "Basic.Password") {
configCopy.Pushgateway.Auth.Basic.Password = redactVariable(configCopy.Pushgateway.Auth.Basic.Password)
}

if utils.HasKey(configCopy.Pushgateway, "Bearer.Token") {
configCopy.Pushgateway.Auth.Bearer.Token = redactVariable(configCopy.Pushgateway.Auth.Bearer.Token)
}

for idx, cert := range configCopy.Certs {
configCopy.Certs[idx].Password = redactVariable(cert.Password)
}

if err := yamlEncoder.Encode(&config.App); err != nil {
if err := yamlEncoder.Encode(&configCopy); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
Expand Down
29 changes: 29 additions & 0 deletions internal/utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"io"
"os"
"reflect"
"strings"
)

Expand Down Expand Up @@ -95,3 +96,31 @@ func CheckFileAccessibility(filePath string) error {

return nil
}

// HasKey checks if a given key (or nested key) exists within a map, struct or interface.
// The function supports nested keys separated by dots, such as "key1.key2.key3".
func HasKey(s interface{}, key string) bool {
v := reflect.ValueOf(s)
keys := strings.Split(key, ".")

for i, k := range keys {
switch v.Kind() {
case reflect.Map:
v = v.MapIndex(reflect.ValueOf(k))
case reflect.Struct:
v = v.FieldByName(k)
case reflect.Interface:
// Extract the underlying value of the interface
v = v.Elem()
// Recursively call HasKey for the remaining key parts
return HasKey(v.Interface(), strings.Join(keys[i:], "."))
default:
return false
}

if !v.IsValid() {
return false
}
}
return true
}
75 changes: 75 additions & 0 deletions internal/utils/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,3 +134,78 @@ func TestCheckFileAccessibility(t *testing.T) {
t.Errorf("Expected no error for readable file, got %v", err)
}
}

type NestedStruct struct {
InnerField string
}

type TestStruct struct {
Field1 string
Field2 NestedStruct
}

func TestHasKey(t *testing.T) {
tests := []struct {
name string
input interface{}
key string
expect bool
}{
{
name: "simple map key exists",
input: map[string]int{"key1": 1, "key2": 2},
key: "key1",
expect: true,
},
{
name: "simple map key does not exist",
input: map[string]int{"key1": 1, "key2": 2},
key: "key3",
expect: false,
},
{
name: "nested map key exists",
input: map[string]map[string]int{"key1": {"nestedKey": 1}},
key: "key1.nestedKey",
expect: true,
},
{
name: "nested map key does not exist",
input: map[string]map[string]int{"key1": {"nestedKey": 1}},
key: "key1.wrongKey",
expect: false,
},
{
name: "struct key exists",
input: TestStruct{Field1: "value1", Field2: NestedStruct{InnerField: "inner"}},
key: "Field1",
expect: true,
},
{
name: "struct key does not exist",
input: TestStruct{Field1: "value1", Field2: NestedStruct{InnerField: "inner"}},
key: "Field3",
expect: false,
},
{
name: "nested struct key exists",
input: TestStruct{Field1: "value1", Field2: NestedStruct{InnerField: "inner"}},
key: "Field2.InnerField",
expect: true,
},
{
name: "nested struct key does not exist",
input: TestStruct{Field1: "value1", Field2: NestedStruct{InnerField: "inner"}},
key: "Field2.WrongField",
expect: false,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := HasKey(tt.input, tt.key); got != tt.expect {
t.Errorf("Expected %v for key '%s', but got %v", tt.expect, tt.key, got)
}
})
}
}

0 comments on commit 5bbed18

Please sign in to comment.