-
Notifications
You must be signed in to change notification settings - Fork 2.5k
feat(license): scan vendor directory for license for go.mod files #8689
New issue
Have a question about this project? No Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “No Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? No Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hello @oneum20
Thanks for your work!
Left a few comments. Take a look, when you have time, please
Also we need to update docs (see https://trivy.dev/latest/docs/coverage/language/golang/#license)
@@ -143,6 +149,14 @@ func (a *gomodAnalyzer) fillAdditionalData(apps []types.Application) error { | |||
usedPkgs := lo.SliceToMap(app.Packages, func(pkg types.Package) (string, types.Package) { | |||
return pkg.Name, pkg | |||
}) | |||
|
|||
// Check if the vendor directory exists | |||
vendorPath := filepath.Join(absPath, filepath.Dir(app.FilePath), "vendor") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if $GOPATH/pkg/mod
doesn't exist - you will not check vendor dir.
trivy/pkg/fanal/analyzer/language/golang/mod/mod.go
Lines 140 to 144 in 118cd99
if !fsutils.DirExists(modPath) { | |
a.logger.Debug("GOPATH not found. Need 'go mod download' to fill licenses and dependency relationships", | |
log.String("GOPATH", modPath)) | |
return nil | |
} |
@@ -123,7 +124,12 @@ func (a *gomodAnalyzer) Version() int { | |||
} | |||
|
|||
// fillAdditionalData collects licenses and dependency relationships, then update applications. | |||
func (a *gomodAnalyzer) fillAdditionalData(apps []types.Application) error { | |||
func (a *gomodAnalyzer) fillAdditionalData(apps []types.Application, fsys fs.FS) error { | |||
absPath, err := filepath.Abs(fsys.(*mapfs.FS).GetUnderlyingRoot()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If repository contains required files - we try to add them into CompositeFS
.
e.g. node_modules
dir for npm
and yarn
.
So i suggest to add vendor
dir into CompositeFS
(use Required
function)
modDirSuffix := fmt.Sprintf("@%s", lib.Version) | ||
if modPath == vendorPath { | ||
modDirSuffix = "" | ||
} | ||
modDir := filepath.Join(modPath, fmt.Sprintf("%s%s", normalizeModName(lib.Name), modDirSuffix)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it will be easier to understand this way.
modDirSuffix := fmt.Sprintf("@%s", lib.Version) | |
if modPath == vendorPath { | |
modDirSuffix = "" | |
} | |
modDir := filepath.Join(modPath, fmt.Sprintf("%s%s", normalizeModName(lib.Name), modDirSuffix)) | |
// Package dir from `vendor` dir doesn't have version suffix. | |
modDirName := normalizeModName(lib.Name) | |
if modPath != vendorPath { | |
// Add version suffix for packages from $$GOPATH | |
// e.g. $GOPATH/pkg/mod/github.com/aquasecurity/go-dep-parser@v1.0.0 | |
modDirName = fmt.Sprintf("%s@%s", modDirName, lib.Version) | |
} | |
modDir := filepath.Join(modPath, modDirName) |
@@ -151,7 +165,11 @@ func (a *gomodAnalyzer) fillAdditionalData(apps []types.Application) error { | |||
} | |||
|
|||
// e.g. $GOPATH/pkg/mod/github.com/aquasecurity/go-dep-parser@v1.0.0 | |||
modDir := filepath.Join(modPath, fmt.Sprintf("%s@%s", normalizeModName(lib.Name), lib.Version)) | |||
modDirSuffix := fmt.Sprintf("@%s", lib.Version) | |||
if modPath == vendorPath { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can add verndorDirFound
bool variable for that.
@@ -165,7 +183,8 @@ func (a *gomodAnalyzer) fillAdditionalData(apps []types.Application) error { | |||
} | |||
|
|||
// Collect dependencies of the direct dependency | |||
if dep, err := a.collectDeps(modDir, lib.ID); err != nil { | |||
gopathModDir := filepath.Join(gopath, "pkg", "mod", fmt.Sprintf("%s@%s", normalizeModName(lib.Name), lib.Version)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to add comment why we use another path here.
Hi @DmitriyLewen! Thanks for your review! Thanks! |
07e4bfe
to
467e9ed
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, left small comments
@@ -111,7 +112,16 @@ func (a *gomodAnalyzer) PostAnalyze(_ context.Context, input analyzer.PostAnalys | |||
|
|||
func (a *gomodAnalyzer) Required(filePath string, _ os.FileInfo) bool { | |||
fileName := filepath.Base(filePath) | |||
return slices.Contains(requiredFiles, fileName) | |||
|
|||
if slices.Contains(requiredFiles, fileName) && !xpath.Contains(filePath, "vendor") { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can remove vendor
dir check here.
As we told in #8527 (comment) - vendor
dir doesn't have go.mod
/go.sum
files.
But we can add comment about this case with link to your comment,
|
||
// Check if the vendor directory exists | ||
_, err := fs.Stat(fsys, vendorDir) | ||
vendorDirFound := err == nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use errors.Is(err, os.ErrNotExist)
to check that dir exists
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and we need to check that this is dir (not file)
// Collect dependencies of the direct dependency from $GOPATH/pkg/mod because the vendor directory doesn't have go.mod files. | ||
gopathModDir := filepath.Join(gopath, "pkg", "mod", fmt.Sprintf("%s@%s", normalizeModName(lib.Name), lib.Version)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can add check here or in collectDeps
func
// Collect dependencies of the direct dependency from $GOPATH/pkg/mod because the vendor directory doesn't have go.mod files. | |
gopathModDir := filepath.Join(gopath, "pkg", "mod", fmt.Sprintf("%s@%s", normalizeModName(lib.Name), lib.Version)) | |
if !gopathModDirFound { | |
continue | |
} | |
// Collect dependencies of the direct dependency from $GOPATH/pkg/mod because the vendor directory doesn't have go.mod files. | |
gopathModDir := filepath.Join(gopath, "pkg", "mod", fmt.Sprintf("%s@%s", normalizeModName(lib.Name), lib.Version)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the review. :)
I've addressed the other points and looked into this suggestion.
It seems the check is already implemented here:
trivy/pkg/fanal/analyzer/language/golang/mod/mod.go
Lines 188 to 198 in b7cbbdc
func (a *gomodAnalyzer) collectDeps(modDir, pkgID string) (types.Dependency, error) { | |
// e.g. $GOPATH/pkg/mod/github.com/aquasecurity/go-dep-parser@v0.0.0-20220406074731-71021a481237/go.mod | |
modPath := filepath.Join(modDir, "go.mod") | |
f, err := os.Open(modPath) | |
if errors.Is(err, fs.ErrNotExist) { | |
a.logger.Debug("Unable to identify dependencies as it doesn't support Go modules", | |
log.String("module", pkgID)) | |
return types.Dependency{}, nil | |
} else if err != nil { | |
return types.Dependency{}, xerrors.Errorf("file open error: %w", err) | |
} |
Was there perhaps a different intention I might have missed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
there are 2 point:
- We try to use "early return" logic.
- We will check
go.mod
file for each dependency (but you know that GOPATH dir doesn't exist), so this is extra resources.
@oneum20 I refactored a bit, can you take a look and confirm that i didn't break your logic? 😄 |
@DmitriyLewen |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@knqyf263 can you also take a look, please?
Description
This PR adds support for scanning the
vendor
directory when detecting licenses for Go modules. Currently, Trivy only checks for licenses in$GOPATH/pkg/mod
, but when users usego mod vendor
command, the dependencies are stored in thevendor
directory without their owngo.mod
files.Related issues
Checklist