github.com/noqcks/syft@v0.0.0-20230920222752-a9e2c4e288e5/syft/pkg/cataloger/cataloger.go (about)

     1  /*
     2  Package cataloger provides the ability to process files from a container image or file system and discover packages
     3  (gems, wheels, jars, rpms, debs, etc). Specifically, this package contains both a catalog function to utilize all
     4  catalogers defined in child packages as well as the interface definition to implement a cataloger.
     5  */
     6  package cataloger
     7  
     8  import (
     9  	"strings"
    10  
    11  	"github.com/anchore/syft/internal/log"
    12  	"github.com/anchore/syft/syft/pkg"
    13  	"github.com/anchore/syft/syft/pkg/cataloger/alpm"
    14  	"github.com/anchore/syft/syft/pkg/cataloger/apkdb"
    15  	"github.com/anchore/syft/syft/pkg/cataloger/binary"
    16  	"github.com/anchore/syft/syft/pkg/cataloger/cpp"
    17  	"github.com/anchore/syft/syft/pkg/cataloger/dart"
    18  	"github.com/anchore/syft/syft/pkg/cataloger/deb"
    19  	"github.com/anchore/syft/syft/pkg/cataloger/dotnet"
    20  	"github.com/anchore/syft/syft/pkg/cataloger/elixir"
    21  	"github.com/anchore/syft/syft/pkg/cataloger/erlang"
    22  	"github.com/anchore/syft/syft/pkg/cataloger/githubactions"
    23  	"github.com/anchore/syft/syft/pkg/cataloger/golang"
    24  	"github.com/anchore/syft/syft/pkg/cataloger/haskell"
    25  	"github.com/anchore/syft/syft/pkg/cataloger/java"
    26  	"github.com/anchore/syft/syft/pkg/cataloger/javascript"
    27  	"github.com/anchore/syft/syft/pkg/cataloger/kernel"
    28  	"github.com/anchore/syft/syft/pkg/cataloger/nix"
    29  	"github.com/anchore/syft/syft/pkg/cataloger/php"
    30  	"github.com/anchore/syft/syft/pkg/cataloger/portage"
    31  	"github.com/anchore/syft/syft/pkg/cataloger/python"
    32  	"github.com/anchore/syft/syft/pkg/cataloger/r"
    33  	"github.com/anchore/syft/syft/pkg/cataloger/rpm"
    34  	"github.com/anchore/syft/syft/pkg/cataloger/ruby"
    35  	"github.com/anchore/syft/syft/pkg/cataloger/rust"
    36  	"github.com/anchore/syft/syft/pkg/cataloger/sbom"
    37  	"github.com/anchore/syft/syft/pkg/cataloger/swift"
    38  )
    39  
    40  const AllCatalogersPattern = "all"
    41  
    42  // ImageCatalogers returns a slice of locally implemented catalogers that are fit for detecting installations of packages.
    43  func ImageCatalogers(cfg Config) []pkg.Cataloger {
    44  	return filterCatalogers([]pkg.Cataloger{
    45  		alpm.NewAlpmdbCataloger(),
    46  		apkdb.NewApkdbCataloger(),
    47  		binary.NewCataloger(),
    48  		deb.NewDpkgdbCataloger(),
    49  		dotnet.NewDotnetPortableExecutableCataloger(),
    50  		golang.NewGoModuleBinaryCataloger(cfg.Golang),
    51  		java.NewJavaCataloger(cfg.Java()),
    52  		java.NewNativeImageCataloger(),
    53  		javascript.NewPackageCataloger(),
    54  		nix.NewStoreCataloger(),
    55  		php.NewComposerInstalledCataloger(),
    56  		portage.NewPortageCataloger(),
    57  		python.NewPythonPackageCataloger(),
    58  		r.NewPackageCataloger(),
    59  		rpm.NewRpmDBCataloger(),
    60  		ruby.NewGemSpecCataloger(),
    61  		sbom.NewSBOMCataloger(),
    62  	}, cfg.Catalogers)
    63  }
    64  
    65  // DirectoryCatalogers returns a slice of locally implemented catalogers that are fit for detecting packages from index files (and select installations)
    66  func DirectoryCatalogers(cfg Config) []pkg.Cataloger {
    67  	return filterCatalogers([]pkg.Cataloger{
    68  		alpm.NewAlpmdbCataloger(),
    69  		apkdb.NewApkdbCataloger(),
    70  		binary.NewCataloger(),
    71  		cpp.NewConanCataloger(),
    72  		dart.NewPubspecLockCataloger(),
    73  		deb.NewDpkgdbCataloger(),
    74  		dotnet.NewDotnetDepsCataloger(),
    75  		dotnet.NewDotnetPortableExecutableCataloger(),
    76  		elixir.NewMixLockCataloger(),
    77  		erlang.NewRebarLockCataloger(),
    78  		githubactions.NewActionUsageCataloger(),
    79  		githubactions.NewWorkflowUsageCataloger(),
    80  		golang.NewGoModFileCataloger(cfg.Golang),
    81  		golang.NewGoModuleBinaryCataloger(cfg.Golang),
    82  		haskell.NewHackageCataloger(),
    83  		java.NewJavaCataloger(cfg.Java()),
    84  		java.NewJavaGradleLockfileCataloger(),
    85  		java.NewJavaPomCataloger(),
    86  		java.NewNativeImageCataloger(),
    87  		javascript.NewLockCataloger(),
    88  		javascript.NewJavaScriptCataloger(),
    89  		nix.NewStoreCataloger(),
    90  		php.NewComposerLockCataloger(),
    91  		portage.NewPortageCataloger(),
    92  		python.NewPythonIndexCataloger(cfg.Python),
    93  		python.NewPythonPackageCataloger(),
    94  		rpm.NewFileCataloger(),
    95  		rpm.NewRpmDBCataloger(),
    96  		ruby.NewGemFileLockCataloger(),
    97  		rust.NewCargoLockCataloger(),
    98  		sbom.NewSBOMCataloger(),
    99  		swift.NewCocoapodsCataloger(),
   100  		swift.NewSwiftPackageManagerCataloger(),
   101  	}, cfg.Catalogers)
   102  }
   103  
   104  // AllCatalogers returns all implemented catalogers
   105  func AllCatalogers(cfg Config) []pkg.Cataloger {
   106  	return filterCatalogers([]pkg.Cataloger{
   107  		alpm.NewAlpmdbCataloger(),
   108  		apkdb.NewApkdbCataloger(),
   109  		binary.NewCataloger(),
   110  		cpp.NewConanCataloger(),
   111  		dart.NewPubspecLockCataloger(),
   112  		deb.NewDpkgdbCataloger(),
   113  		dotnet.NewDotnetDepsCataloger(),
   114  		dotnet.NewDotnetPortableExecutableCataloger(),
   115  		elixir.NewMixLockCataloger(),
   116  		erlang.NewRebarLockCataloger(),
   117  		githubactions.NewActionUsageCataloger(),
   118  		githubactions.NewWorkflowUsageCataloger(),
   119  		golang.NewGoModFileCataloger(cfg.Golang),
   120  		golang.NewGoModuleBinaryCataloger(cfg.Golang),
   121  		haskell.NewHackageCataloger(),
   122  		java.NewJavaCataloger(cfg.Java()),
   123  		java.NewJavaGradleLockfileCataloger(),
   124  		java.NewJavaPomCataloger(),
   125  		java.NewNativeImageCataloger(),
   126  		javascript.NewLockCataloger(),
   127  		javascript.NewJavaScriptCataloger(),
   128  		javascript.NewPackageCataloger(),
   129  		kernel.NewLinuxKernelCataloger(cfg.LinuxKernel),
   130  		nix.NewStoreCataloger(),
   131  		php.NewComposerInstalledCataloger(),
   132  		php.NewComposerLockCataloger(),
   133  		portage.NewPortageCataloger(),
   134  		python.NewPythonIndexCataloger(cfg.Python),
   135  		python.NewPythonPackageCataloger(),
   136  		r.NewPackageCataloger(),
   137  		rpm.NewFileCataloger(),
   138  		rpm.NewRpmDBCataloger(),
   139  		ruby.NewGemFileLockCataloger(),
   140  		ruby.NewGemSpecCataloger(),
   141  		rust.NewAuditBinaryCataloger(),
   142  		rust.NewCargoLockCataloger(),
   143  		sbom.NewSBOMCataloger(),
   144  		swift.NewCocoapodsCataloger(),
   145  		swift.NewSwiftPackageManagerCataloger(),
   146  	}, cfg.Catalogers)
   147  }
   148  
   149  func RequestedAllCatalogers(cfg Config) bool {
   150  	for _, enableCatalogerPattern := range cfg.Catalogers {
   151  		if enableCatalogerPattern == AllCatalogersPattern {
   152  			return true
   153  		}
   154  	}
   155  	return false
   156  }
   157  
   158  func filterCatalogers(catalogers []pkg.Cataloger, enabledCatalogerPatterns []string) []pkg.Cataloger {
   159  	// if cataloger is not set, all applicable catalogers are enabled by default
   160  	if len(enabledCatalogerPatterns) == 0 {
   161  		return catalogers
   162  	}
   163  	for _, enableCatalogerPattern := range enabledCatalogerPatterns {
   164  		if enableCatalogerPattern == AllCatalogersPattern {
   165  			return catalogers
   166  		}
   167  	}
   168  	var keepCatalogers []pkg.Cataloger
   169  	for _, cataloger := range catalogers {
   170  		if contains(enabledCatalogerPatterns, cataloger.Name()) {
   171  			keepCatalogers = append(keepCatalogers, cataloger)
   172  			continue
   173  		}
   174  		log.Infof("skipping cataloger %q", cataloger.Name())
   175  	}
   176  	return keepCatalogers
   177  }
   178  
   179  func contains(enabledPartial []string, catalogerName string) bool {
   180  	catalogerName = strings.TrimSuffix(catalogerName, "-cataloger")
   181  	for _, partial := range enabledPartial {
   182  		partial = strings.TrimSuffix(partial, "-cataloger")
   183  		if partial == "" {
   184  			continue
   185  		}
   186  		if hasFullWord(partial, catalogerName) {
   187  			return true
   188  		}
   189  	}
   190  	return false
   191  }
   192  
   193  func hasFullWord(targetPhrase, candidate string) bool {
   194  	if targetPhrase == "cataloger" || targetPhrase == "" {
   195  		return false
   196  	}
   197  	start := strings.Index(candidate, targetPhrase)
   198  	if start == -1 {
   199  		return false
   200  	}
   201  
   202  	if start > 0 && candidate[start-1] != '-' {
   203  		return false
   204  	}
   205  
   206  	end := start + len(targetPhrase)
   207  	if end < len(candidate) && candidate[end] != '-' {
   208  		return false
   209  	}
   210  	return true
   211  }