forked from anchore/syft
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
34 changed files
with
1,027 additions
and
66 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,27 +1,164 @@ | ||
package cyclonedxhelpers | ||
|
||
import ( | ||
"fmt" | ||
"reflect" | ||
"strconv" | ||
|
||
"github.com/CycloneDX/cyclonedx-go" | ||
|
||
"github.com/anchore/syft/internal/log" | ||
"github.com/anchore/syft/syft/pkg" | ||
"github.com/anchore/syft/syft/source" | ||
) | ||
|
||
func Component(p pkg.Package) cyclonedx.Component { | ||
func encodeComponent(p pkg.Package) cyclonedx.Component { | ||
return cyclonedx.Component{ | ||
Type: cyclonedx.ComponentTypeLibrary, | ||
Name: p.Name, | ||
Group: Group(p), | ||
Group: encodeGroup(p), | ||
Version: p.Version, | ||
PackageURL: p.PURL, | ||
Licenses: Licenses(p), | ||
CPE: CPE(p), | ||
Author: Author(p), | ||
Publisher: Publisher(p), | ||
Description: Description(p), | ||
ExternalReferences: ExternalReferences(p), | ||
Properties: Properties(p), | ||
Licenses: encodeLicenses(p), | ||
CPE: encodeCPE(p), | ||
Author: encodeAuthor(p), | ||
Publisher: encodePublisher(p), | ||
Description: encodeDescription(p), | ||
ExternalReferences: encodeExternalReferences(p), | ||
Properties: encodeProperties(p), | ||
} | ||
} | ||
|
||
func hasMetadata(p pkg.Package) bool { | ||
return p.Metadata != nil | ||
} | ||
|
||
func decodeComponent(c *cyclonedx.Component) *pkg.Package { | ||
typ := pkg.Type(findPropertyValue(c, "type")) | ||
purl := c.PackageURL | ||
if typ == "" && purl != "" { | ||
typ = pkg.TypeFromPURL(purl) | ||
} | ||
|
||
metaType, meta := decodePackageMetadata(c) | ||
|
||
p := &pkg.Package{ | ||
Name: c.Name, | ||
Version: c.Version, | ||
FoundBy: findPropertyValue(c, "foundBy"), | ||
Locations: decodeLocations(c), | ||
Licenses: decodeLicenses(c), | ||
Language: pkg.Language(findPropertyValue(c, "language")), | ||
Type: typ, | ||
CPEs: decodeCPEs(c), | ||
PURL: purl, | ||
MetadataType: metaType, | ||
Metadata: meta, | ||
} | ||
|
||
return p | ||
} | ||
|
||
func decodeLocations(c *cyclonedx.Component) (out []source.Location) { | ||
if c.Properties != nil { | ||
props := *c.Properties | ||
for i := 0; i < len(props)-1; i++ { | ||
if props[i].Name == "path" && props[i+1].Name == "layerID" { | ||
out = append(out, source.Location{ | ||
Coordinates: source.Coordinates{ | ||
RealPath: props[i].Value, | ||
FileSystemID: props[i+1].Value, | ||
}, | ||
}) | ||
i++ | ||
} | ||
} | ||
} | ||
return | ||
} | ||
|
||
func mapAllProps(c *cyclonedx.Component, obj reflect.Value) { | ||
value := obj | ||
if value.Kind() == reflect.Ptr { | ||
value = value.Elem() | ||
} | ||
|
||
structType := value.Type() | ||
if structType.Kind() != reflect.Struct { | ||
return | ||
} | ||
for i := 0; i < value.NumField(); i++ { | ||
field := structType.Field(i) | ||
fieldType := field.Type | ||
fieldValue := value.Field(i) | ||
|
||
name, mapped := field.Tag.Lookup("cyclonedx") | ||
if !mapped { | ||
continue | ||
} | ||
|
||
if fieldType.Kind() == reflect.Ptr { | ||
fieldType = fieldType.Elem() | ||
if fieldValue.IsNil() { | ||
newValue := reflect.New(fieldType) | ||
fieldValue.Set(newValue) | ||
} | ||
fieldValue = fieldValue.Elem() | ||
} | ||
|
||
propertyValue := findPropertyValue(c, name) | ||
switch fieldType.Kind() { | ||
case reflect.String: | ||
if fieldValue.CanSet() { | ||
fieldValue.SetString(propertyValue) | ||
} else { | ||
msg := fmt.Sprintf("unable to set field: %s.%s", structType.Name(), field.Name) | ||
log.Info(msg) | ||
} | ||
case reflect.Bool: | ||
if b, err := strconv.ParseBool(propertyValue); err == nil { | ||
fieldValue.SetBool(b) | ||
} | ||
case reflect.Int: | ||
if i, err := strconv.Atoi(propertyValue); err == nil { | ||
fieldValue.SetInt(int64(i)) | ||
} | ||
case reflect.Float32, reflect.Float64: | ||
if i, err := strconv.ParseFloat(propertyValue, 64); err == nil { | ||
fieldValue.SetFloat(i) | ||
} | ||
case reflect.Struct: | ||
mapAllProps(c, fieldValue) | ||
case reflect.Complex128, reflect.Complex64: | ||
fallthrough | ||
case reflect.Ptr: | ||
msg := fmt.Sprintf("decoding CycloneDX properties to a pointer is not supported: %s.%s", field.Type.Name(), field.Name) | ||
log.Warnf(msg) | ||
} | ||
} | ||
} | ||
|
||
func decodePackageMetadata(c *cyclonedx.Component) (pkg.MetadataType, interface{}) { | ||
if c.Properties != nil { | ||
typ := pkg.MetadataType(findPropertyValue(c, "metadataType")) | ||
if typ != "" { | ||
meta := reflect.New(pkg.MetadataTypeByName[typ]) | ||
metaPtr := meta.Interface() | ||
|
||
// Map all dynamic properties | ||
mapAllProps(c, meta.Elem()) | ||
|
||
// Map all explicit metadata properties | ||
decodeAuthor(c.Author, metaPtr) | ||
decodeGroup(c.Group, metaPtr) | ||
decodePublisher(c.Publisher, metaPtr) | ||
decodeDescription(c.Description, metaPtr) | ||
decodeExternalReferences(c, metaPtr) | ||
|
||
// return the actual interface{} | struct ( not interface{} | *struct ) | ||
return typ, meta.Elem().Interface() | ||
} | ||
} | ||
|
||
return pkg.UnknownMetadataType, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,30 @@ | ||
package cyclonedxhelpers | ||
|
||
import "github.com/anchore/syft/syft/pkg" | ||
import ( | ||
"github.com/CycloneDX/cyclonedx-go" | ||
"github.com/anchore/syft/internal/log" | ||
"github.com/anchore/syft/syft/pkg" | ||
) | ||
|
||
func CPE(p pkg.Package) string { | ||
func encodeCPE(p pkg.Package) string { | ||
// Since the CPEs in a package are sorted by specificity | ||
// we can extract the first CPE as the one to output in cyclonedx | ||
if len(p.CPEs) > 0 { | ||
return pkg.CPEString(p.CPEs[0]) | ||
} | ||
return "" | ||
} | ||
|
||
func decodeCPEs(c *cyclonedx.Component) []pkg.CPE { | ||
// FIXME we not encoding all the CPEs (see above), so here we just use the single provided one | ||
if c.CPE != "" { | ||
cp, err := pkg.NewCPE(c.CPE) | ||
if err != nil { | ||
log.Warnf("invalid CPE: %s", c.CPE) | ||
} else { | ||
return []pkg.CPE{cp} | ||
} | ||
} | ||
|
||
return []pkg.CPE{} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.