github.com/lineaje-labs/syft@v0.98.1-0.20231227153149-9e393f60ff1b/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/syft/pkg"
    12  	"github.com/anchore/syft/syft/pkg/cataloger/alpine"
    13  	"github.com/anchore/syft/syft/pkg/cataloger/arch"
    14  	"github.com/anchore/syft/syft/pkg/cataloger/binary"
    15  	"github.com/anchore/syft/syft/pkg/cataloger/cpp"
    16  	"github.com/anchore/syft/syft/pkg/cataloger/dart"
    17  	"github.com/anchore/syft/syft/pkg/cataloger/debian"
    18  	"github.com/anchore/syft/syft/pkg/cataloger/dotnet"
    19  	"github.com/anchore/syft/syft/pkg/cataloger/elixir"
    20  	"github.com/anchore/syft/syft/pkg/cataloger/erlang"
    21  	"github.com/anchore/syft/syft/pkg/cataloger/gentoo"
    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/python"
    31  	"github.com/anchore/syft/syft/pkg/cataloger/r"
    32  	"github.com/anchore/syft/syft/pkg/cataloger/redhat"
    33  	"github.com/anchore/syft/syft/pkg/cataloger/ruby"
    34  	"github.com/anchore/syft/syft/pkg/cataloger/rust"
    35  	"github.com/anchore/syft/syft/pkg/cataloger/sbom"
    36  	"github.com/anchore/syft/syft/pkg/cataloger/swift"
    37  	"github.com/lineaje-labs/syft/internal/log"
    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  		arch.NewDBCataloger(),
    46  		alpine.NewDBCataloger(),
    47  		binary.NewCataloger(),
    48  		cpp.NewConanInfoCataloger(),
    49  		debian.NewDBCataloger(),
    50  		dotnet.NewDotnetPortableExecutableCataloger(),
    51  		golang.NewGoModuleBinaryCataloger(cfg.Golang),
    52  		java.NewArchiveCataloger(cfg.JavaConfig()),
    53  		java.NewNativeImageCataloger(),
    54  		javascript.NewPackageCataloger(),
    55  		nix.NewStoreCataloger(),
    56  		php.NewComposerInstalledCataloger(),
    57  		gentoo.NewPortageCataloger(),
    58  		python.NewInstalledPackageCataloger(),
    59  		r.NewPackageCataloger(),
    60  		redhat.NewDBCataloger(),
    61  		ruby.NewInstalledGemSpecCataloger(),
    62  		sbom.NewCataloger(),
    63  	}, cfg.Catalogers)
    64  }
    65  
    66  // DirectoryCatalogers returns a slice of locally implemented catalogers that are fit for detecting packages from index files (and select installations)
    67  func DirectoryCatalogers(cfg Config) []pkg.Cataloger {
    68  	return filterCatalogers([]pkg.Cataloger{
    69  		arch.NewDBCataloger(),
    70  		alpine.NewDBCataloger(),
    71  		binary.NewCataloger(),
    72  		cpp.NewConanCataloger(),
    73  		dart.NewPubspecLockCataloger(),
    74  		debian.NewDBCataloger(),
    75  		dotnet.NewDotnetDepsCataloger(),
    76  		dotnet.NewDotnetPortableExecutableCataloger(),
    77  		elixir.NewMixLockCataloger(),
    78  		erlang.NewRebarLockCataloger(),
    79  		githubactions.NewActionUsageCataloger(),
    80  		githubactions.NewWorkflowUsageCataloger(),
    81  		golang.NewGoModuleFileCataloger(cfg.Golang),
    82  		golang.NewGoModuleBinaryCataloger(cfg.Golang),
    83  		haskell.NewHackageCataloger(),
    84  		java.NewArchiveCataloger(cfg.JavaConfig()),
    85  		java.NewGradleLockfileCataloger(),
    86  		java.NewPomCataloger(),
    87  		java.NewNativeImageCataloger(),
    88  		javascript.NewLockCataloger(),
    89  		nix.NewStoreCataloger(),
    90  		php.NewComposerLockCataloger(),
    91  		gentoo.NewPortageCataloger(),
    92  		python.NewPackageCataloger(cfg.Python),
    93  		python.NewInstalledPackageCataloger(),
    94  		redhat.NewArchiveCataloger(),
    95  		redhat.NewDBCataloger(),
    96  		ruby.NewGemFileLockCataloger(),
    97  		ruby.NewGemSpecCataloger(),
    98  		rust.NewCargoLockCataloger(),
    99  		sbom.NewCataloger(),
   100  		swift.NewCocoapodsCataloger(),
   101  		swift.NewSwiftPackageManagerCataloger(),
   102  	}, cfg.Catalogers)
   103  }
   104  
   105  // AllCatalogers returns all implemented catalogers
   106  func AllCatalogers(cfg Config) []pkg.Cataloger {
   107  	return filterCatalogers([]pkg.Cataloger{
   108  		arch.NewDBCataloger(),
   109  		alpine.NewDBCataloger(),
   110  		binary.NewCataloger(),
   111  		cpp.NewConanCataloger(),
   112  		dart.NewPubspecLockCataloger(),
   113  		debian.NewDBCataloger(),
   114  		dotnet.NewDotnetDepsCataloger(),
   115  		dotnet.NewDotnetPortableExecutableCataloger(),
   116  		elixir.NewMixLockCataloger(),
   117  		erlang.NewRebarLockCataloger(),
   118  		githubactions.NewActionUsageCataloger(),
   119  		githubactions.NewWorkflowUsageCataloger(),
   120  		golang.NewGoModuleFileCataloger(cfg.Golang),
   121  		golang.NewGoModuleBinaryCataloger(cfg.Golang),
   122  		haskell.NewHackageCataloger(),
   123  		java.NewArchiveCataloger(cfg.JavaConfig()),
   124  		java.NewGradleLockfileCataloger(),
   125  		java.NewPomCataloger(),
   126  		java.NewNativeImageCataloger(),
   127  		javascript.NewLockCataloger(),
   128  		javascript.NewPackageCataloger(),
   129  		kernel.NewLinuxKernelCataloger(cfg.LinuxKernel),
   130  		nix.NewStoreCataloger(),
   131  		php.NewComposerInstalledCataloger(),
   132  		php.NewComposerLockCataloger(),
   133  		gentoo.NewPortageCataloger(),
   134  		python.NewPackageCataloger(cfg.Python),
   135  		python.NewInstalledPackageCataloger(),
   136  		r.NewPackageCataloger(),
   137  		redhat.NewArchiveCataloger(),
   138  		redhat.NewDBCataloger(),
   139  		ruby.NewGemFileLockCataloger(),
   140  		ruby.NewGemSpecCataloger(),
   141  		ruby.NewInstalledGemSpecCataloger(),
   142  		rust.NewAuditBinaryCataloger(),
   143  		rust.NewCargoLockCataloger(),
   144  		sbom.NewCataloger(),
   145  		swift.NewCocoapodsCataloger(),
   146  		swift.NewSwiftPackageManagerCataloger(),
   147  	}, cfg.Catalogers)
   148  }
   149  
   150  func RequestedAllCatalogers(cfg Config) bool {
   151  	for _, enableCatalogerPattern := range cfg.Catalogers {
   152  		if enableCatalogerPattern == AllCatalogersPattern {
   153  			return true
   154  		}
   155  	}
   156  	return false
   157  }
   158  
   159  func filterCatalogers(catalogers []pkg.Cataloger, enabledCatalogerPatterns []string) []pkg.Cataloger {
   160  	// if cataloger is not set, all applicable catalogers are enabled by default
   161  	if len(enabledCatalogerPatterns) == 0 {
   162  		return catalogers
   163  	}
   164  	for _, enableCatalogerPattern := range enabledCatalogerPatterns {
   165  		if enableCatalogerPattern == AllCatalogersPattern {
   166  			return catalogers
   167  		}
   168  	}
   169  	var keepCatalogers []pkg.Cataloger
   170  	for _, cataloger := range catalogers {
   171  		if contains(enabledCatalogerPatterns, cataloger.Name()) {
   172  			keepCatalogers = append(keepCatalogers, cataloger)
   173  			continue
   174  		}
   175  		log.Infof("skipping cataloger %q", cataloger.Name())
   176  	}
   177  	return keepCatalogers
   178  }
   179  
   180  func contains(enabledPartial []string, catalogerName string) bool {
   181  	catalogerName = strings.TrimSuffix(catalogerName, "-cataloger")
   182  	for _, partial := range enabledPartial {
   183  		partial = strings.TrimSuffix(partial, "-cataloger")
   184  		if partial == "" {
   185  			continue
   186  		}
   187  		if hasFullWord(partial, catalogerName) {
   188  			return true
   189  		}
   190  	}
   191  	return false
   192  }
   193  
   194  func hasFullWord(targetPhrase, candidate string) bool {
   195  	if targetPhrase == "cataloger" || targetPhrase == "" {
   196  		return false
   197  	}
   198  	start := strings.Index(candidate, targetPhrase)
   199  	if start == -1 {
   200  		return false
   201  	}
   202  
   203  	if start > 0 && candidate[start-1] != '-' {
   204  		return false
   205  	}
   206  
   207  	end := start + len(targetPhrase)
   208  	if end < len(candidate) && candidate[end] != '-' {
   209  		return false
   210  	}
   211  	return true
   212  }