defer to GenericCataloger instances for pkg catalogers

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
This commit is contained in:
Alex Goodman 2020-10-06 11:23:54 -04:00 committed by Toure Dunnon
parent 7a8a5419b8
commit 1c320a8382
16 changed files with 81 additions and 268 deletions

View File

@ -4,39 +4,14 @@ Package apkdb provides a concrete Cataloger implementation for Alpine DB files.
package apkdb package apkdb
import ( import (
"github.com/anchore/stereoscope/pkg/file"
"github.com/anchore/syft/syft/cataloger/common" "github.com/anchore/syft/syft/cataloger/common"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/scope"
) )
// Cataloger catalogs pkg.ApkPkg Package Types defined in Alpine DB files. // NewApkdbCataloger returns a new Alpine DB cataloger object.
type Cataloger struct { func NewApkdbCataloger() *common.GenericCataloger {
cataloger common.GenericCataloger
}
// New returns a new Alpine DB cataloger object.
func New() *Cataloger {
globParsers := map[string]common.ParserFn{ globParsers := map[string]common.ParserFn{
"**/lib/apk/db/installed": parseApkDB, "**/lib/apk/db/installed": parseApkDB,
} }
return &Cataloger{ return common.NewGenericCataloger(nil, globParsers, "apkdb-cataloger")
cataloger: common.NewGenericCataloger(nil, globParsers),
}
}
// Name returns a string that uniquely describes this cataloger.
func (a *Cataloger) Name() string {
return "apkdb-cataloger"
}
// SelectFiles returns a set of discovered Alpine DB files from the user content source.
func (a *Cataloger) SelectFiles(resolver scope.FileResolver) []file.Reference {
return a.cataloger.SelectFiles(resolver)
}
// Catalog returns the Packages indexed from all Alpine DB files discovered.
func (a *Cataloger) Catalog(contents map[file.Reference]string) ([]pkg.Package, error) {
return a.cataloger.Catalog(contents, a.Name())
} }

View File

@ -4,40 +4,23 @@ Package bundler provides a concrete Cataloger implementation for Ruby Gemfile.lo
package bundler package bundler
import ( import (
"github.com/anchore/stereoscope/pkg/file"
"github.com/anchore/syft/syft/cataloger/common" "github.com/anchore/syft/syft/cataloger/common"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/scope"
) )
// Cataloger catalogs pkg.GemPkg Package Types defined in Bundler Gemfile.lock files. // NewGemfileLockCataloger returns a new Bundler cataloger object tailored for parsing index-oriented files (e.g. Gemfile.lock).
type Cataloger struct { func NewGemfileLockCataloger() *common.GenericCataloger {
cataloger common.GenericCataloger
}
// New returns a new Bundler cataloger object.
func New() *Cataloger {
globParsers := map[string]common.ParserFn{ globParsers := map[string]common.ParserFn{
"**/Gemfile.lock": parseGemfileLockEntries, // valid in a dir context "**/Gemfile.lock": parseGemfileLockEntries,
//"**/specification/*.gemspec": parseGemSpecEntries, // valid in an image context (against installed gems)
} }
return &Cataloger{ return common.NewGenericCataloger(nil, globParsers, "ruby-gemfile-cataloger")
cataloger: common.NewGenericCataloger(nil, globParsers), }
// NewGemspecCataloger returns a new Bundler cataloger object tailored for detecting installations of gems (e.g. Gemspec).
func NewGemspecCataloger() *common.GenericCataloger {
globParsers := map[string]common.ParserFn{
"**/specification/*.gemspec": parseGemspecEntries,
} }
}
// Name returns a string that uniquely describes this cataloger. return common.NewGenericCataloger(nil, globParsers, "ruby-gemspec-cataloger")
func (a *Cataloger) Name() string {
return "bundler-cataloger"
}
// SelectFiles returns a set of discovered Gemfile.lock files from the user content source.
func (a *Cataloger) SelectFiles(resolver scope.FileResolver) []file.Reference {
return a.cataloger.SelectFiles(resolver)
}
// Catalog returns the Packages indexed from all Gemfile.lock files discovered.
func (a *Cataloger) Catalog(contents map[file.Reference]string) ([]pkg.Package, error) {
return a.cataloger.Catalog(contents, a.Name())
} }

View File

@ -9,7 +9,7 @@ import (
"github.com/anchore/stereoscope/pkg/file" "github.com/anchore/stereoscope/pkg/file"
"github.com/anchore/syft/syft/cataloger/apkdb" "github.com/anchore/syft/syft/cataloger/apkdb"
"github.com/anchore/syft/syft/cataloger/bundler" "github.com/anchore/syft/syft/cataloger/bundler"
"github.com/anchore/syft/syft/cataloger/dpkg" "github.com/anchore/syft/syft/cataloger/deb"
"github.com/anchore/syft/syft/cataloger/golang" "github.com/anchore/syft/syft/cataloger/golang"
"github.com/anchore/syft/syft/cataloger/java" "github.com/anchore/syft/syft/cataloger/java"
"github.com/anchore/syft/syft/cataloger/javascript" "github.com/anchore/syft/syft/cataloger/javascript"
@ -36,13 +36,13 @@ type Cataloger interface {
// All returns a slice of all locally defined catalogers (defined in child packages). // All returns a slice of all locally defined catalogers (defined in child packages).
func All() []Cataloger { func All() []Cataloger {
return []Cataloger{ return []Cataloger{
dpkg.New(), deb.NewDpkgdbCataloger(),
bundler.New(), bundler.NewGemfileLockCataloger(),
python.New(), python.NewPythonCataloger(),
rpmdb.New(), rpmdb.NewRpmdbCataloger(),
java.New(), java.NewJavaCataloger(),
apkdb.New(), apkdb.NewApkdbCataloger(),
golang.New(), golang.NewGoModCataloger(),
javascript.New(), javascript.NewJavascriptCataloger(),
} }
} }

View File

@ -15,22 +15,29 @@ import (
// GenericCataloger implements the Catalog interface and is responsible for dispatching the proper parser function for // GenericCataloger implements the Catalog interface and is responsible for dispatching the proper parser function for
// a given path or glob pattern. This is intended to be reusable across many package cataloger types. // a given path or glob pattern. This is intended to be reusable across many package cataloger types.
type GenericCataloger struct { type GenericCataloger struct {
globParsers map[string]ParserFn globParsers map[string]ParserFn
pathParsers map[string]ParserFn pathParsers map[string]ParserFn
selectedFiles []file.Reference selectedFiles []file.Reference
parsers map[file.Reference]ParserFn parsers map[file.Reference]ParserFn
upstreamMatcher string
} }
// NewGenericCataloger if provided path-to-parser-function and glob-to-parser-function lookups creates a GenericCataloger // NewGenericCataloger if provided path-to-parser-function and glob-to-parser-function lookups creates a GenericCataloger
func NewGenericCataloger(pathParsers map[string]ParserFn, globParsers map[string]ParserFn) GenericCataloger { func NewGenericCataloger(pathParsers map[string]ParserFn, globParsers map[string]ParserFn, upstreamMatcher string) *GenericCataloger {
return GenericCataloger{ return &GenericCataloger{
globParsers: globParsers, globParsers: globParsers,
pathParsers: pathParsers, pathParsers: pathParsers,
selectedFiles: make([]file.Reference, 0), selectedFiles: make([]file.Reference, 0),
parsers: make(map[file.Reference]ParserFn), parsers: make(map[file.Reference]ParserFn),
upstreamMatcher: upstreamMatcher,
} }
} }
// Name returns a string that uniquely describes the upstream cataloger that this Generic Cataloger represents.
func (a *GenericCataloger) Name() string {
return a.upstreamMatcher
}
// register pairs a set of file references with a parser function for future cataloging (when the file contents are resolved) // register pairs a set of file references with a parser function for future cataloging (when the file contents are resolved)
func (a *GenericCataloger) register(files []file.Reference, parser ParserFn) { func (a *GenericCataloger) register(files []file.Reference, parser ParserFn) {
a.selectedFiles = append(a.selectedFiles, files...) a.selectedFiles = append(a.selectedFiles, files...)
@ -73,7 +80,7 @@ func (a *GenericCataloger) SelectFiles(resolver scope.FileResolver) []file.Refer
} }
// Catalog takes a set of file contents and uses any configured parser functions to resolve and return discovered packages // Catalog takes a set of file contents and uses any configured parser functions to resolve and return discovered packages
func (a *GenericCataloger) Catalog(contents map[file.Reference]string, upstreamMatcher string) ([]pkg.Package, error) { func (a *GenericCataloger) Catalog(contents map[file.Reference]string) ([]pkg.Package, error) {
defer a.clear() defer a.clear()
packages := make([]pkg.Package, 0) packages := make([]pkg.Package, 0)
@ -81,19 +88,19 @@ func (a *GenericCataloger) Catalog(contents map[file.Reference]string, upstreamM
for reference, parser := range a.parsers { for reference, parser := range a.parsers {
content, ok := contents[reference] content, ok := contents[reference]
if !ok { if !ok {
log.Errorf("cataloger '%s' missing file content: %+v", upstreamMatcher, reference) log.Errorf("cataloger '%s' missing file content: %+v", a.upstreamMatcher, reference)
continue continue
} }
entries, err := parser(string(reference.Path), strings.NewReader(content)) entries, err := parser(string(reference.Path), strings.NewReader(content))
if err != nil { if err != nil {
// TODO: should we fail? or only log? // TODO: should we fail? or only log?
log.Errorf("cataloger '%s' failed to parse entries (reference=%+v): %+v", upstreamMatcher, reference, err) log.Errorf("cataloger '%s' failed to parse entries (reference=%+v): %+v", a.upstreamMatcher, reference, err)
continue continue
} }
for _, entry := range entries { for _, entry := range entries {
entry.FoundBy = upstreamMatcher entry.FoundBy = a.upstreamMatcher
entry.Source = []file.Reference{reference} entry.Source = []file.Reference{reference}
packages = append(packages, entry) packages = append(packages, entry)

View File

@ -60,9 +60,9 @@ func TestGenericCataloger(t *testing.T) {
"/another-path.txt": parser, "/another-path.txt": parser,
"/last/path.txt": parser, "/last/path.txt": parser,
} }
upstream := "some-other-cataloger"
resolver := newTestResolver() resolver := newTestResolver()
cataloger := NewGenericCataloger(pathParsers, globParsers) cataloger := NewGenericCataloger(pathParsers, globParsers, upstream)
selected := cataloger.SelectFiles(resolver) selected := cataloger.SelectFiles(resolver)
@ -79,7 +79,6 @@ func TestGenericCataloger(t *testing.T) {
selectionByPath[string(s.Path)] = s selectionByPath[string(s.Path)] = s
} }
upstream := "some-other-cataloger"
expectedPkgs := make(map[file.Reference]pkg.Package) expectedPkgs := make(map[file.Reference]pkg.Package)
for path, ref := range selectionByPath { for path, ref := range selectionByPath {
expectedPkgs[ref] = pkg.Package{ expectedPkgs[ref] = pkg.Package{
@ -89,7 +88,7 @@ func TestGenericCataloger(t *testing.T) {
} }
} }
actualPkgs, err := cataloger.Catalog(resolver.contents, upstream) actualPkgs, err := cataloger.Catalog(resolver.contents)
if err != nil { if err != nil {
t.Fatalf("cataloger catalog action failed: %+v", err) t.Fatalf("cataloger catalog action failed: %+v", err)
} }

View File

@ -0,0 +1,17 @@
/*
Package dpkg provides a concrete Cataloger implementation for Debian package DB status files.
*/
package deb
import (
"github.com/anchore/syft/syft/cataloger/common"
)
// NewDpkgdbCataloger returns a new Deb package cataloger object.
func NewDpkgdbCataloger() *common.GenericCataloger {
globParsers := map[string]common.ParserFn{
"**/var/lib/dpkg/status": parseDpkgStatus,
}
return common.NewGenericCataloger(nil, globParsers, "dpkgdb-cataloger")
}

View File

@ -1,4 +1,4 @@
package dpkg package deb
import ( import (
"bufio" "bufio"

View File

@ -1,4 +1,4 @@
package dpkg package deb
import ( import (
"bufio" "bufio"

View File

@ -1,42 +0,0 @@
/*
Package dpkg provides a concrete Cataloger implementation for Debian package DB status files.
*/
package dpkg
import (
"github.com/anchore/stereoscope/pkg/file"
"github.com/anchore/syft/syft/cataloger/common"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/scope"
)
// Cataloger catalogs pkg.DebPkg Package Types defined in DPKG status files.
type Cataloger struct {
cataloger common.GenericCataloger
}
// New returns a new Deb package cataloger object.
func New() *Cataloger {
globParsers := map[string]common.ParserFn{
"**/var/lib/dpkg/status": parseDpkgStatus,
}
return &Cataloger{
cataloger: common.NewGenericCataloger(nil, globParsers),
}
}
// Name returns a string that uniquely describes this cataloger.
func (a *Cataloger) Name() string {
return "dpkg-cataloger"
}
// SelectFiles returns a set of discovered DPKG status files from the user content source.
func (a *Cataloger) SelectFiles(resolver scope.FileResolver) []file.Reference {
return a.cataloger.SelectFiles(resolver)
}
// Catalog returns the Packages indexed from all DPKG status files discovered.
func (a *Cataloger) Catalog(contents map[file.Reference]string) ([]pkg.Package, error) {
return a.cataloger.Catalog(contents, a.Name())
}

View File

@ -4,39 +4,14 @@ Package golang provides a concrete Cataloger implementation for go.mod files.
package golang package golang
import ( import (
"github.com/anchore/stereoscope/pkg/file"
"github.com/anchore/syft/syft/cataloger/common" "github.com/anchore/syft/syft/cataloger/common"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/scope"
) )
// Cataloger catalogs pkg.GoModulePkg Package Types defined in go.mod files. // NewGoModCataloger returns a new Go module cataloger object.
type Cataloger struct { func NewGoModCataloger() *common.GenericCataloger {
cataloger common.GenericCataloger
}
// New returns a new Go module cataloger object.
func New() *Cataloger {
globParsers := map[string]common.ParserFn{ globParsers := map[string]common.ParserFn{
"**/go.mod": parseGoMod, "**/go.mod": parseGoMod,
} }
return &Cataloger{ return common.NewGenericCataloger(nil, globParsers, "go-cataloger")
cataloger: common.NewGenericCataloger(nil, globParsers),
}
}
// Name returns a string that uniquely describes this cataloger.
func (a *Cataloger) Name() string {
return "go-cataloger"
}
// SelectFiles returns a set of discovered go.mod files from the user content source.
func (a *Cataloger) SelectFiles(resolver scope.FileResolver) []file.Reference {
return a.cataloger.SelectFiles(resolver)
}
// Catalog returns the Packages indexed from all go.mod files discovered.
func (a *Cataloger) Catalog(contents map[file.Reference]string) ([]pkg.Package, error) {
return a.cataloger.Catalog(contents, a.Name())
} }

View File

@ -4,40 +4,15 @@ Package java provides a concrete Cataloger implementation for Java archives (jar
package java package java
import ( import (
"github.com/anchore/stereoscope/pkg/file"
"github.com/anchore/syft/syft/cataloger/common" "github.com/anchore/syft/syft/cataloger/common"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/scope"
) )
// Cataloger catalogs pkg.JavaPkg and pkg.JenkinsPluginPkg Package Types defined in java archive files. // NewJavaCataloger returns a new Java archive cataloger object.
type Cataloger struct { func NewJavaCataloger() *common.GenericCataloger {
cataloger common.GenericCataloger
}
// New returns a new Java archive cataloger object.
func New() *Cataloger {
globParsers := make(map[string]common.ParserFn) globParsers := make(map[string]common.ParserFn)
for _, pattern := range archiveFormatGlobs { for _, pattern := range archiveFormatGlobs {
globParsers[pattern] = parseJavaArchive globParsers[pattern] = parseJavaArchive
} }
return &Cataloger{ return common.NewGenericCataloger(nil, globParsers, "java-cataloger")
cataloger: common.NewGenericCataloger(nil, globParsers),
}
}
// Name returns a string that uniquely describes this cataloger.
func (a *Cataloger) Name() string {
return "java-cataloger"
}
// SelectFiles returns a set of discovered Java archive files from the user content source.
func (a *Cataloger) SelectFiles(resolver scope.FileResolver) []file.Reference {
return a.cataloger.SelectFiles(resolver)
}
// Catalog returns the Packages indexed from all Java archive files discovered.
func (a *Cataloger) Catalog(contents map[file.Reference]string) ([]pkg.Package, error) {
return a.cataloger.Catalog(contents, a.Name())
} }

View File

@ -4,40 +4,15 @@ Package javascript provides a concrete Cataloger implementation for JavaScript e
package javascript package javascript
import ( import (
"github.com/anchore/stereoscope/pkg/file"
"github.com/anchore/syft/syft/cataloger/common" "github.com/anchore/syft/syft/cataloger/common"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/scope"
) )
// Cataloger catalogs pkg.YarnPkg and pkg.NpmPkg Package Types defined in package-lock.json and yarn.lock files. // NewJavascriptCataloger returns a new JavaScript cataloger object.
type Cataloger struct { func NewJavascriptCataloger() *common.GenericCataloger {
cataloger common.GenericCataloger
}
// New returns a new JavaScript cataloger object.
func New() *Cataloger {
globParsers := map[string]common.ParserFn{ globParsers := map[string]common.ParserFn{
"**/package-lock.json": parsePackageLock, "**/package-lock.json": parsePackageLock,
"**/yarn.lock": parseYarnLock, "**/yarn.lock": parseYarnLock,
} }
return &Cataloger{ return common.NewGenericCataloger(nil, globParsers, "javascript-cataloger")
cataloger: common.NewGenericCataloger(nil, globParsers),
}
}
// Name returns a string that uniquely describes this cataloger.
func (a *Cataloger) Name() string {
return "javascript-cataloger"
}
// SelectFiles returns a set of discovered Javascript ecosystem files from the user content source.
func (a *Cataloger) SelectFiles(resolver scope.FileResolver) []file.Reference {
return a.cataloger.SelectFiles(resolver)
}
// Catalog returns the Packages indexed from all Javascript ecosystem files discovered.
func (a *Cataloger) Catalog(contents map[file.Reference]string) ([]pkg.Package, error) {
return a.cataloger.Catalog(contents, a.Name())
} }

View File

@ -4,19 +4,11 @@ Package python provides a concrete Cataloger implementation for Python ecosystem
package python package python
import ( import (
"github.com/anchore/stereoscope/pkg/file"
"github.com/anchore/syft/syft/cataloger/common" "github.com/anchore/syft/syft/cataloger/common"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/scope"
) )
// Cataloger catalogs pkg.WheelPkg, pkg.EggPkg, and pkg.PythonRequirementsPkg Package Types defined in Python ecosystem files. // NewPythonCataloger returns a new Python cataloger object.
type Cataloger struct { func NewPythonCataloger() *common.GenericCataloger {
cataloger common.GenericCataloger
}
// New returns a new Python cataloger object.
func New() *Cataloger {
globParsers := map[string]common.ParserFn{ globParsers := map[string]common.ParserFn{
"**/*egg-info/PKG-INFO": parseEggMetadata, "**/*egg-info/PKG-INFO": parseEggMetadata,
"**/*dist-info/METADATA": parseWheelMetadata, "**/*dist-info/METADATA": parseWheelMetadata,
@ -25,22 +17,5 @@ func New() *Cataloger {
"**/setup.py": parseSetup, "**/setup.py": parseSetup,
} }
return &Cataloger{ return common.NewGenericCataloger(nil, globParsers, "python-cataloger")
cataloger: common.NewGenericCataloger(nil, globParsers),
}
}
// Name returns a string that uniquely describes this cataloger.
func (a *Cataloger) Name() string {
return "python-cataloger"
}
// SelectFiles returns a set of discovered Python ecosystem files from the user content source.
func (a *Cataloger) SelectFiles(resolver scope.FileResolver) []file.Reference {
return a.cataloger.SelectFiles(resolver)
}
// Catalog returns the Packages indexed from all Python ecosystem files discovered.
func (a *Cataloger) Catalog(contents map[file.Reference]string) ([]pkg.Package, error) {
return a.cataloger.Catalog(contents, a.Name())
} }

View File

@ -4,39 +4,13 @@ Package rpmdb provides a concrete Cataloger implementation for RPM "Package" DB
package rpmdb package rpmdb
import ( import (
"github.com/anchore/stereoscope/pkg/file"
"github.com/anchore/syft/syft/cataloger/common" "github.com/anchore/syft/syft/cataloger/common"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/scope"
) )
// Cataloger catalogs pkg.RpmPkg Package Types defined in RPM DB files. // NewRpmdbCataloger returns a new RPM DB cataloger object.
type Cataloger struct { func NewRpmdbCataloger() *common.GenericCataloger {
cataloger common.GenericCataloger
}
// New returns a new RPM DB cataloger object.
func New() *Cataloger {
globParsers := map[string]common.ParserFn{ globParsers := map[string]common.ParserFn{
"**/var/lib/rpm/Packages": parseRpmDB, "**/var/lib/rpm/Packages": parseRpmDB,
} }
return common.NewGenericCataloger(nil, globParsers, "rpmdb-cataloger")
return &Cataloger{
cataloger: common.NewGenericCataloger(nil, globParsers),
}
}
// Name returns a string that uniquely describes this cataloger.
func (a *Cataloger) Name() string {
return "rpmdb-cataloger"
}
// SelectFiles returns a set of discovered RPM DB files from the user content source.
func (a *Cataloger) SelectFiles(resolver scope.FileResolver) []file.Reference {
return a.cataloger.SelectFiles(resolver)
}
// Catalog returns the Packages indexed from all RPM DB files discovered.
func (a *Cataloger) Catalog(contents map[file.Reference]string) ([]pkg.Package, error) {
return a.cataloger.Catalog(contents, a.Name())
} }