feat(golang): add license parsing from vendor dirs (#3522)

Signed-off-by: Dominik Schmidt <dev@dominik-schmidt.de>
Signed-off-by: Keith Zantow <kzantow@gmail.com>
Co-authored-by: Keith Zantow <kzantow@gmail.com>
This commit is contained in:
Dominik Schmidt
2025-01-17 20:25:05 -05:00
committed by GitHub
co-authored by Keith Zantow
parent 8198a706d6
commit 19a75fe504
9 changed files with 562 additions and 11 deletions
+46
View File
@@ -42,6 +42,7 @@ type goLicenseResolver struct {
catalogerName string
opts CatalogerConfig
localModCacheDir fs.FS
localVendorDir fs.FS
licenseCache cache.Resolver[[]goLicense]
lowerLicenseFileNames *strset.Set
}
@@ -52,10 +53,25 @@ func newGoLicenseResolver(catalogerName string, opts CatalogerConfig) goLicenseR
localModCacheDir = os.DirFS(opts.LocalModCacheDir)
}
var localVendorDir fs.FS
if opts.SearchLocalVendorLicenses {
vendorDir := opts.LocalVendorDir
if vendorDir == "" {
wd, err := os.Getwd()
if err != nil {
log.Warn("unable to get CWD while resolving the local go vendor dir: %v", err)
} else {
vendorDir = filepath.Join(wd, "vendor")
}
}
localVendorDir = os.DirFS(vendorDir)
}
return goLicenseResolver{
catalogerName: catalogerName,
opts: opts,
localModCacheDir: localModCacheDir,
localVendorDir: localVendorDir,
licenseCache: cache.GetResolverCachingErrors[[]goLicense]("golang", "v1"),
lowerLicenseFileNames: strset.New(lowercaseLicenseFiles()...),
}
@@ -103,6 +119,17 @@ func (c *goLicenseResolver) getLicenses(ctx context.Context, scanner licenses.Sc
}
}
// look in the local vendor directory...
if c.opts.SearchLocalVendorLicenses {
goLicenses, err = c.getLicensesFromLocalVendor(ctx, scanner, moduleName)
if err != nil {
log.WithFields("error", err, "module", moduleName, "version", moduleVersion).Trace("unable to read golang licenses vendor")
}
if len(goLicenses) > 0 {
return toPkgLicenses(goLicenses)
}
}
// download from remote sources
if c.opts.SearchRemoteLicenses {
goLicenses, err = c.getLicensesFromRemote(ctx, scanner, moduleName, moduleVersion)
@@ -133,6 +160,25 @@ func (c *goLicenseResolver) getLicensesFromLocal(ctx context.Context, scanner li
return c.findLicensesInFS(ctx, scanner, "file://$GOPATH/pkg/mod/"+subdir+"/", dir)
}
func (c *goLicenseResolver) getLicensesFromLocalVendor(ctx context.Context, scanner licenses.Scanner, moduleName string) ([]goLicense, error) {
if c.localVendorDir == nil {
return nil, nil
}
subdir := processCaps(moduleName)
// get the local subdirectory containing the specific go module
dir, err := fs.Sub(c.localVendorDir, subdir)
if err != nil {
return nil, err
}
// if we're running against a directory on the filesystem, it may not include the
// user's homedir / GOPATH, so we defer to using the localModCacheResolver
// we use $GOPATH/pkg/mod to avoid leaking information about the user's system
return c.findLicensesInFS(ctx, scanner, "file://$GO_VENDOR/"+subdir+"/", dir)
}
func (c *goLicenseResolver) getLicensesFromRemote(ctx context.Context, scanner licenses.Scanner, moduleName, moduleVersion string) ([]goLicense, error) {
return c.licenseCache.Resolve(fmt.Sprintf("%s/%s", moduleName, moduleVersion), func() ([]goLicense, error) {
proxies := remotesForModule(c.opts.Proxies, c.opts.NoProxy, moduleName)