From 03612a28b8139d27e2455e80bfa7a8bc560656ef Mon Sep 17 00:00:00 2001 From: zt2 Date: Sun, 27 Feb 2022 22:28:00 +0800 Subject: [PATCH 1/2] feat(template): allow custom type in metadata In some case you may need to use custom type in `metadata`, like nested array or nested k-v: ```yaml info: metadata: components: - bootstrap - jquery ``` So this commit allowed use any custom type in `metadata`. --- v2/pkg/model/model.go | 2 +- v2/pkg/model/model_test.go | 33 +++++++++++++++++++++----- v2/pkg/reporting/format/format.go | 9 ++++--- v2/pkg/reporting/format/format_test.go | 2 +- v2/pkg/utils/insertion_ordered_map.go | 10 ++++---- 5 files changed, 40 insertions(+), 16 deletions(-) diff --git a/v2/pkg/model/model.go b/v2/pkg/model/model.go index f8ddb0858..2a31329ff 100644 --- a/v2/pkg/model/model.go +++ b/v2/pkg/model/model.go @@ -57,7 +57,7 @@ type Info struct { // examples: // - value: > // map[string]string{"customField1":"customValue1"} - Metadata map[string]string `json:"metadata,omitempty" yaml:"metadata,omitempty" jsonschema:"title=additional metadata for the template,description=Additional metadata fields for the template"` + Metadata map[string]interface{} `json:"metadata,omitempty" yaml:"metadata,omitempty" jsonschema:"title=additional metadata for the template,description=Additional metadata fields for the template"` // description: | // Classification contains classification information about the template. diff --git a/v2/pkg/model/model_test.go b/v2/pkg/model/model_test.go index e0803c31a..d706cdce8 100644 --- a/v2/pkg/model/model_test.go +++ b/v2/pkg/model/model_test.go @@ -21,12 +21,19 @@ func TestInfoJsonMarshal(t *testing.T) { SeverityHolder: severity.Holder{Severity: severity.High}, Tags: stringslice.StringSlice{Value: []string{"cve", "misc"}}, Reference: stringslice.StringSlice{Value: "reference1"}, + Metadata: map[string]interface{}{ + "string_key": "string_value", + "array_key": []string{"array_value1", "array_value2"}, + "map_key": map[string]string{ + "key1": "val1", + }, + }, } result, err := json.Marshal(&info) assert.Nil(t, err) - expected := `{"name":"Test Template Name","author":["forgedhallpass","ice3man"],"tags":["cve","misc"],"description":"Test description","reference":"reference1","severity":"high"}` + expected := `{"name":"Test Template Name","author":["forgedhallpass","ice3man"],"tags":["cve","misc"],"description":"Test description","reference":"reference1","severity":"high","metadata":{"array_key":["array_value1","array_value2"],"map_key":{"key1":"val1"},"string_key":"string_value"}}` assert.Equal(t, expected, string(result)) } @@ -38,6 +45,13 @@ func TestInfoYamlMarshal(t *testing.T) { SeverityHolder: severity.Holder{Severity: severity.High}, Tags: stringslice.StringSlice{Value: []string{"cve", "misc"}}, Reference: stringslice.StringSlice{Value: "reference1"}, + Metadata: map[string]interface{}{ + "string_key": "string_value", + "array_key": []string{"array_value1", "array_value2"}, + "map_key": map[string]string{ + "key1": "val1", + }, + }, } result, err := yaml.Marshal(&info) @@ -53,6 +67,13 @@ tags: description: Test description reference: reference1 severity: high +metadata: + array_key: + - array_value1 + - array_value2 + map_key: + key1: val1 + string_key: string_value ` assert.Equal(t, expected, string(result)) } @@ -66,7 +87,7 @@ func TestUnmarshal(t *testing.T) { dynamicKey1 := "customDynamicKey1" dynamicKey2 := "customDynamicKey2" - dynamicKeysMap := map[string]string{ + dynamicKeysMap := map[string]interface{}{ dynamicKey1: "customDynamicValue1", dynamicKey2: "customDynamicValue2", } @@ -92,8 +113,8 @@ func TestUnmarshal(t *testing.T) { severity: critical reference: ` + strings.Join(references, ", ") + ` metadata: - ` + dynamicKey1 + `: ` + dynamicKeysMap[dynamicKey1] + ` - ` + dynamicKey2 + `: ` + dynamicKeysMap[dynamicKey2] + ` + ` + dynamicKey1 + `: ` + dynamicKeysMap[dynamicKey1].(string) + ` + ` + dynamicKey2 + `: ` + dynamicKeysMap[dynamicKey2].(string) + ` ` yamlPayload2 := ` name: ` + templateName + ` @@ -108,8 +129,8 @@ func TestUnmarshal(t *testing.T) { - ` + references[0] + ` # comments are not unmarshalled - ` + references[1] + ` metadata: - ` + dynamicKey1 + `: ` + dynamicKeysMap[dynamicKey1] + ` - ` + dynamicKey2 + `: ` + dynamicKeysMap[dynamicKey2] + ` + ` + dynamicKey1 + `: ` + dynamicKeysMap[dynamicKey1].(string) + ` + ` + dynamicKey2 + `: ` + dynamicKeysMap[dynamicKey2].(string) + ` ` info1 := assertUnmarshalledTemplateInfo(t, yamlPayload1) diff --git a/v2/pkg/reporting/format/format.go b/v2/pkg/reporting/format/format.go index 4f9d3e526..baaca4bb1 100644 --- a/v2/pkg/reporting/format/format.go +++ b/v2/pkg/reporting/format/format.go @@ -181,9 +181,12 @@ func ToMarkdownTableString(templateInfo *model.Info) string { builder := &bytes.Buffer{} toMarkDownTable := func(insertionOrderedStringMap *utils.InsertionOrderedStringMap) { - insertionOrderedStringMap.ForEach(func(key string, value string) { - if utils.IsNotBlank(value) { - builder.WriteString(fmt.Sprintf("| %s | %s |\n", key, value)) + insertionOrderedStringMap.ForEach(func(key string, value interface{}) { + switch value.(type) { + case string: + if utils.IsNotBlank(value.(string)) { + builder.WriteString(fmt.Sprintf("| %s | %s |\n", key, value)) + } } }) } diff --git a/v2/pkg/reporting/format/format_test.go b/v2/pkg/reporting/format/format_test.go index 340424a72..101d1b8a2 100644 --- a/v2/pkg/reporting/format/format_test.go +++ b/v2/pkg/reporting/format/format_test.go @@ -19,7 +19,7 @@ func TestToMarkdownTableString(t *testing.T) { SeverityHolder: severity.Holder{Severity: severity.High}, Tags: stringslice.StringSlice{Value: []string{"cve", "misc"}}, Reference: stringslice.StringSlice{Value: "reference1"}, - Metadata: map[string]string{ + Metadata: map[string]interface{}{ "customDynamicKey1": "customDynamicValue1", "customDynamicKey2": "customDynamicValue2", }, diff --git a/v2/pkg/utils/insertion_ordered_map.go b/v2/pkg/utils/insertion_ordered_map.go index d8b432862..f8391c2fe 100644 --- a/v2/pkg/utils/insertion_ordered_map.go +++ b/v2/pkg/utils/insertion_ordered_map.go @@ -2,17 +2,17 @@ package utils type InsertionOrderedStringMap struct { keys []string `yaml:"-"` - values map[string]string + values map[string]interface{} } func NewEmptyInsertionOrderedStringMap(size int) *InsertionOrderedStringMap { return &InsertionOrderedStringMap{ keys: make([]string, 0, size), - values: make(map[string]string, size), + values: make(map[string]interface{}, size), } } -func NewInsertionOrderedStringMap(stringMap map[string]string) *InsertionOrderedStringMap { +func NewInsertionOrderedStringMap(stringMap map[string]interface{}) *InsertionOrderedStringMap { result := NewEmptyInsertionOrderedStringMap(len(stringMap)) for k, v := range stringMap { @@ -22,13 +22,13 @@ func NewInsertionOrderedStringMap(stringMap map[string]string) *InsertionOrdered return result } -func (insertionOrderedStringMap *InsertionOrderedStringMap) ForEach(fn func(key string, data string)) { +func (insertionOrderedStringMap *InsertionOrderedStringMap) ForEach(fn func(key string, data interface{})) { for _, key := range insertionOrderedStringMap.keys { fn(key, insertionOrderedStringMap.values[key]) } } -func (insertionOrderedStringMap *InsertionOrderedStringMap) Set(key string, value string) { +func (insertionOrderedStringMap *InsertionOrderedStringMap) Set(key string, value interface{}) { _, present := insertionOrderedStringMap.values[key] insertionOrderedStringMap.values[key] = value if !present { From 4e384e3814aa9258b70465f2fd79acb41ec340c6 Mon Sep 17 00:00:00 2001 From: zt2 Date: Mon, 28 Feb 2022 00:04:35 +0800 Subject: [PATCH 2/2] style: switch lint --- v2/pkg/reporting/format/format.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/v2/pkg/reporting/format/format.go b/v2/pkg/reporting/format/format.go index baaca4bb1..14153037e 100644 --- a/v2/pkg/reporting/format/format.go +++ b/v2/pkg/reporting/format/format.go @@ -182,9 +182,9 @@ func ToMarkdownTableString(templateInfo *model.Info) string { toMarkDownTable := func(insertionOrderedStringMap *utils.InsertionOrderedStringMap) { insertionOrderedStringMap.ForEach(func(key string, value interface{}) { - switch value.(type) { + switch value := value.(type) { case string: - if utils.IsNotBlank(value.(string)) { + if utils.IsNotBlank(value) { builder.WriteString(fmt.Sprintf("| %s | %s |\n", key, value)) } }