From 37d42e1a5c23d5e3b08132a1eaff2e5c4b0d54d1 Mon Sep 17 00:00:00 2001 From: Fabian Siegel Date: Fri, 3 Sep 2021 23:43:26 +0200 Subject: [PATCH] make only specific keys configurable by validating them (#18) --- cmd/commands/config/config.go | 17 +++++--- config/config.go | 79 +++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+), 5 deletions(-) create mode 100644 config/config.go diff --git a/cmd/commands/config/config.go b/cmd/commands/config/config.go index 4e53257..cde1f66 100644 --- a/cmd/commands/config/config.go +++ b/cmd/commands/config/config.go @@ -9,6 +9,7 @@ import ( "strings" "github.com/craftamap/bb/cmd/options" + "github.com/craftamap/bb/config" bbgit "github.com/craftamap/bb/git" "github.com/craftamap/bb/util/logging" "github.com/kirsle/configdir" @@ -37,6 +38,16 @@ func Add(rootCmd *cobra.Command, _ *options.GlobalOptions) { if Get { // TODO: code here } else { + key := args[0] + inputValue := args[1] + + newValue, err := config.BbConfigurationValidation.ValidateEntry(key, inputValue) + + if err != nil { + logging.Error(fmt.Sprintf("failed to validate %s: %s", inputValue, err)) + return + } + var configDirectory string var filename string if Local { @@ -75,9 +86,6 @@ func Add(rootCmd *cobra.Command, _ *options.GlobalOptions) { tmpVp.SetConfigFile(path) tmpVp.ReadInConfig() - key := args[0] - newValue := args[1] - isSetAlready := tmpVp.IsSet(key) oldValue := tmpVp.Get(key) @@ -122,7 +130,6 @@ func Add(rootCmd *cobra.Command, _ *options.GlobalOptions) { return } - logging.SuccessExclamation(fmt.Sprintf("Successfully updated configuration %s", path)) } }, @@ -137,7 +144,7 @@ func Add(rootCmd *cobra.Command, _ *options.GlobalOptions) { func copyFileContent(src string, dst string) error { sourceFileStat, err := os.Stat(src) if err != nil { - return err + return err } if !sourceFileStat.Mode().IsRegular() { diff --git a/config/config.go b/config/config.go new file mode 100644 index 0000000..b072033 --- /dev/null +++ b/config/config.go @@ -0,0 +1,79 @@ +package config + +import ( + "fmt" + "strings" +) + +type Validator func(interface{}) (interface{}, error) + +// Enum is just a string of a list +func EnumValidator(validValues ...string) Validator { + return func(inputValue interface{}) (interface{}, error) { + _, ok := inputValue.(string) + if !ok { + return "", fmt.Errorf("value \"%s\" is not a string, but of type %T", inputValue, inputValue) + } + isInList := false + for _, validValue := range validValues { + if inputValue == validValue { + isInList = true + break + } + } + if !isInList { + return "", fmt.Errorf("value \"%s\" is not a valid value. Valid Values are %s", inputValue, validValues) + } + + return inputValue, nil + } +} + +// SimpleStringValidator validates if a input is a "simple" string - only single-line strings are supported +func SimpleStringValidator() Validator { + return func(inputValue interface{}) (interface{}, error) { + _, ok := inputValue.(string) + if !ok { + return "", fmt.Errorf("value \"%s\" is not a string, but of type %T", inputValue, inputValue) + } + + if strings.ContainsAny(inputValue.(string), "\r\n") { + return "", fmt.Errorf("value \"%s\" contains illegal line break", inputValue) + } + + return inputValue, nil + } +} + +// Entry contains all the data required for Validation and Convertion +type Entry struct { + Validator Validator +} + +type Configuration map[string]Entry + +func (c Configuration) ValidateEntry(key string, value interface{}) (interface{}, error) { + e, ok := c[key] + if !ok { + return "", fmt.Errorf("key \"%s\" is not a valid key", key) + } + return e.Validator(value) +} + +var BbConfigurationValidation Configuration = map[string]Entry{ + "username": { + Validator: SimpleStringValidator(), + }, + "password": { + Validator: SimpleStringValidator(), + }, + "remote": { + Validator: SimpleStringValidator(), + }, + "git_protocol": { + Validator: EnumValidator("ssh", "https"), + }, + "sync-method": { + Validator: EnumValidator("merge", "rebase"), + }, +}