github.com/lineaje-labs/syft@v0.98.1-0.20231227153149-9e393f60ff1b/syft/pkg/cataloger/cpp/parse_conanlock.go (about) 1 package cpp 2 3 import ( 4 "encoding/json" 5 "strings" 6 7 "github.com/anchore/syft/syft/artifact" 8 "github.com/anchore/syft/syft/file" 9 "github.com/anchore/syft/syft/pkg" 10 "github.com/anchore/syft/syft/pkg/cataloger/generic" 11 ) 12 13 var _ generic.Parser = parseConanlock 14 15 type conanLock struct { 16 GraphLock struct { 17 Nodes map[string]struct { 18 Ref string `json:"ref"` 19 PackageID string `json:"package_id"` 20 Context string `json:"context"` 21 Prev string `json:"prev"` 22 Requires []string `json:"requires"` 23 PythonRequires string `json:"py_requires"` 24 Options string `json:"options"` 25 Path string `json:"path"` 26 } `json:"nodes"` 27 } `json:"graph_lock"` 28 Version string `json:"version"` 29 ProfileHost string `json:"profile_host"` 30 } 31 32 // parseConanlock is a parser function for conan.lock contents, returning all packages discovered. 33 func parseConanlock(_ file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) { 34 var pkgs []pkg.Package 35 var cl conanLock 36 if err := json.NewDecoder(reader).Decode(&cl); err != nil { 37 return nil, nil, err 38 } 39 40 // requires is a list of package indices. We first need to fill it, and then we can resolve the package 41 // in a second iteration 42 var indexToPkgMap = map[string]pkg.Package{} 43 44 // we do not want to store the index list requires in the conan metadata, because it is not useful to have it in 45 // the SBOM. Instead, we will store it in a map and then use it to build the relationships 46 // maps pkg.ID to a list of indices 47 var parsedPkgRequires = map[artifact.ID][]string{} 48 49 for idx, node := range cl.GraphLock.Nodes { 50 metadata := pkg.ConanLockEntry{ 51 Ref: node.Ref, 52 Options: parseOptions(node.Options), 53 Path: node.Path, 54 Context: node.Context, 55 PackageID: node.PackageID, 56 Prev: node.Prev, 57 } 58 59 p := newConanlockPackage( 60 metadata, 61 reader.Location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation), 62 ) 63 64 if p != nil { 65 pk := *p 66 pkgs = append(pkgs, pk) 67 parsedPkgRequires[pk.ID()] = node.Requires 68 indexToPkgMap[idx] = pk 69 } 70 } 71 72 var relationships []artifact.Relationship 73 74 for _, p := range pkgs { 75 requires := parsedPkgRequires[p.ID()] 76 for _, r := range requires { 77 // this is a pkg that package "p" depends on... make a relationship 78 relationships = append(relationships, artifact.Relationship{ 79 From: indexToPkgMap[r], 80 To: p, 81 Type: artifact.DependencyOfRelationship, 82 }) 83 } 84 } 85 86 return pkgs, relationships, nil 87 } 88 89 func parseOptions(options string) map[string]string { 90 o := make(map[string]string) 91 if len(options) == 0 { 92 return nil 93 } 94 95 kvps := strings.Split(options, "\n") 96 for _, kvp := range kvps { 97 kv := strings.Split(kvp, "=") 98 if len(kv) == 2 { 99 o[kv[0]] = kv[1] 100 } 101 } 102 103 return o 104 }