mirror of
https://github.com/anchore/syft.git
synced 2026-10-31 22:46:36 +01:00
Normalize cataloger configuration patterns (#2365)
* normalize cataloger patterns Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * remove central reference for maven configurable Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> --------- Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
This commit is contained in:
@@ -53,14 +53,14 @@ type archiveParser struct {
|
||||
contentPath string
|
||||
fileInfo archiveFilename
|
||||
detectNested bool
|
||||
cfg Config
|
||||
cfg ArchiveCatalogerConfig
|
||||
}
|
||||
|
||||
type genericArchiveParserAdapter struct {
|
||||
cfg Config
|
||||
cfg ArchiveCatalogerConfig
|
||||
}
|
||||
|
||||
func newGenericArchiveParserAdapter(cfg Config) genericArchiveParserAdapter {
|
||||
func newGenericArchiveParserAdapter(cfg ArchiveCatalogerConfig) genericArchiveParserAdapter {
|
||||
return genericArchiveParserAdapter{cfg: cfg}
|
||||
}
|
||||
|
||||
@@ -85,7 +85,7 @@ func uniquePkgKey(groupID string, p *pkg.Package) string {
|
||||
|
||||
// newJavaArchiveParser returns a new java archive parser object for the given archive. Can be configured to discover
|
||||
// and parse nested archives or ignore them.
|
||||
func newJavaArchiveParser(reader file.LocationReadCloser, detectNested bool, cfg Config) (*archiveParser, func(), error) {
|
||||
func newJavaArchiveParser(reader file.LocationReadCloser, detectNested bool, cfg ArchiveCatalogerConfig) (*archiveParser, func(), error) {
|
||||
// fetch the last element of the virtual path
|
||||
virtualElements := strings.Split(reader.Path(), ":")
|
||||
currentFilepath := virtualElements[len(virtualElements)-1]
|
||||
@@ -338,7 +338,7 @@ func artifactIDMatchesFilename(artifactID, fileName string) bool {
|
||||
return strings.HasPrefix(artifactID, fileName) || strings.HasSuffix(fileName, artifactID)
|
||||
}
|
||||
|
||||
func findPomLicenses(pomProjectObject *parsedPomProject, cfg Config) {
|
||||
func findPomLicenses(pomProjectObject *parsedPomProject, cfg ArchiveCatalogerConfig) {
|
||||
// If we don't have any licenses until now, and if we have a parent Pom, then we'll check the parent pom in maven central for licenses.
|
||||
if pomProjectObject != nil && pomProjectObject.Parent != nil && len(pomProjectObject.Licenses) == 0 {
|
||||
parentLicenses, err := recursivelyFindLicensesFromParentPom(
|
||||
@@ -373,11 +373,11 @@ func formatMavenPomURL(groupID, artifactID, version, mavenBaseURL string) (reque
|
||||
return requestURL, err
|
||||
}
|
||||
|
||||
func recursivelyFindLicensesFromParentPom(groupID, artifactID, version string, cfg Config) ([]string, error) {
|
||||
func recursivelyFindLicensesFromParentPom(groupID, artifactID, version string, cfg ArchiveCatalogerConfig) ([]string, error) {
|
||||
var licenses []string
|
||||
// As there can be nested parent poms, we'll recursively check for licenses until we reach the max depth
|
||||
for i := 0; i < cfg.MaxParentRecursiveDepth; i++ {
|
||||
parentPom, err := getPomFromMavenCentral(groupID, artifactID, version, cfg.MavenBaseURL)
|
||||
parentPom, err := getPomFromMavenRepo(groupID, artifactID, version, cfg.MavenBaseURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -395,7 +395,7 @@ func recursivelyFindLicensesFromParentPom(groupID, artifactID, version string, c
|
||||
return licenses, nil
|
||||
}
|
||||
|
||||
func getPomFromMavenCentral(groupID, artifactID, version, mavenBaseURL string) (*gopom.Project, error) {
|
||||
func getPomFromMavenRepo(groupID, artifactID, version, mavenBaseURL string) (*gopom.Project, error) {
|
||||
requestURL, err := formatMavenPomURL(groupID, artifactID, version, mavenBaseURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -542,7 +542,7 @@ func (j *archiveParser) discoverPkgsFromNestedArchives(parentPkg *pkg.Package) (
|
||||
|
||||
// discoverPkgsFromZip finds Java archives within Java archives, returning all listed Java packages found and
|
||||
// associating each discovered package to the given parent package.
|
||||
func discoverPkgsFromZip(location file.Location, archivePath, contentPath string, fileManifest intFile.ZipFileManifest, parentPkg *pkg.Package, cfg Config) ([]pkg.Package, []artifact.Relationship, error) {
|
||||
func discoverPkgsFromZip(location file.Location, archivePath, contentPath string, fileManifest intFile.ZipFileManifest, parentPkg *pkg.Package, cfg ArchiveCatalogerConfig) ([]pkg.Package, []artifact.Relationship, error) {
|
||||
// search and parse pom.properties files & fetch the contents
|
||||
openers, err := intFile.ExtractFromZipToUniqueTempFile(archivePath, contentPath, fileManifest.GlobMatch(false, archiveFormatGlobs...)...)
|
||||
if err != nil {
|
||||
@@ -553,7 +553,7 @@ func discoverPkgsFromZip(location file.Location, archivePath, contentPath string
|
||||
}
|
||||
|
||||
// discoverPkgsFromOpeners finds Java archives within the given files and associates them with the given parent package.
|
||||
func discoverPkgsFromOpeners(location file.Location, openers map[string]intFile.Opener, parentPkg *pkg.Package, cfg Config) ([]pkg.Package, []artifact.Relationship, error) {
|
||||
func discoverPkgsFromOpeners(location file.Location, openers map[string]intFile.Opener, parentPkg *pkg.Package, cfg ArchiveCatalogerConfig) ([]pkg.Package, []artifact.Relationship, error) {
|
||||
var pkgs []pkg.Package
|
||||
var relationships []artifact.Relationship
|
||||
|
||||
@@ -582,7 +582,7 @@ func discoverPkgsFromOpeners(location file.Location, openers map[string]intFile.
|
||||
}
|
||||
|
||||
// discoverPkgsFromOpener finds Java archives within the given file.
|
||||
func discoverPkgsFromOpener(location file.Location, pathWithinArchive string, archiveOpener intFile.Opener, cfg Config) ([]pkg.Package, []artifact.Relationship, error) {
|
||||
func discoverPkgsFromOpener(location file.Location, pathWithinArchive string, archiveOpener intFile.Opener, cfg ArchiveCatalogerConfig) ([]pkg.Package, []artifact.Relationship, error) {
|
||||
archiveReadCloser, err := archiveOpener.Open()
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("unable to open archived file from tempdir: %w", err)
|
||||
@@ -669,7 +669,7 @@ func pomProjectByParentPath(archivePath string, location file.Location, extractP
|
||||
|
||||
// newPackageFromMavenData processes a single Maven POM properties for a given parent package, returning all listed Java packages found and
|
||||
// associating each discovered package to the given parent package. Note the pom.xml is optional, the pom.properties is not.
|
||||
func newPackageFromMavenData(pomProperties pkg.JavaPomProperties, parsedPomProject *parsedPomProject, parentPkg *pkg.Package, location file.Location, cfg Config) *pkg.Package {
|
||||
func newPackageFromMavenData(pomProperties pkg.JavaPomProperties, parsedPomProject *parsedPomProject, parentPkg *pkg.Package, location file.Location, cfg ArchiveCatalogerConfig) *pkg.Package {
|
||||
// keep the artifact name within the virtual path if this package does not match the parent package
|
||||
vPathSuffix := ""
|
||||
groupID := ""
|
||||
|
||||
@@ -78,7 +78,7 @@ func TestSearchMavenForLicenses(t *testing.T) {
|
||||
name string
|
||||
fixture string
|
||||
detectNested bool
|
||||
config Config
|
||||
config ArchiveCatalogerConfig
|
||||
requestPath string
|
||||
requestHandlers []handlerPath
|
||||
expectedLicenses []pkg.License
|
||||
@@ -87,7 +87,7 @@ func TestSearchMavenForLicenses(t *testing.T) {
|
||||
name: "searchMavenForLicenses returns the expected licenses when search is set to true",
|
||||
fixture: "opensaml-core-3.4.6",
|
||||
detectNested: false,
|
||||
config: Config{
|
||||
config: ArchiveCatalogerConfig{
|
||||
UseNetwork: true,
|
||||
MavenBaseURL: url,
|
||||
MaxParentRecursiveDepth: 2,
|
||||
@@ -161,7 +161,7 @@ func TestFormatMavenURL(t *testing.T) {
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
requestURL, err := formatMavenPomURL(tc.groupID, tc.artifactID, tc.version, MavenBaseURL)
|
||||
requestURL, err := formatMavenPomURL(tc.groupID, tc.artifactID, tc.version, mavenBaseURL)
|
||||
assert.NoError(t, err, "expected no err; got %w", err)
|
||||
assert.Equal(t, tc.expected, requestURL)
|
||||
})
|
||||
@@ -401,7 +401,7 @@ func TestParseJar(t *testing.T) {
|
||||
parser, cleanupFn, err := newJavaArchiveParser(file.LocationReadCloser{
|
||||
Location: file.NewLocation(fixture.Name()),
|
||||
ReadCloser: fixture,
|
||||
}, false, Config{UseNetwork: false})
|
||||
}, false, ArchiveCatalogerConfig{UseNetwork: false})
|
||||
defer cleanupFn()
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -667,7 +667,7 @@ func TestParseNestedJar(t *testing.T) {
|
||||
|
||||
fixture, err := os.Open(test.fixture)
|
||||
require.NoError(t, err)
|
||||
gap := newGenericArchiveParserAdapter(Config{})
|
||||
gap := newGenericArchiveParserAdapter(ArchiveCatalogerConfig{})
|
||||
|
||||
actual, _, err := gap.parseJavaArchive(nil, nil, file.LocationReadCloser{
|
||||
Location: file.NewLocation(fixture.Name()),
|
||||
@@ -1089,7 +1089,7 @@ func Test_newPackageFromMavenData(t *testing.T) {
|
||||
}
|
||||
test.expectedParent.Locations = locations
|
||||
|
||||
actualPackage := newPackageFromMavenData(test.props, test.project, test.parent, file.NewLocation(virtualPath), Config{})
|
||||
actualPackage := newPackageFromMavenData(test.props, test.project, test.parent, file.NewLocation(virtualPath), DefaultArchiveCatalogerConfig())
|
||||
if test.expectedPackage == nil {
|
||||
require.Nil(t, actualPackage)
|
||||
} else {
|
||||
@@ -1309,7 +1309,7 @@ func Test_parseJavaArchive_regressions(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
gap := newGenericArchiveParserAdapter(Config{})
|
||||
gap := newGenericArchiveParserAdapter(ArchiveCatalogerConfig{})
|
||||
if tt.assignParent {
|
||||
assignParent(&tt.expectedPkgs[0], tt.expectedPkgs[1:]...)
|
||||
}
|
||||
|
||||
@@ -4,23 +4,24 @@ Package java provides a concrete Cataloger implementation for packages relating
|
||||
package java
|
||||
|
||||
import (
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/generic"
|
||||
)
|
||||
|
||||
// NewArchiveCataloger returns a new Java archive cataloger object for detecting packages with archives (jar, war, ear, par, sar, jpi, hpi, and native-image formats)
|
||||
func NewArchiveCataloger(cfg Config) *generic.Cataloger {
|
||||
func NewArchiveCataloger(cfg ArchiveCatalogerConfig) *generic.Cataloger {
|
||||
gap := newGenericArchiveParserAdapter(cfg)
|
||||
|
||||
c := generic.NewCataloger("java-archive-cataloger").
|
||||
WithParserByGlobs(gap.parseJavaArchive, archiveFormatGlobs...)
|
||||
|
||||
if cfg.SearchIndexedArchives {
|
||||
if cfg.IncludeIndexedArchives {
|
||||
// java archives wrapped within zip files
|
||||
gzp := newGenericZipWrappedJavaArchiveParser(cfg)
|
||||
c.WithParserByGlobs(gzp.parseZipWrappedJavaArchive, genericZipGlobs...)
|
||||
}
|
||||
|
||||
if cfg.SearchUnindexedArchives {
|
||||
if cfg.IncludeUnindexedArchives {
|
||||
// java archives wrapped within tar files
|
||||
gtp := newGenericTarWrappedJavaArchiveParser(cfg)
|
||||
c.WithParserByGlobs(gtp.parseTarWrappedJavaArchive, genericTarGlobs...)
|
||||
@@ -30,14 +31,14 @@ func NewArchiveCataloger(cfg Config) *generic.Cataloger {
|
||||
|
||||
// NewPomCataloger returns a cataloger capable of parsing dependencies from a pom.xml file.
|
||||
// Pom files list dependencies that maybe not be locally installed yet.
|
||||
func NewPomCataloger() *generic.Cataloger {
|
||||
func NewPomCataloger() pkg.Cataloger {
|
||||
return generic.NewCataloger("java-pom-cataloger").
|
||||
WithParserByGlobs(parserPomXML, "**/pom.xml")
|
||||
}
|
||||
|
||||
// NewGradleLockfileCataloger returns a cataloger capable of parsing dependencies from a gradle.lockfile file.
|
||||
// Note: Older versions of lockfiles aren't supported yet
|
||||
func NewGradleLockfileCataloger() *generic.Cataloger {
|
||||
func NewGradleLockfileCataloger() pkg.Cataloger {
|
||||
return generic.NewCataloger("java-gradle-lockfile-cataloger").
|
||||
WithParserByGlobs(parseGradleLockfile, gradleLockfileGlob)
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package java
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/anchore/syft/syft/cataloging"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/internal/pkgtest"
|
||||
)
|
||||
|
||||
@@ -54,10 +55,16 @@ func Test_ArchiveCataloger_Globs(t *testing.T) {
|
||||
pkgtest.NewCatalogTester().
|
||||
FromDirectory(t, test.fixture).
|
||||
ExpectsResolverContentQueries(test.expected).
|
||||
TestCataloger(t, NewArchiveCataloger(Config{
|
||||
SearchUnindexedArchives: true,
|
||||
SearchIndexedArchives: true,
|
||||
}))
|
||||
TestCataloger(t,
|
||||
NewArchiveCataloger(
|
||||
ArchiveCatalogerConfig{
|
||||
ArchiveSearchConfig: cataloging.ArchiveSearchConfig{
|
||||
IncludeIndexedArchives: true,
|
||||
IncludeUnindexedArchives: true,
|
||||
},
|
||||
},
|
||||
),
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,44 @@
|
||||
package java
|
||||
|
||||
type Config struct {
|
||||
SearchUnindexedArchives bool
|
||||
SearchIndexedArchives bool
|
||||
UseNetwork bool
|
||||
MavenBaseURL string
|
||||
MaxParentRecursiveDepth int
|
||||
import "github.com/anchore/syft/syft/cataloging"
|
||||
|
||||
const mavenBaseURL = "https://repo1.maven.org/maven2"
|
||||
|
||||
type ArchiveCatalogerConfig struct {
|
||||
cataloging.ArchiveSearchConfig `yaml:",inline" json:"" mapstructure:",squash"`
|
||||
UseNetwork bool `yaml:"use-network" json:"use-network" mapstructure:"use-network"`
|
||||
MavenBaseURL string `yaml:"maven-base-url" json:"maven-base-url" mapstructure:"maven-base-url"`
|
||||
MaxParentRecursiveDepth int `yaml:"max-parent-recursive-depth" json:"max-parent-recursive-depth" mapstructure:"max-parent-recursive-depth"`
|
||||
}
|
||||
|
||||
func DefaultArchiveCatalogerConfig() ArchiveCatalogerConfig {
|
||||
return ArchiveCatalogerConfig{
|
||||
ArchiveSearchConfig: cataloging.ArchiveSearchConfig{
|
||||
IncludeIndexedArchives: true,
|
||||
IncludeUnindexedArchives: false,
|
||||
},
|
||||
UseNetwork: false,
|
||||
MavenBaseURL: mavenBaseURL,
|
||||
MaxParentRecursiveDepth: 5,
|
||||
}
|
||||
}
|
||||
|
||||
func (j ArchiveCatalogerConfig) WithUseNetwork(input bool) ArchiveCatalogerConfig {
|
||||
j.UseNetwork = input
|
||||
return j
|
||||
}
|
||||
|
||||
func (j ArchiveCatalogerConfig) WithMavenBaseURL(input string) ArchiveCatalogerConfig {
|
||||
if input != "" {
|
||||
j.MavenBaseURL = input
|
||||
}
|
||||
return j
|
||||
}
|
||||
|
||||
func (j ArchiveCatalogerConfig) WithArchiveTraversal(search cataloging.ArchiveSearchConfig, maxDepth int) ArchiveCatalogerConfig {
|
||||
if maxDepth > 0 {
|
||||
j.MaxParentRecursiveDepth = maxDepth
|
||||
}
|
||||
j.ArchiveSearchConfig = search
|
||||
return j
|
||||
}
|
||||
|
||||
@@ -102,7 +102,7 @@ const nativeImageInvalidIndexError = "parsing the executable file generated an i
|
||||
const nativeImageMissingExportedDataDirectoryError = "exported data directory is missing"
|
||||
|
||||
// newNativeImageCataloger returns a new Native Image cataloger object.
|
||||
func NewNativeImageCataloger() *NativeImageCataloger {
|
||||
func NewNativeImageCataloger() pkg.Cataloger {
|
||||
return &NativeImageCataloger{}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
package java
|
||||
|
||||
const MavenBaseURL = "https://repo1.maven.org/maven2"
|
||||
|
||||
type CatalogerOpts struct {
|
||||
UseNetwork bool
|
||||
MavenURL string
|
||||
MaxParentRecursiveDepth int
|
||||
}
|
||||
|
||||
func (j CatalogerOpts) WithUseNetwork(input bool) CatalogerOpts {
|
||||
j.UseNetwork = input
|
||||
return j
|
||||
}
|
||||
|
||||
func (j CatalogerOpts) WithMavenURL(input string) CatalogerOpts {
|
||||
if input != "" {
|
||||
j.MavenURL = input
|
||||
}
|
||||
return j
|
||||
}
|
||||
|
||||
func (j CatalogerOpts) WithMaxParentRecursiveDepth(input int) CatalogerOpts {
|
||||
if input > 0 {
|
||||
j.MaxParentRecursiveDepth = input
|
||||
}
|
||||
return j
|
||||
}
|
||||
|
||||
func DefaultCatalogerOpts() CatalogerOpts {
|
||||
return CatalogerOpts{
|
||||
UseNetwork: false,
|
||||
MavenURL: MavenBaseURL,
|
||||
MaxParentRecursiveDepth: 5,
|
||||
}
|
||||
}
|
||||
@@ -47,10 +47,10 @@ var genericTarGlobs = []string{
|
||||
// a file listing within the archive you must decompress the entire archive and seek through all of the entries.
|
||||
|
||||
type genericTarWrappedJavaArchiveParser struct {
|
||||
cfg Config
|
||||
cfg ArchiveCatalogerConfig
|
||||
}
|
||||
|
||||
func newGenericTarWrappedJavaArchiveParser(cfg Config) genericTarWrappedJavaArchiveParser {
|
||||
func newGenericTarWrappedJavaArchiveParser(cfg ArchiveCatalogerConfig) genericTarWrappedJavaArchiveParser {
|
||||
return genericTarWrappedJavaArchiveParser{
|
||||
cfg: cfg,
|
||||
}
|
||||
@@ -68,7 +68,7 @@ func (gtp genericTarWrappedJavaArchiveParser) parseTarWrappedJavaArchive(_ file.
|
||||
return discoverPkgsFromTar(reader.Location, archivePath, contentPath, gtp.cfg)
|
||||
}
|
||||
|
||||
func discoverPkgsFromTar(location file.Location, archivePath, contentPath string, cfg Config) ([]pkg.Package, []artifact.Relationship, error) {
|
||||
func discoverPkgsFromTar(location file.Location, archivePath, contentPath string, cfg ArchiveCatalogerConfig) ([]pkg.Package, []artifact.Relationship, error) {
|
||||
openers, err := intFile.ExtractGlobsFromTarToUniqueTempFile(archivePath, contentPath, archiveFormatGlobs...)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("unable to extract files from tar: %w", err)
|
||||
|
||||
@@ -40,7 +40,7 @@ func Test_parseTarWrappedJavaArchive(t *testing.T) {
|
||||
t.Fatalf("failed to open fixture: %+v", err)
|
||||
}
|
||||
|
||||
gtp := newGenericTarWrappedJavaArchiveParser(Config{})
|
||||
gtp := newGenericTarWrappedJavaArchiveParser(ArchiveCatalogerConfig{})
|
||||
actualPkgs, _, err := gtp.parseTarWrappedJavaArchive(nil, nil, file.LocationReadCloser{
|
||||
Location: file.NewLocation(test.fixture),
|
||||
ReadCloser: fixture,
|
||||
|
||||
@@ -19,10 +19,10 @@ var genericZipGlobs = []string{
|
||||
// parseZipWrappedJavaArchive is a parser function for java archive contents contained within arbitrary zip files.
|
||||
|
||||
type genericZipWrappedJavaArchiveParser struct {
|
||||
cfg Config
|
||||
cfg ArchiveCatalogerConfig
|
||||
}
|
||||
|
||||
func newGenericZipWrappedJavaArchiveParser(cfg Config) genericZipWrappedJavaArchiveParser {
|
||||
func newGenericZipWrappedJavaArchiveParser(cfg ArchiveCatalogerConfig) genericZipWrappedJavaArchiveParser {
|
||||
return genericZipWrappedJavaArchiveParser{
|
||||
cfg: cfg,
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ func Test_parseZipWrappedJavaArchive(t *testing.T) {
|
||||
t.Fatalf("failed to open fixture: %+v", err)
|
||||
}
|
||||
|
||||
gzp := newGenericZipWrappedJavaArchiveParser(Config{})
|
||||
gzp := newGenericZipWrappedJavaArchiveParser(ArchiveCatalogerConfig{})
|
||||
|
||||
actualPkgs, _, err := gzp.parseZipWrappedJavaArchive(nil, nil, file.LocationReadCloser{
|
||||
Location: file.NewLocation(test.fixture),
|
||||
|
||||
Reference in New Issue
Block a user