github.com/lineaje-labs/syft@v0.98.1-0.20231227153149-9e393f60ff1b/syft/pkg/cataloger/dotnet/parse_dotnet_deps.go (about) 1 package dotnet 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "sort" 7 8 "github.com/anchore/syft/syft/artifact" 9 "github.com/anchore/syft/syft/file" 10 "github.com/anchore/syft/syft/pkg" 11 "github.com/anchore/syft/syft/pkg/cataloger/generic" 12 "github.com/lineaje-labs/syft/internal/log" 13 ) 14 15 var _ generic.Parser = parseDotnetDeps 16 17 type dotnetDeps struct { 18 RuntimeTarget dotnetRuntimeTarget `json:"runtimeTarget"` 19 Targets map[string]map[string]dotnetDepsTarget `json:"targets"` 20 Libraries map[string]dotnetDepsLibrary `json:"libraries"` 21 } 22 23 type dotnetRuntimeTarget struct { 24 Name string `json:"name"` 25 } 26 27 type dotnetDepsTarget struct { 28 Dependencies map[string]string `json:"dependencies"` 29 Runtime map[string]struct{} `json:"runtime"` 30 } 31 32 type dotnetDepsLibrary struct { 33 Type string `json:"type"` 34 Path string `json:"path"` 35 Sha512 string `json:"sha512"` 36 HashPath string `json:"hashPath"` 37 } 38 39 //nolint:funlen 40 func parseDotnetDeps( 41 _ file.Resolver, _ *generic.Environment, reader file.LocationReadCloser, 42 ) ([]pkg.Package, []artifact.Relationship, error) { 43 var pkgs []pkg.Package 44 var pkgMap = make(map[string]pkg.Package) 45 var relationships []artifact.Relationship 46 47 dec := json.NewDecoder(reader) 48 49 var depsDoc dotnetDeps 50 if err := dec.Decode(&depsDoc); err != nil { 51 return nil, nil, fmt.Errorf("failed to parse deps.json file: %w", err) 52 } 53 54 rootName := getDepsJSONFilePrefix(reader.Path()) 55 if rootName == "" { 56 return nil, nil, fmt.Errorf("unable to determine root package name from deps.json file: %s", reader.Path()) 57 } 58 var rootPkg *pkg.Package 59 for nameVersion, lib := range depsDoc.Libraries { 60 name, _ := extractNameAndVersion(nameVersion) 61 if lib.Type == "project" && name == rootName { 62 rootPkg = newDotnetDepsPackage( 63 nameVersion, 64 lib, 65 reader.Location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation), 66 ) 67 } 68 } 69 if rootPkg == nil { 70 return nil, nil, fmt.Errorf("unable to determine root package from deps.json file: %s", reader.Path()) 71 } 72 pkgs = append(pkgs, *rootPkg) 73 pkgMap[createNameAndVersion(rootPkg.Name, rootPkg.Version)] = *rootPkg 74 75 var names []string 76 for nameVersion := range depsDoc.Libraries { 77 names = append(names, nameVersion) 78 } 79 // sort the names so that the order of the packages is deterministic 80 sort.Strings(names) 81 82 for _, nameVersion := range names { 83 // skip the root package 84 name, version := extractNameAndVersion(nameVersion) 85 if name == rootPkg.Name && version == rootPkg.Version { 86 continue 87 } 88 89 lib := depsDoc.Libraries[nameVersion] 90 dotnetPkg := newDotnetDepsPackage( 91 nameVersion, 92 lib, 93 reader.Location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation), 94 ) 95 96 if dotnetPkg != nil { 97 pkgs = append(pkgs, *dotnetPkg) 98 pkgMap[nameVersion] = *dotnetPkg 99 } 100 } 101 102 for pkgNameVersion, target := range depsDoc.Targets[depsDoc.RuntimeTarget.Name] { 103 for depName, depVersion := range target.Dependencies { 104 depNameVersion := createNameAndVersion(depName, depVersion) 105 depPkg, ok := pkgMap[depNameVersion] 106 if !ok { 107 log.Debug("unable to find package in map", depNameVersion) 108 continue 109 } 110 p, ok := pkgMap[pkgNameVersion] 111 if !ok { 112 log.Debug("unable to find package in map", pkgNameVersion) 113 continue 114 } 115 rel := artifact.Relationship{ 116 From: depPkg, 117 To: p, 118 Type: artifact.DependencyOfRelationship, 119 } 120 relationships = append(relationships, rel) 121 } 122 } 123 124 // sort the relationships for deterministic output 125 // TODO: ideally this would be replaced with artifact.SortRelationships when one exists and is type agnostic. 126 // this will only consider package-to-package relationships. 127 pkg.SortRelationships(relationships) 128 129 return pkgs, relationships, nil 130 }