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  }