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