Fix panic in pom parsing (#2064)

A recent update to gopom changed many fields to be omitted when empty,
resulting in a number of nil pointers inside the nested structure of the
pom that previously didn't exist. Defend against these in the search for
the property value.

Signed-off-by: Will Murphy <will.murphy@anchore.com>
This commit is contained in:
William Murphy 2023-08-25 12:04:57 -04:00 committed by GitHub
parent faa902209e
commit d08e2be768
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 30 additions and 2 deletions

View File

@ -188,7 +188,7 @@ func resolveProperty(pom gopom.Project, property *string, propertyName string) s
propertyCase := safeString(property) propertyCase := safeString(property)
log.WithFields("existingPropertyValue", propertyCase, "propertyName", propertyName).Trace("resolving property") log.WithFields("existingPropertyValue", propertyCase, "propertyName", propertyName).Trace("resolving property")
return propertyMatcher.ReplaceAllStringFunc(propertyCase, func(match string) string { return propertyMatcher.ReplaceAllStringFunc(propertyCase, func(match string) string {
propertyName := strings.TrimSpace(match[2 : len(match)-1]) propertyName := strings.TrimSpace(match[2 : len(match)-1]) // remove leading ${ and trailing }
entries := pomProperties(pom) entries := pomProperties(pom)
if value, ok := entries[propertyName]; ok { if value, ok := entries[propertyName]; ok {
return value return value
@ -210,16 +210,26 @@ func resolveProperty(pom gopom.Project, property *string, propertyName string) s
for fieldNum := 0; fieldNum < pomValueType.NumField(); fieldNum++ { for fieldNum := 0; fieldNum < pomValueType.NumField(); fieldNum++ {
f := pomValueType.Field(fieldNum) f := pomValueType.Field(fieldNum)
tag := f.Tag.Get("xml") tag := f.Tag.Get("xml")
tag = strings.TrimSuffix(tag, ",omitempty") tag = strings.Split(tag, ",")[0]
// a segment of the property name matches the xml tag for the field,
// so we need to recurse down the nested structs or return a match
// if we're done.
if part == tag { if part == tag {
pomValue = pomValue.Field(fieldNum) pomValue = pomValue.Field(fieldNum)
pomValueType = pomValue.Type() pomValueType = pomValue.Type()
if pomValueType.Kind() == reflect.Ptr { if pomValueType.Kind() == reflect.Ptr {
// we were recursing down the nested structs, but one of the steps
// we need to take is a nil pointer, so give up and return the original match
if pomValue.IsNil() {
return match
}
pomValue = pomValue.Elem() pomValue = pomValue.Elem()
if !pomValue.IsZero() { if !pomValue.IsZero() {
// we found a non-zero value whose tag matches this part of the property name
pomValueType = pomValue.Type() pomValueType = pomValue.Type()
} }
} }
// If this was the last part of the property name, return the value
if partNum == numParts-1 { if partNum == numParts-1 {
return fmt.Sprintf("%v", pomValue.Interface()) return fmt.Sprintf("%v", pomValue.Interface())
} }

View File

@ -446,6 +446,24 @@ func Test_resolveProperty(t *testing.T) {
}, },
expected: "org.some.parent", expected: "org.some.parent",
}, },
{
name: "nil pointer halts search",
property: "${project.parent.groupId}",
pom: gopom.Project{
Parent: nil,
},
expected: "${project.parent.groupId}",
},
{
name: "nil string pointer halts search",
property: "${project.parent.groupId}",
pom: gopom.Project{
Parent: &gopom.Parent{
GroupID: nil,
},
},
expected: "${project.parent.groupId}",
},
} }
for _, test := range tests { for _, test := range tests {