github.com/devseccon/trivy@v0.47.1-0.20231123133102-bd902a0bd996/pkg/fanal/analyzer/language/dotnet/nuget/nuget.go (about) 1 package nuget 2 3 import ( 4 "context" 5 "errors" 6 "io" 7 "io/fs" 8 "os" 9 "path/filepath" 10 "sort" 11 12 "golang.org/x/exp/slices" 13 "golang.org/x/xerrors" 14 15 "github.com/aquasecurity/go-dep-parser/pkg/nuget/config" 16 "github.com/aquasecurity/go-dep-parser/pkg/nuget/lock" 17 godeptypes "github.com/aquasecurity/go-dep-parser/pkg/types" 18 "github.com/devseccon/trivy/pkg/fanal/analyzer" 19 "github.com/devseccon/trivy/pkg/fanal/analyzer/language" 20 "github.com/devseccon/trivy/pkg/fanal/types" 21 "github.com/devseccon/trivy/pkg/utils/fsutils" 22 ) 23 24 func init() { 25 analyzer.RegisterPostAnalyzer(analyzer.TypeNuget, newNugetLibraryAnalyzer) 26 } 27 28 const ( 29 version = 3 30 lockFile = types.NuGetPkgsLock 31 configFile = types.NuGetPkgsConfig 32 ) 33 34 var requiredFiles = []string{lockFile, configFile} 35 36 type nugetLibraryAnalyzer struct { 37 lockParser godeptypes.Parser 38 configParser godeptypes.Parser 39 licenseParser nuspecParser 40 } 41 42 func newNugetLibraryAnalyzer(_ analyzer.AnalyzerOptions) (analyzer.PostAnalyzer, error) { 43 return &nugetLibraryAnalyzer{ 44 lockParser: lock.NewParser(), 45 configParser: config.NewParser(), 46 licenseParser: newNuspecParser(), 47 }, nil 48 } 49 50 func (a *nugetLibraryAnalyzer) PostAnalyze(_ context.Context, input analyzer.PostAnalysisInput) (*analyzer.AnalysisResult, error) { 51 var apps []types.Application 52 foundLicenses := make(map[string][]string) 53 54 // We saved only config and lock files in the FS, 55 // so we need to parse all saved files 56 required := func(path string, d fs.DirEntry) bool { 57 return true 58 } 59 60 err := fsutils.WalkDir(input.FS, ".", required, func(path string, d fs.DirEntry, r io.Reader) error { 61 // Set the default parser 62 parser := a.lockParser 63 64 targetFile := filepath.Base(path) 65 if targetFile == configFile { 66 parser = a.configParser 67 } 68 69 app, err := language.Parse(types.NuGet, path, r, parser) 70 if err != nil { 71 return xerrors.Errorf("NuGet parse error: %w", err) 72 } 73 74 // nuget file doesn't contain dependencies 75 if app == nil { 76 return nil 77 } 78 79 for i, lib := range app.Libraries { 80 license, ok := foundLicenses[lib.ID] 81 if !ok { 82 license, err = a.licenseParser.findLicense(lib.Name, lib.Version) 83 if err != nil && !errors.Is(err, fs.ErrNotExist) { 84 return xerrors.Errorf("license find error: %w", err) 85 } 86 foundLicenses[lib.ID] = license 87 } 88 89 app.Libraries[i].Licenses = license 90 } 91 92 sort.Sort(app.Libraries) 93 apps = append(apps, *app) 94 return nil 95 }) 96 if err != nil { 97 return nil, xerrors.Errorf("NuGet walk error: %w", err) 98 } 99 100 return &analyzer.AnalysisResult{ 101 Applications: apps, 102 }, nil 103 } 104 105 func (a *nugetLibraryAnalyzer) Required(filePath string, _ os.FileInfo) bool { 106 fileName := filepath.Base(filePath) 107 return slices.Contains(requiredFiles, fileName) 108 } 109 110 func (a *nugetLibraryAnalyzer) Type() analyzer.Type { 111 return analyzer.TypeNuget 112 } 113 114 func (a *nugetLibraryAnalyzer) Version() int { 115 return version 116 }