mirror of
https://github.com/aquasecurity/trivy.git
synced 2025-12-23 15:37:50 -08:00
chore(deps): merge go-dep-parser into Trivy (#6094)
Signed-off-by: Arunprasad Rajkumar <arajkuma@redhat.com> Signed-off-by: guoguangwu <guoguangwu@magic-shield.com> Signed-off-by: dependabot[bot] <support@github.com> Signed-off-by: knqyf263 <knqyf263@gmail.com> Co-authored-by: Masahiro <mur4m4s4.331@gmail.com> Co-authored-by: Tomoya Amachi <tomoya.amachi@gmail.com> Co-authored-by: Masahiro <lomycisw@gmail.com> Co-authored-by: Liz Rice <liz@lizrice.com> Co-authored-by: Johannes <johannes@jitesoft.com> Co-authored-by: aprp <doelaudi@gmail.com> Co-authored-by: rahul2393 <rahulyadavsep92@gmail.com> Co-authored-by: Arunprasad Rajkumar <ar.arunprasad@gmail.com> Co-authored-by: Emrecan BATI <emrecanbati@gmail.com> Co-authored-by: sherif84 <12298259+sherif84@users.noreply.github.com> Co-authored-by: Sherif Fathalla <sfathall@akamai.com> Co-authored-by: sherif <sherif.mailbox@gmail.com> Co-authored-by: Sam Lane <samuel.lane@hotmail.com> Co-authored-by: Ankush K <akhobragade@gmail.com> Co-authored-by: Ankush K <akhobragade42@gmail.com> Co-authored-by: Tauseef <tauseefmlk@gmail.com> Co-authored-by: Daniel <danfaizer@gmail.com> Co-authored-by: Matthieu MOREL <mmorel-35@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: afdesk <work@afdesk.com> Co-authored-by: AndreyLevchenko <levchenko.andrey@gmail.com> Co-authored-by: Kobus van Schoor <10784365+kobus-v-schoor@users.noreply.github.com> Co-authored-by: Jan-Otto Kröpke <github@jkroepke.de> Co-authored-by: jerbob92 <jerbob92@users.noreply.github.com> Co-authored-by: DmitriyLewen <91113035+DmitriyLewen@users.noreply.github.com> Co-authored-by: Shira Cohen <97398476+ShiraCohen33@users.noreply.github.com> Co-authored-by: astevenson-microsoft <78623826+astevenson-microsoft@users.noreply.github.com> Co-authored-by: Kyriakos Georgiou <kgeorgiou@users.noreply.github.com> Co-authored-by: mycodeself <mycodeself@users.noreply.github.com> Co-authored-by: DavidSalame <75929252+davidsalame1@users.noreply.github.com> Co-authored-by: Tom Fay <tom@teamfay.co.uk> Co-authored-by: Tom Fay <tomfay@microsoft.com> Co-authored-by: François Poirotte <fpoirotte@users.noreply.github.com> Co-authored-by: Guy Ben-Aharon <baguy3@gmail.com> Co-authored-by: Catminusminus <37803616+Catminusminus@users.noreply.github.com> Co-authored-by: Lior Vaisman Argon <97836016+VaismanLior@users.noreply.github.com> Co-authored-by: Matthieu Maitre <mmaitre@microsoft.com> Co-authored-by: Andrea Scarpino <andrea@scarpino.dev> Co-authored-by: MorAlon1 <101275199+MorAlon1@users.noreply.github.com> Co-authored-by: liorj-orca <96177663+liorj-orca@users.noreply.github.com> Co-authored-by: Nikita Pivkin <100182843+nikpivkin@users.noreply.github.com> Co-authored-by: guangwu <guoguangwu@magic-shield.com> Co-authored-by: Nikita Pivkin <nikita.pivkin@smartforce.io> Co-authored-by: DmitriyLewen <dmitriy.lewen@smartforce.io> Co-authored-by: yuriShafet <5830215+yuriShafet@users.noreply.github.com> Co-authored-by: Octogonapus <firey45@gmail.com>
This commit is contained in:
162
pkg/dependency/parser/golang/mod/parse.go
Normal file
162
pkg/dependency/parser/golang/mod/parse.go
Normal file
@@ -0,0 +1,162 @@
|
||||
package mod
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/exp/maps"
|
||||
"golang.org/x/mod/modfile"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
dio "github.com/aquasecurity/trivy/pkg/dependency/parser/io"
|
||||
"github.com/aquasecurity/trivy/pkg/dependency/parser/types"
|
||||
)
|
||||
|
||||
var (
|
||||
// By convention, modules with a major version equal to or above v2
|
||||
// have it as suffix in their module path.
|
||||
VCSUrlMajorVersionSuffixRegex = regexp.MustCompile(`(/v[\d]+)$`)
|
||||
|
||||
// gopkg.in/user/pkg.v -> github.com/user/pkg
|
||||
VCSUrlGoPkgInRegexWithUser = regexp.MustCompile(`^gopkg\.in/([^/]+)/([^.]+)\..*$`)
|
||||
|
||||
// gopkg.in without user segment
|
||||
// Example: gopkg.in/pkg.v3 -> github.com/go-pkg/pkg
|
||||
VCSUrlGoPkgInRegexWithoutUser = regexp.MustCompile(`^gopkg\.in/([^.]+)\..*$`)
|
||||
)
|
||||
|
||||
type Parser struct {
|
||||
replace bool // 'replace' represents if the 'replace' directive should be taken into account.
|
||||
}
|
||||
|
||||
func NewParser(replace bool) types.Parser {
|
||||
return &Parser{
|
||||
replace: replace,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Parser) GetExternalRefs(path string) []types.ExternalRef {
|
||||
if url := resolveVCSUrl(path); url != "" {
|
||||
return []types.ExternalRef{
|
||||
{
|
||||
Type: types.RefVCS,
|
||||
URL: url,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resolveVCSUrl(modulePath string) string {
|
||||
switch {
|
||||
case strings.HasPrefix(modulePath, "github.com/"):
|
||||
return "https://" + VCSUrlMajorVersionSuffixRegex.ReplaceAllString(modulePath, "")
|
||||
case VCSUrlGoPkgInRegexWithUser.MatchString(modulePath):
|
||||
return "https://" + VCSUrlGoPkgInRegexWithUser.ReplaceAllString(modulePath, "github.com/$1/$2")
|
||||
case VCSUrlGoPkgInRegexWithoutUser.MatchString(modulePath):
|
||||
return "https://" + VCSUrlGoPkgInRegexWithoutUser.ReplaceAllString(modulePath, "github.com/go-$1/$1")
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
// Parse parses a go.mod file
|
||||
func (p *Parser) Parse(r dio.ReadSeekerAt) ([]types.Library, []types.Dependency, error) {
|
||||
libs := make(map[string]types.Library)
|
||||
|
||||
goModData, err := io.ReadAll(r)
|
||||
if err != nil {
|
||||
return nil, nil, xerrors.Errorf("file read error: %w", err)
|
||||
}
|
||||
|
||||
modFileParsed, err := modfile.Parse("go.mod", goModData, nil)
|
||||
if err != nil {
|
||||
return nil, nil, xerrors.Errorf("go.mod parse error: %w", err)
|
||||
}
|
||||
|
||||
skipIndirect := true
|
||||
if modFileParsed.Go != nil { // Old go.mod file may not include the go version. Go version for these files is less than 1.17
|
||||
skipIndirect = lessThan117(modFileParsed.Go.Version)
|
||||
}
|
||||
|
||||
for _, require := range modFileParsed.Require {
|
||||
// Skip indirect dependencies less than Go 1.17
|
||||
if skipIndirect && require.Indirect {
|
||||
continue
|
||||
}
|
||||
libs[require.Mod.Path] = types.Library{
|
||||
ID: ModuleID(require.Mod.Path, require.Mod.Version[1:]),
|
||||
Name: require.Mod.Path,
|
||||
Version: require.Mod.Version[1:],
|
||||
Indirect: require.Indirect,
|
||||
ExternalReferences: p.GetExternalRefs(require.Mod.Path),
|
||||
}
|
||||
}
|
||||
|
||||
// No need to evaluate the 'replace' directive for indirect dependencies
|
||||
if p.replace {
|
||||
for _, rep := range modFileParsed.Replace {
|
||||
// Check if replaced path is actually in our libs.
|
||||
old, ok := libs[rep.Old.Path]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
// If the replace directive has a version on the left side, make sure it matches the version that was imported.
|
||||
if rep.Old.Version != "" && old.Version != rep.Old.Version[1:] {
|
||||
continue
|
||||
}
|
||||
|
||||
// Only support replace directive with version on the right side.
|
||||
// Directive without version is a local path.
|
||||
if rep.New.Version == "" {
|
||||
// Delete old lib, since it's a local path now.
|
||||
delete(libs, rep.Old.Path)
|
||||
continue
|
||||
}
|
||||
|
||||
// Delete old lib, in case the path has changed.
|
||||
delete(libs, rep.Old.Path)
|
||||
|
||||
// Add replaced library to library register.
|
||||
libs[rep.New.Path] = types.Library{
|
||||
ID: ModuleID(rep.New.Path, rep.New.Version[1:]),
|
||||
Name: rep.New.Path,
|
||||
Version: rep.New.Version[1:],
|
||||
Indirect: old.Indirect,
|
||||
ExternalReferences: p.GetExternalRefs(rep.New.Path),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return maps.Values(libs), nil, nil
|
||||
}
|
||||
|
||||
// Check if the Go version is less than 1.17
|
||||
func lessThan117(ver string) bool {
|
||||
ss := strings.Split(ver, ".")
|
||||
if len(ss) != 2 {
|
||||
return false
|
||||
}
|
||||
major, err := strconv.Atoi(ss[0])
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
minor, err := strconv.Atoi(ss[1])
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return major <= 1 && minor < 17
|
||||
}
|
||||
|
||||
// ModuleID returns a module ID according the Go way.
|
||||
// Format: <module_name>@v<module_version>
|
||||
// e.g. github.com/aquasecurity/go-dep-parser@v0.0.0-20230130190635-5e31092b0621
|
||||
func ModuleID(name, version string) string {
|
||||
return fmt.Sprintf("%s@v%s", name, version)
|
||||
}
|
||||
Reference in New Issue
Block a user