mirror of
https://github.com/anchore/syft.git
synced 2026-02-12 02:26:42 +01:00
fix: golang PURL should include full module (#4395)
* fixed #4316 go mod with ver purl Signed-off-by: Rez Moss <hi@rezmoss.com> * go mod purl fixed, added func to handle go.mod Signed-off-by: Rez Moss <hi@rezmoss.com> * fix: use module name in PURL string everywhere Signed-off-by: Keith Zantow <kzantow@gmail.com> --------- Signed-off-by: Rez Moss <hi@rezmoss.com> Signed-off-by: Keith Zantow <kzantow@gmail.com> Co-authored-by: Keith Zantow <kzantow@gmail.com>
This commit is contained in:
parent
4c38ee1932
commit
e0b61a3ae3
@ -188,7 +188,8 @@ func (cfg Catalog) ToPackagesConfig() pkgcataloging.Config {
|
|||||||
WithFromContents(cfg.Golang.MainModuleVersion.FromContents).
|
WithFromContents(cfg.Golang.MainModuleVersion.FromContents).
|
||||||
WithFromBuildSettings(cfg.Golang.MainModuleVersion.FromBuildSettings).
|
WithFromBuildSettings(cfg.Golang.MainModuleVersion.FromBuildSettings).
|
||||||
WithFromLDFlags(cfg.Golang.MainModuleVersion.FromLDFlags),
|
WithFromLDFlags(cfg.Golang.MainModuleVersion.FromLDFlags),
|
||||||
),
|
).
|
||||||
|
WithUsePackagesLib(*multiLevelOption(true, enrichmentEnabled(cfg.Enrich, task.Go, task.Golang), cfg.Golang.UsePackagesLib)),
|
||||||
JavaScript: javascript.DefaultCatalogerConfig().
|
JavaScript: javascript.DefaultCatalogerConfig().
|
||||||
WithIncludeDevDependencies(*multiLevelOption(false, cfg.JavaScript.IncludeDevDependencies)).
|
WithIncludeDevDependencies(*multiLevelOption(false, cfg.JavaScript.IncludeDevDependencies)).
|
||||||
WithSearchRemoteLicenses(*multiLevelOption(false, enrichmentEnabled(cfg.Enrich, task.JavaScript, task.Node, task.NPM), cfg.JavaScript.SearchRemoteLicenses)).
|
WithSearchRemoteLicenses(*multiLevelOption(false, enrichmentEnabled(cfg.Enrich, task.JavaScript, task.Node, task.NPM), cfg.JavaScript.SearchRemoteLicenses)).
|
||||||
|
|||||||
@ -16,6 +16,7 @@ type golangConfig struct {
|
|||||||
Proxy string `json:"proxy" yaml:"proxy" mapstructure:"proxy"`
|
Proxy string `json:"proxy" yaml:"proxy" mapstructure:"proxy"`
|
||||||
NoProxy string `json:"no-proxy" yaml:"no-proxy" mapstructure:"no-proxy"`
|
NoProxy string `json:"no-proxy" yaml:"no-proxy" mapstructure:"no-proxy"`
|
||||||
MainModuleVersion golangMainModuleVersionConfig `json:"main-module-version" yaml:"main-module-version" mapstructure:"main-module-version"`
|
MainModuleVersion golangMainModuleVersionConfig `json:"main-module-version" yaml:"main-module-version" mapstructure:"main-module-version"`
|
||||||
|
UsePackagesLib *bool `json:"use-packages-lib" yaml:"use-packages-lib" mapstructure:"use-packages-lib"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ interface {
|
var _ interface {
|
||||||
@ -37,6 +38,7 @@ if unset this defaults to $GONOPROXY`)
|
|||||||
descriptions.Add(&o.MainModuleVersion, `the go main module version discovered from binaries built with the go compiler will
|
descriptions.Add(&o.MainModuleVersion, `the go main module version discovered from binaries built with the go compiler will
|
||||||
always show (devel) as the version. Use these options to control heuristics to guess
|
always show (devel) as the version. Use these options to control heuristics to guess
|
||||||
a more accurate version from the binary.`)
|
a more accurate version from the binary.`)
|
||||||
|
descriptions.Add(&o.UsePackagesLib, `use the golang.org/x/tools/go/packages library, which executes golang tooling found on the path in addition to potential network access to get the most accurate results`)
|
||||||
descriptions.Add(&o.MainModuleVersion.FromLDFlags, `look for LD flags that appear to be setting a version (e.g. -X main.version=1.0.0)`)
|
descriptions.Add(&o.MainModuleVersion.FromLDFlags, `look for LD flags that appear to be setting a version (e.g. -X main.version=1.0.0)`)
|
||||||
descriptions.Add(&o.MainModuleVersion.FromBuildSettings, `use the build settings (e.g. vcs.version & vcs.time) to craft a v0 pseudo version
|
descriptions.Add(&o.MainModuleVersion.FromBuildSettings, `use the build settings (e.g. vcs.version & vcs.time) to craft a v0 pseudo version
|
||||||
(e.g. v0.0.0-20220308212642-53e6d0aaf6fb) when a more accurate version cannot be found otherwise`)
|
(e.g. v0.0.0-20220308212642-53e6d0aaf6fb) when a more accurate version cannot be found otherwise`)
|
||||||
@ -64,5 +66,6 @@ func defaultGolangConfig() golangConfig {
|
|||||||
FromContents: def.MainModuleVersion.FromContents,
|
FromContents: def.MainModuleVersion.FromContents,
|
||||||
FromBuildSettings: def.MainModuleVersion.FromBuildSettings,
|
FromBuildSettings: def.MainModuleVersion.FromBuildSettings,
|
||||||
},
|
},
|
||||||
|
UsePackagesLib: nil, // this defaults to true, which is the API default
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -48,6 +48,9 @@ type CatalogerConfig struct {
|
|||||||
NoProxy []string `yaml:"no-proxy,omitempty" json:"no-proxy,omitempty" mapstructure:"no-proxy"`
|
NoProxy []string `yaml:"no-proxy,omitempty" json:"no-proxy,omitempty" mapstructure:"no-proxy"`
|
||||||
|
|
||||||
MainModuleVersion MainModuleVersionConfig `yaml:"main-module-version" json:"main-module-version" mapstructure:"main-module-version"`
|
MainModuleVersion MainModuleVersionConfig `yaml:"main-module-version" json:"main-module-version" mapstructure:"main-module-version"`
|
||||||
|
|
||||||
|
// Whether to use the golang.org/x/tools/go/packages, which executes golang tooling found on the path in addition to potential network access
|
||||||
|
UsePackagesLib bool `json:"use-packages-lib" yaml:"use-packages-lib" mapstructure:"use-packages-lib"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type MainModuleVersionConfig struct {
|
type MainModuleVersionConfig struct {
|
||||||
@ -70,6 +73,7 @@ type MainModuleVersionConfig struct {
|
|||||||
// - setting the default local module cache dir if none is provided
|
// - setting the default local module cache dir if none is provided
|
||||||
func DefaultCatalogerConfig() CatalogerConfig {
|
func DefaultCatalogerConfig() CatalogerConfig {
|
||||||
g := CatalogerConfig{
|
g := CatalogerConfig{
|
||||||
|
UsePackagesLib: true,
|
||||||
MainModuleVersion: DefaultMainModuleVersionConfig(),
|
MainModuleVersion: DefaultMainModuleVersionConfig(),
|
||||||
LocalModCacheDir: defaultGoModDir(),
|
LocalModCacheDir: defaultGoModDir(),
|
||||||
}
|
}
|
||||||
@ -180,6 +184,11 @@ func (g CatalogerConfig) WithMainModuleVersion(input MainModuleVersionConfig) Ca
|
|||||||
return g
|
return g
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (g CatalogerConfig) WithUsePackagesLib(useLib bool) CatalogerConfig {
|
||||||
|
g.UsePackagesLib = useLib
|
||||||
|
return g
|
||||||
|
}
|
||||||
|
|
||||||
func (g MainModuleVersionConfig) WithFromLDFlags(input bool) MainModuleVersionConfig {
|
func (g MainModuleVersionConfig) WithFromLDFlags(input bool) MainModuleVersionConfig {
|
||||||
g.FromLDFlags = input
|
g.FromLDFlags = input
|
||||||
return g
|
return g
|
||||||
|
|||||||
@ -57,6 +57,7 @@ func Test_Config(t *testing.T) {
|
|||||||
Proxies: []string{"https://my.proxy"},
|
Proxies: []string{"https://my.proxy"},
|
||||||
NoProxy: []string{"my.private", "no.proxy"},
|
NoProxy: []string{"my.private", "no.proxy"},
|
||||||
MainModuleVersion: DefaultMainModuleVersionConfig(),
|
MainModuleVersion: DefaultMainModuleVersionConfig(),
|
||||||
|
UsePackagesLib: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -84,6 +85,7 @@ func Test_Config(t *testing.T) {
|
|||||||
Proxies: []string{"https://alt.proxy", "direct"},
|
Proxies: []string{"https://alt.proxy", "direct"},
|
||||||
NoProxy: []string{"alt.no.proxy"},
|
NoProxy: []string{"alt.no.proxy"},
|
||||||
MainModuleVersion: DefaultMainModuleVersionConfig(),
|
MainModuleVersion: DefaultMainModuleVersionConfig(),
|
||||||
|
UsePackagesLib: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@ -64,27 +64,23 @@ func newBinaryMetadata(dep *debug.Module, mainModule, goVersion, architecture st
|
|||||||
func packageURL(moduleName, moduleVersion string) string {
|
func packageURL(moduleName, moduleVersion string) string {
|
||||||
// source: https://github.com/package-url/purl-spec/blob/master/PURL-TYPES.rst#golang
|
// source: https://github.com/package-url/purl-spec/blob/master/PURL-TYPES.rst#golang
|
||||||
// note: "The version is often empty when a commit is not specified and should be the commit in most cases when available."
|
// note: "The version is often empty when a commit is not specified and should be the commit in most cases when available."
|
||||||
|
if moduleName == "" {
|
||||||
fields := strings.Split(moduleName, "/")
|
|
||||||
if len(fields) == 0 {
|
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace := ""
|
namespace := ""
|
||||||
name := ""
|
name := moduleName
|
||||||
// The subpath is used to point to a subpath inside a package (e.g. pkg:golang/google.golang.org/genproto#googleapis/api/annotations)
|
|
||||||
subpath := ""
|
|
||||||
|
|
||||||
switch len(fields) {
|
// golang PURLs from _modules_ are constructed as pkg:golang/<module>@version, where
|
||||||
case 1:
|
// the full module name often includes multiple segments including `/v#`-type versions, for example:
|
||||||
name = fields[0]
|
// pkg:golang/github.com/cli/cli/v2@2.63.0
|
||||||
case 2:
|
// see: https://github.com/package-url/purl-spec/issues/63
|
||||||
name = fields[1]
|
// and: https://github.com/package-url/purl-spec/blob/main/types-doc/golang-definition.md#subpath-definition
|
||||||
namespace = fields[0]
|
// by setting the namespace this way, it does not escape the slashes:
|
||||||
default:
|
lastSlash := strings.LastIndex(moduleName, "/")
|
||||||
name = fields[2]
|
if lastSlash > 0 && lastSlash < len(moduleName)-1 {
|
||||||
namespace = strings.Join(fields[0:2], "/")
|
name = moduleName[lastSlash+1:]
|
||||||
subpath = strings.Join(fields[3:], "/")
|
namespace = moduleName[0:lastSlash]
|
||||||
}
|
}
|
||||||
|
|
||||||
return packageurl.NewPackageURL(
|
return packageurl.NewPackageURL(
|
||||||
@ -93,6 +89,6 @@ func packageURL(moduleName, moduleVersion string) string {
|
|||||||
name,
|
name,
|
||||||
moduleVersion,
|
moduleVersion,
|
||||||
nil,
|
nil,
|
||||||
subpath,
|
"", // subpath is used to reference a specific _package_ within the module
|
||||||
).ToString()
|
).ToString()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -38,14 +38,14 @@ func Test_packageURL(t *testing.T) {
|
|||||||
Name: "github.com/coreos/go-systemd/v22",
|
Name: "github.com/coreos/go-systemd/v22",
|
||||||
Version: "v22.1.0",
|
Version: "v22.1.0",
|
||||||
},
|
},
|
||||||
expected: "pkg:golang/github.com/coreos/go-systemd@v22.1.0#v22",
|
expected: "pkg:golang/github.com/coreos/go-systemd/v22@v22.1.0",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "golang with subpath deep",
|
name: "golang with subpath deep",
|
||||||
pkg: pkg.Package{
|
pkg: pkg.Package{
|
||||||
Name: "google.golang.org/genproto/googleapis/api/annotations",
|
Name: "google.golang.org/genproto/googleapis/api/annotations",
|
||||||
},
|
},
|
||||||
expected: "pkg:golang/google.golang.org/genproto/googleapis#api/annotations",
|
expected: "pkg:golang/google.golang.org/genproto/googleapis/api/annotations",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -278,7 +278,7 @@ func TestBuildGoPkgInfo(t *testing.T) {
|
|||||||
{
|
{
|
||||||
Name: "github.com/a/b/c",
|
Name: "github.com/a/b/c",
|
||||||
Version: "", // this was (devel) but we cleared it explicitly
|
Version: "", // this was (devel) but we cleared it explicitly
|
||||||
PURL: "pkg:golang/github.com/a/b#c",
|
PURL: "pkg:golang/github.com/a/b/c",
|
||||||
Language: pkg.Go,
|
Language: pkg.Go,
|
||||||
Type: pkg.GoModulePkg,
|
Type: pkg.GoModulePkg,
|
||||||
Locations: file.NewLocationSet(
|
Locations: file.NewLocationSet(
|
||||||
|
|||||||
@ -8,7 +8,6 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"slices"
|
"slices"
|
||||||
"sort"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
@ -26,17 +25,19 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type goModCataloger struct {
|
type goModCataloger struct {
|
||||||
|
usePackagesLib bool
|
||||||
licenseResolver goLicenseResolver
|
licenseResolver goLicenseResolver
|
||||||
}
|
}
|
||||||
|
|
||||||
func newGoModCataloger(opts CatalogerConfig) *goModCataloger {
|
func newGoModCataloger(opts CatalogerConfig) *goModCataloger {
|
||||||
return &goModCataloger{
|
return &goModCataloger{
|
||||||
|
usePackagesLib: opts.UsePackagesLib,
|
||||||
licenseResolver: newGoLicenseResolver(modFileCatalogerName, opts),
|
licenseResolver: newGoLicenseResolver(modFileCatalogerName, opts),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseGoModFile takes a go.mod and tries to resolve and lists all packages discovered.
|
// parseGoModFile takes a go.mod and tries to resolve and lists all packages discovered.
|
||||||
func (c *goModCataloger) parseGoModFile(ctx context.Context, resolver file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
|
func (c *goModCataloger) parseGoModFile(ctx context.Context, resolver file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) (pkgs []pkg.Package, relationships []artifact.Relationship, err error) {
|
||||||
modDir := filepath.Dir(string(reader.Location.Reference().RealPath))
|
modDir := filepath.Dir(string(reader.Location.Reference().RealPath))
|
||||||
digests, err := parseGoSumFile(resolver, reader)
|
digests, err := parseGoSumFile(resolver, reader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -48,24 +49,34 @@ func (c *goModCataloger) parseGoModFile(ctx context.Context, resolver file.Resol
|
|||||||
scanRoot = dir.Chroot.Base()
|
scanRoot = dir.Chroot.Base()
|
||||||
}
|
}
|
||||||
|
|
||||||
// source analysis using go toolchain if available
|
|
||||||
syftSourcePackages, sourceModules, sourceDependencies, unknownErr := c.loadPackages(modDir, reader.Location)
|
|
||||||
catalogedModules, sourceModuleToPkg := c.catalogModules(ctx, scanRoot, syftSourcePackages, sourceModules, reader, digests)
|
|
||||||
relationships := buildModuleRelationships(catalogedModules, sourceDependencies, sourceModuleToPkg)
|
|
||||||
|
|
||||||
// base case go.mod file parsing
|
// base case go.mod file parsing
|
||||||
modFile, err := c.parseModFileContents(reader)
|
modFile, err := c.parseModFileContents(reader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// only use mod packages NOT found in source analysis
|
// source analysis using go toolchain if available
|
||||||
|
var sourceModules map[string]*packages.Module
|
||||||
|
var catalogedModules []pkg.Package
|
||||||
|
|
||||||
|
if c.usePackagesLib {
|
||||||
|
var sourcePackages map[string][]pkgInfo
|
||||||
|
var sourceDependencies map[string][]string
|
||||||
|
var sourceModuleToPkg map[string]artifact.Identifiable
|
||||||
|
|
||||||
|
sourcePackages, sourceModules, sourceDependencies, err = c.loadPackages(modDir, reader.Location)
|
||||||
|
catalogedModules, sourceModuleToPkg = c.catalogModules(ctx, scanRoot, sourcePackages, sourceModules, reader, digests)
|
||||||
|
relationships = buildModuleRelationships(catalogedModules, sourceDependencies, sourceModuleToPkg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// only use go.mod packages NOT found in source analysis
|
||||||
goModPackages := c.createGoModPackages(ctx, resolver, modFile, sourceModules, reader, digests)
|
goModPackages := c.createGoModPackages(ctx, resolver, modFile, sourceModules, reader, digests)
|
||||||
c.applyReplaceDirectives(ctx, resolver, modFile, goModPackages, reader, digests)
|
c.applyReplaceDirectives(ctx, resolver, modFile, goModPackages, reader, digests)
|
||||||
c.applyExcludeDirectives(modFile, goModPackages)
|
c.applyExcludeDirectives(modFile, goModPackages)
|
||||||
|
|
||||||
finalPkgs := c.assembleResults(catalogedModules, goModPackages)
|
pkgs = c.assembleResults(catalogedModules, goModPackages)
|
||||||
return finalPkgs, relationships, unknownErr
|
|
||||||
|
return pkgs, relationships, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// loadPackages uses golang.org/x/tools/go/packages to get dependency information.
|
// loadPackages uses golang.org/x/tools/go/packages to get dependency information.
|
||||||
@ -327,7 +338,7 @@ func (c *goModCataloger) createGoModPackages(ctx context.Context, resolver file.
|
|||||||
goModPackages := make(map[string]pkg.Package)
|
goModPackages := make(map[string]pkg.Package)
|
||||||
|
|
||||||
for _, m := range modFile.Require {
|
for _, m := range modFile.Require {
|
||||||
if _, exists := sourceModules[m.Mod.Path]; !exists {
|
if sourceModules == nil || sourceModules[m.Mod.Path] == nil {
|
||||||
lics := c.licenseResolver.getLicenses(ctx, resolver, m.Mod.Path, m.Mod.Version)
|
lics := c.licenseResolver.getLicenses(ctx, resolver, m.Mod.Path, m.Mod.Version)
|
||||||
goModPkg := pkg.Package{
|
goModPkg := pkg.Package{
|
||||||
Name: m.Mod.Path,
|
Name: m.Mod.Path,
|
||||||
@ -392,9 +403,7 @@ func (c *goModCataloger) assembleResults(catalogedPkgs []pkg.Package, goModPacka
|
|||||||
pkgsSlice = append(pkgsSlice, p)
|
pkgsSlice = append(pkgsSlice, p)
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.SliceStable(pkgsSlice, func(i, j int) bool {
|
pkg.Sort(pkgsSlice)
|
||||||
return pkgsSlice[i].Name < pkgsSlice[j].Name
|
|
||||||
})
|
|
||||||
|
|
||||||
return pkgsSlice
|
return pkgsSlice
|
||||||
}
|
}
|
||||||
|
|||||||
@ -54,7 +54,7 @@ func TestParseGoMod(t *testing.T) {
|
|||||||
{
|
{
|
||||||
Name: "github.com/anchore/archiver/v3",
|
Name: "github.com/anchore/archiver/v3",
|
||||||
Version: "v3.5.2",
|
Version: "v3.5.2",
|
||||||
PURL: "pkg:golang/github.com/anchore/archiver@v3.5.2#v3",
|
PURL: "pkg:golang/github.com/anchore/archiver/v3@v3.5.2",
|
||||||
Locations: file.NewLocationSet(file.NewLocation("test-fixtures/go-mod-fixtures/many-packages/go.mod")),
|
Locations: file.NewLocationSet(file.NewLocation("test-fixtures/go-mod-fixtures/many-packages/go.mod")),
|
||||||
Language: pkg.Go,
|
Language: pkg.Go,
|
||||||
Type: pkg.GoModulePkg,
|
Type: pkg.GoModulePkg,
|
||||||
@ -111,7 +111,7 @@ func TestParseGoMod(t *testing.T) {
|
|||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
t.Run(test.fixture, func(t *testing.T) {
|
t.Run(test.fixture, func(t *testing.T) {
|
||||||
c := newGoModCataloger(DefaultCatalogerConfig())
|
c := newGoModCataloger(DefaultCatalogerConfig().WithUsePackagesLib(false))
|
||||||
pkgtest.NewCatalogTester().
|
pkgtest.NewCatalogTester().
|
||||||
FromFile(t, test.fixture).
|
FromFile(t, test.fixture).
|
||||||
Expects(test.expected, nil).
|
Expects(test.expected, nil).
|
||||||
@ -172,7 +172,9 @@ func Test_GoSumHashes(t *testing.T) {
|
|||||||
pkgtest.NewCatalogTester().
|
pkgtest.NewCatalogTester().
|
||||||
FromDirectory(t, test.fixture).
|
FromDirectory(t, test.fixture).
|
||||||
Expects(test.expected, nil).
|
Expects(test.expected, nil).
|
||||||
TestCataloger(t, NewGoModuleFileCataloger(CatalogerConfig{}))
|
TestCataloger(t, NewGoModuleFileCataloger(CatalogerConfig{
|
||||||
|
UsePackagesLib: false,
|
||||||
|
}))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -189,7 +191,6 @@ func Test_parseGoSource_packageResolution(t *testing.T) {
|
|||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
fixturePath string
|
fixturePath string
|
||||||
config CatalogerConfig
|
|
||||||
expectedPkgs []string
|
expectedPkgs []string
|
||||||
expectedRels []string
|
expectedRels []string
|
||||||
expectedLicenses map[string][]string
|
expectedLicenses map[string][]string
|
||||||
@ -333,7 +334,7 @@ func Test_parseGoSource_packageResolution(t *testing.T) {
|
|||||||
t.Errorf("mismatch in licenses (-want +got):\n%s", diff)
|
t.Errorf("mismatch in licenses (-want +got):\n%s", diff)
|
||||||
}
|
}
|
||||||
}).
|
}).
|
||||||
TestCataloger(t, NewGoModuleFileCataloger(CatalogerConfig{}))
|
TestCataloger(t, NewGoModuleFileCataloger(DefaultCatalogerConfig().WithUsePackagesLib(true)))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user