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  }