github.com/google/osv-scalibr@v0.4.1/enricher/enricherlist/list.go (about) 1 // Copyright 2025 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Package enricherlist provides methods to initialize enrichers from attributes like names or capabilities. 16 package enricherlist 17 18 import ( 19 "fmt" 20 "maps" 21 "slices" 22 23 "github.com/google/osv-scalibr/enricher" 24 "github.com/google/osv-scalibr/enricher/baseimage" 25 govcsource "github.com/google/osv-scalibr/enricher/govulncheck/source" 26 "github.com/google/osv-scalibr/enricher/hcpidentity" 27 "github.com/google/osv-scalibr/enricher/huggingfacemeta" 28 "github.com/google/osv-scalibr/enricher/license" 29 "github.com/google/osv-scalibr/enricher/packagedeprecation" 30 "github.com/google/osv-scalibr/enricher/reachability/java" 31 "github.com/google/osv-scalibr/enricher/secrets/convert" 32 "github.com/google/osv-scalibr/enricher/secrets/hashicorp" 33 "github.com/google/osv-scalibr/enricher/transitivedependency/requirements" 34 "github.com/google/osv-scalibr/enricher/vex/filter" 35 "github.com/google/osv-scalibr/enricher/vulnmatch/osvdev" 36 "github.com/google/osv-scalibr/veles" 37 "github.com/google/osv-scalibr/veles/secrets/anthropicapikey" 38 "github.com/google/osv-scalibr/veles/secrets/awsaccesskey" 39 "github.com/google/osv-scalibr/veles/secrets/cratesioapitoken" 40 "github.com/google/osv-scalibr/veles/secrets/digitaloceanapikey" 41 "github.com/google/osv-scalibr/veles/secrets/dockerhubpat" 42 "github.com/google/osv-scalibr/veles/secrets/gcpoauth2access" 43 "github.com/google/osv-scalibr/veles/secrets/gcpsak" 44 "github.com/google/osv-scalibr/veles/secrets/gcshmackey" 45 "github.com/google/osv-scalibr/veles/secrets/gitbasicauth/codecatalyst" 46 "github.com/google/osv-scalibr/veles/secrets/github" 47 "github.com/google/osv-scalibr/veles/secrets/gitlabpat" 48 "github.com/google/osv-scalibr/veles/secrets/grokxaiapikey" 49 "github.com/google/osv-scalibr/veles/secrets/hcp" 50 "github.com/google/osv-scalibr/veles/secrets/huggingfaceapikey" 51 "github.com/google/osv-scalibr/veles/secrets/openai" 52 "github.com/google/osv-scalibr/veles/secrets/perplexityapikey" 53 "github.com/google/osv-scalibr/veles/secrets/postmanapikey" 54 "github.com/google/osv-scalibr/veles/secrets/pypiapitoken" 55 "github.com/google/osv-scalibr/veles/secrets/slacktoken" 56 "github.com/google/osv-scalibr/veles/secrets/stripeapikeys" 57 58 cpb "github.com/google/osv-scalibr/binary/proto/config_go_proto" 59 ) 60 61 // InitFn is the enricher initializer function. 62 type InitFn func(cfg *cpb.PluginConfig) enricher.Enricher 63 64 // InitMap is a map of names to enricher initializer functions. 65 type InitMap map[string][]InitFn 66 67 var ( 68 69 // LayerDetails enrichers. 70 LayerDetails = InitMap{ 71 baseimage.Name: {noCFG(baseimage.NewDefault)}, 72 } 73 74 // License enrichers. 75 License = InitMap{ 76 license.Name: {noCFG(license.New)}, 77 } 78 79 // VulnMatching enrichers. 80 VulnMatching = InitMap{ 81 82 osvdev.Name: {noCFG(osvdev.NewDefault)}, 83 } 84 85 // VEX related enrichers. 86 VEX = InitMap{ 87 filter.Name: {noCFG(filter.New)}, 88 } 89 90 // SecretsValidate lists secret validators. 91 SecretsValidate = initMapFromVelesPlugins([]velesPlugin{ 92 fromVeles(anthropicapikey.NewWorkspaceValidator(), "secrets/anthropicapikeyworkspacevalidate", 0), 93 fromVeles(anthropicapikey.NewModelValidator(), "secrets/anthropicapikeymodelvalidate", 0), 94 fromVeles(digitaloceanapikey.NewValidator(), "secrets/digitaloceanapikeyvalidate", 0), 95 fromVeles(pypiapitoken.NewValidator(), "secrets/pypiapitokenvalidate", 0), 96 fromVeles(cratesioapitoken.NewValidator(), "secrets/cratesioapitokenvalidate", 0), 97 fromVeles(slacktoken.NewAppLevelTokenValidator(), "secrets/slackappleveltokenvalidate", 0), 98 fromVeles(slacktoken.NewAppConfigRefreshTokenValidator(), "secrets/slackconfigrefreshtokenvalidate", 0), 99 fromVeles(slacktoken.NewAppConfigAccessTokenValidator(), "secrets/slackconfigaccesstokenvalidate", 0), 100 fromVeles(dockerhubpat.NewValidator(), "secrets/dockerhubpatvalidate", 0), 101 fromVeles(gcpsak.NewValidator(), "secrets/gcpsakvalidate", 0), 102 fromVeles(gitlabpat.NewValidator(), "secrets/gitlabpatvalidate", 0), 103 fromVeles(grokxaiapikey.NewAPIValidator(), "secrets/grokxaiapikeyvalidate", 0), 104 fromVeles(grokxaiapikey.NewManagementAPIValidator(), "secrets/grokxaimanagementkeyvalidate", 0), 105 fromVelesWithCfg(hashicorp.NewTokenValidatorEnricher, "secrets/hashicorpvaulttokenvalidate"), 106 fromVelesWithCfg(hashicorp.NewAppRoleValidatorEnricher, "secrets/hashicorpvaultapprolevalidate"), 107 fromVeles(hcp.NewClientCredentialsValidator(), "secrets/hcpclientcredentialsvalidate", 0), 108 fromVeles(hcp.NewAccessTokenValidator(), "secrets/hcpaccesstokenvalidate", 0), 109 fromVeles(huggingfaceapikey.NewValidator(), "secrets/huggingfaceapikeyvalidate", 0), 110 fromVeles(openai.NewProjectValidator(), "secrets/openaivalidate", 0), 111 fromVeles(perplexityapikey.NewValidator(), "secrets/perplexityapikeyvalidate", 0), 112 fromVeles(postmanapikey.NewAPIValidator(), "secrets/postmanapikeyvalidate", 0), 113 fromVeles(postmanapikey.NewCollectionValidator(), "secrets/postmancollectiontokenvalidate", 0), 114 fromVeles(github.NewAppS2STokenValidator(), "secrets/githubapps2stokenvalidate", 0), 115 fromVeles(github.NewAppU2STokenValidator(), "secrets/githubappu2stokenvalidate", 0), 116 fromVeles(github.NewOAuthTokenValidator(), "secrets/githuboauthtokenvalidate", 0), 117 fromVeles(github.NewClassicPATValidator(), "secrets/githubclassicpatvalidate", 0), 118 fromVeles(github.NewFineGrainedPATValidator(), "secrets/githubfinegrainedpatvalidate", 0), 119 fromVeles(stripeapikeys.NewSecretKeyValidator(), "secrets/stripesecretkeyvalidate", 0), 120 fromVeles(stripeapikeys.NewRestrictedKeyValidator(), "secrets/striperestrictedkeyvalidate", 0), 121 fromVeles(gcpoauth2access.NewValidator(), "secrets/gcpoauth2accesstokenvalidate", 0), 122 fromVeles(gcshmackey.NewValidator(), "secrets/gcshmackeyvalidate", 0), 123 fromVeles(awsaccesskey.NewValidator(), "secrets/awsaccesskeyvalidate", 0), 124 fromVeles(codecatalyst.NewValidator(), "secrets/codecatalystcredentialsvalidate", 0), 125 }) 126 127 // SecretsEnrich lists enrichers that add data to detected secrets. 128 SecretsEnrich = InitMap{ 129 hcpidentity.Name: {noCFG(hcpidentity.New)}, 130 } 131 132 // HuggingfaceMeta enricher. 133 HuggingfaceMeta = InitMap{ 134 huggingfacemeta.Name: {noCFG(huggingfacemeta.New)}, 135 } 136 137 // Reachability enrichers. 138 Reachability = InitMap{ 139 java.Name: {noCFG(java.NewDefault)}, 140 govcsource.Name: {govcsource.New}, 141 } 142 143 // TransitiveDependency enrichers. 144 TransitiveDependency = InitMap{ 145 requirements.Name: {requirements.New}, 146 } 147 148 // PackageDeprecation enricher. 149 PackageDeprecation = InitMap{ 150 packagedeprecation.Name: {noCFG(packagedeprecation.New)}, 151 } 152 153 // Default enrichers. 154 Default = concat() 155 156 // All enrichers. 157 All = concat( 158 LayerDetails, 159 VulnMatching, 160 VEX, 161 SecretsValidate, 162 SecretsEnrich, 163 HuggingfaceMeta, 164 License, 165 Reachability, 166 TransitiveDependency, 167 PackageDeprecation, 168 ) 169 170 enricherNames = concat(All, InitMap{ 171 "license": vals(License), 172 "vex": vals(VEX), 173 "vulnmatch": vals(VulnMatching), 174 "layerdetails": vals(LayerDetails), 175 "secretsvalidate": vals(SecretsValidate), 176 "secretsenrich": vals(SecretsEnrich), 177 "reachability": vals(Reachability), 178 "transitivedependency": vals(TransitiveDependency), 179 "packagedeprecation": vals(PackageDeprecation), 180 181 "enrichers/default": vals(Default), 182 "default": vals(Default), 183 "enrichers/all": vals(All), 184 "all": vals(All), 185 }) 186 ) 187 188 func concat(initMaps ...InitMap) InitMap { 189 result := InitMap{} 190 for _, m := range initMaps { 191 maps.Copy(result, m) 192 } 193 return result 194 } 195 196 func vals(initMap InitMap) []InitFn { 197 return slices.Concat(slices.AppendSeq(make([][]InitFn, 0, len(initMap)), maps.Values(initMap))...) 198 } 199 200 // Wraps initer functions that don't take any config value to initer functions that do. 201 // TODO(b/400910349): Remove once all plugins take config values. 202 func noCFG(f func() enricher.Enricher) InitFn { 203 return func(_ *cpb.PluginConfig) enricher.Enricher { return f() } 204 } 205 206 // EnricherFromName returns a single enricher based on its exact name. 207 func EnricherFromName(name string, cfg *cpb.PluginConfig) (enricher.Enricher, error) { 208 initers, ok := enricherNames[name] 209 if !ok { 210 return nil, fmt.Errorf("unknown enricher %q", name) 211 } 212 if len(initers) != 1 { 213 return nil, fmt.Errorf("not an exact name for an enricher: %s", name) 214 } 215 e := initers[0](cfg) 216 if e.Name() != name { 217 return nil, fmt.Errorf("not an exact name for an enricher: %s", name) 218 } 219 return e, nil 220 } 221 222 // EnrichersFromName returns a list of enrichers from a name. 223 func EnrichersFromName(name string, cfg *cpb.PluginConfig) ([]enricher.Enricher, error) { 224 if initers, ok := enricherNames[name]; ok { 225 var result []enricher.Enricher 226 for _, initer := range initers { 227 result = append(result, initer(cfg)) 228 } 229 return result, nil 230 } 231 return nil, fmt.Errorf("unknown enricher %q", name) 232 } 233 234 type velesPlugin struct { 235 initFunc InitFn 236 name string 237 } 238 239 func fromVeles[S veles.Secret](validator veles.Validator[S], name string, version int) velesPlugin { 240 return velesPlugin{ 241 initFunc: noCFG(convert.FromVelesValidator(validator, name, version)), 242 name: name, 243 } 244 } 245 246 func fromVelesWithCfg(initFunc InitFn, name string) velesPlugin { 247 return velesPlugin{ 248 initFunc: initFunc, 249 name: name, 250 } 251 } 252 253 func initMapFromVelesPlugins(plugins []velesPlugin) InitMap { 254 result := InitMap{} 255 for _, p := range plugins { 256 result[p.name] = []InitFn{p.initFunc} 257 } 258 return result 259 }