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`.
dev
zt2 2022-02-27 22:28:00 +08:00
parent c0932168ac
commit 03612a28b8
5 changed files with 40 additions and 16 deletions

View File

@ -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.

View File

@ -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)

View File

@ -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))
}
}
})
}

View File

@ -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",
},

View File

@ -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 {