forked from anchore/syft
-
Notifications
You must be signed in to change notification settings - Fork 0
/
component.go
126 lines (106 loc) · 3.47 KB
/
component.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
package cyclonedxhelpers
import (
"reflect"
"github.com/CycloneDX/cyclonedx-go"
"github.com/anchore/packageurl-go"
"github.com/anchore/syft/internal/formats/common"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/source"
)
func encodeComponent(p pkg.Package) cyclonedx.Component {
props := encodeProperties(p, "syft:package")
props = append(props, encodeCPEs(p)...)
locations := p.Locations.ToSlice()
if len(locations) > 0 {
props = append(props, encodeProperties(locations, "syft:location")...)
}
if hasMetadata(p) {
props = append(props, encodeProperties(p.Metadata, "syft:metadata")...)
}
var properties *[]cyclonedx.Property
if len(props) > 0 {
properties = &props
}
return cyclonedx.Component{
Type: cyclonedx.ComponentTypeLibrary,
Name: p.Name,
Group: encodeGroup(p),
Version: p.Version,
PackageURL: p.PURL,
Licenses: encodeLicenses(p),
CPE: encodeSingleCPE(p),
Author: encodeAuthor(p),
Publisher: encodePublisher(p),
Description: encodeDescription(p),
ExternalReferences: encodeExternalReferences(p),
Properties: properties,
BOMRef: deriveBomRef(p),
}
}
func deriveBomRef(p pkg.Package) string {
// try and parse the PURL if possible and append syft id to it, to make
// the purl unique in the BOM.
// TODO: In the future we may want to dedupe by PURL and combine components with
// the same PURL while preserving their unique metadata.
if parsedPURL, err := packageurl.FromString(p.PURL); err == nil {
parsedPURL.Qualifiers = append(parsedPURL.Qualifiers, packageurl.Qualifier{Key: "syft-id", Value: string(p.ID())})
return parsedPURL.ToString()
}
// fallback is to use strictly the ID if there is no valid pURL
return string(p.ID())
}
func hasMetadata(p pkg.Package) bool {
return p.Metadata != nil
}
func decodeComponent(c *cyclonedx.Component) *pkg.Package {
values := map[string]string{}
if c.Properties != nil {
for _, p := range *c.Properties {
values[p.Name] = p.Value
}
}
p := &pkg.Package{
Name: c.Name,
Version: c.Version,
Locations: decodeLocations(values),
Licenses: decodeLicenses(c),
CPEs: decodeCPEs(c),
PURL: c.PackageURL,
}
common.DecodeInto(p, values, "syft:package", CycloneDXFields)
p.Metadata = decodePackageMetadata(values, c, p.MetadataType)
if p.Type == "" {
p.Type = pkg.TypeFromPURL(p.PURL)
}
if p.Language == "" {
p.Language = pkg.LanguageFromPURL(p.PURL)
}
return p
}
func decodeLocations(vals map[string]string) source.LocationSet {
v := common.Decode(reflect.TypeOf([]source.Location{}), vals, "syft:location", CycloneDXFields)
out, ok := v.([]source.Location)
if !ok {
out = nil
}
return source.NewLocationSet(out...)
}
func decodePackageMetadata(vals map[string]string, c *cyclonedx.Component, typ pkg.MetadataType) interface{} {
if typ != "" && c.Properties != nil {
metaTyp, ok := pkg.MetadataTypeByName[typ]
if !ok {
return nil
}
metaPtrTyp := reflect.PtrTo(metaTyp)
metaPtr := common.Decode(metaPtrTyp, vals, "syft:metadata", CycloneDXFields)
// 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 common.PtrToStruct(metaPtr)
}
return nil
}