From ebd7c9fb53367865c11763759d217dda639f2730 Mon Sep 17 00:00:00 2001 From: Harry Bagdi Date: Mon, 9 Nov 2020 12:27:47 -0600 Subject: [PATCH] fix(file) convert yaml to JSON `go-yaml` marshals into `map[interface{}]interface{}`. This change ensures that `map[interface{}]interface{}` is converted into `map[string]interface{}` RECURSIVELY. See #144 --- file/readfile.go | 13 +++++++++++-- file/readfile_test.go | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/file/readfile.go b/file/readfile.go index 1d9d46f1e..5892fc5b4 100644 --- a/file/readfile.go +++ b/file/readfile.go @@ -8,9 +8,9 @@ import ( "path/filepath" "regexp" + ghodssyaml "github.com/ghodss/yaml" "github.com/imdario/mergo" "github.com/pkg/errors" - yaml "gopkg.in/yaml.v2" ) // getContent reads all the YAML and JSON files in the directory or the @@ -91,13 +91,22 @@ func readContent(reader io.Reader) (*Content, error) { if err != nil { return nil, errors.Wrap(err, "validating file content") } - err = yaml.Unmarshal(bytes, &content) + err = yamlUnmarshal(bytes, &content) if err != nil { return nil, err } return &content, nil } +// yamlUnmarshal is a wrapper around yaml.Unmarshal to ensure that the right +// yaml package is in use. Using ghodss/yaml ensures that no +// `map[interface{}]interface{}` is present in go-kong.Plugin.Configuration. +// If it is present, then it leads to a silent error. See Github Issue #144. +// The verification for this is done using a test. +func yamlUnmarshal(bytes []byte, v interface{}) error { + return ghodssyaml.Unmarshal(bytes, v) +} + // configFilesInDir traverses the directory rooted at dir and // returns all the files with a case-insensitive extension of `yml` or `yaml`. func configFilesInDir(dir string) ([]string, error) { diff --git a/file/readfile_test.go b/file/readfile_test.go index 7bb488890..0ec7b15d5 100644 --- a/file/readfile_test.go +++ b/file/readfile_test.go @@ -315,3 +315,37 @@ func Test_getContent(t *testing.T) { }) } } + +func Test_yamlUnmarshal(t *testing.T) { + stringToInterfaceMap := map[string]interface{}{} + bytes1 := ` +versions: + v1: + enabled: false +` + mapOfMap := map[string]interface{}{} + err := yamlUnmarshal([]byte(bytes1), &mapOfMap) + if err != nil { + t.Errorf("yamlUnmarshal() error = %v (should be nil)", err) + } + subMap := mapOfMap["versions"] + if reflect.TypeOf(subMap) != reflect.TypeOf(stringToInterfaceMap) { + t.Errorf("yamlUnmarshal() expected type: %T, got: %T", stringToInterfaceMap, subMap) + } + + bytes2 := ` +versions: +- enabled: false + version: 1 +` + mapOfArrayOfMap := map[string]interface{}{} + err = yamlUnmarshal([]byte(bytes2), &mapOfArrayOfMap) + if err != nil { + t.Errorf("yamlUnmarshal() error = %v (should be nil)", err) + } + array := mapOfArrayOfMap["versions"].([]interface{}) + element := array[0] + if reflect.TypeOf(element) != reflect.TypeOf(stringToInterfaceMap) { + t.Errorf("yamlUnmarshal() expected type: %T, got: %T", stringToInterfaceMap, element) + } +}