Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 23 additions & 13 deletions annotator/list/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,38 +31,48 @@ import (
"github.com/google/osv-scalibr/annotator/osduplicate/cos"
"github.com/google/osv-scalibr/annotator/osduplicate/dpkg"
"github.com/google/osv-scalibr/annotator/osduplicate/rpm"
"github.com/google/osv-scalibr/plugin/config"

cpb "github.com/google/osv-scalibr/binary/proto/config_go_proto"
)

// InitFn is the annotator initializer function.
type InitFn func(cfg *cpb.PluginConfig) (annotator.Annotator, error)
type InitFn func(cfg *config.PluginConfig) (annotator.Annotator, error)

func protoCfg(f func(cfg *cpb.PluginConfig) (annotator.Annotator, error)) InitFn {
return func(cfg *config.PluginConfig) (annotator.Annotator, error) {
if cfg == nil || cfg.ProtoConfig == nil {
return f(&cpb.PluginConfig{})
}
return f(cfg.ProtoConfig)
}
}

// InitMap is a map of annotator names to their initers.
type InitMap map[string][]InitFn

// VEX generation related annotators.
var VEX = InitMap{
apk.Name: {apk.New},
cachedir.Name: {cachedir.New},
cos.Name: {cos.New},
dpkg.Name: {dpkg.New},
rpm.Name: {rpm.New},
noexecutabledpkg.Name: {noexecutabledpkg.New},
apk.Name: {protoCfg(apk.New)},
cachedir.Name: {protoCfg(cachedir.New)},
cos.Name: {protoCfg(cos.New)},
dpkg.Name: {protoCfg(dpkg.New)},
rpm.Name: {protoCfg(rpm.New)},
noexecutabledpkg.Name: {protoCfg(noexecutabledpkg.New)},
}

// Misc annotators.
var Misc = InitMap{
npmsource.Name: {npmsource.New},
dpkgsource.Name: {dpkgsource.New},
brewsource.Name: {brewsource.New},
npmsource.Name: {protoCfg(npmsource.New)},
dpkgsource.Name: {protoCfg(dpkgsource.New)},
brewsource.Name: {protoCfg(brewsource.New)},
}

// FFA (Full Filesystem Accountability) related annotators.
var FFA = InitMap{unknownbinariesanno.Name: {unknownbinariesanno.New}}
var FFA = InitMap{unknownbinariesanno.Name: {protoCfg(unknownbinariesanno.New)}}

// Default detectors that are recommended to be enabled.
var Default = InitMap{cachedir.Name: {cachedir.New}}
var Default = InitMap{cachedir.Name: {protoCfg(cachedir.New)}}

// All annotators.
var All = concat(
Expand Down Expand Up @@ -94,7 +104,7 @@ func vals(initMap InitMap) []InitFn {
}

// AnnotatorsFromName returns a list of annotators from a name.
func AnnotatorsFromName(name string, cfg *cpb.PluginConfig) ([]annotator.Annotator, error) {
func AnnotatorsFromName(name string, cfg *config.PluginConfig) ([]annotator.Annotator, error) {
if initers, ok := annotatorNames[name]; ok {
result := []annotator.Annotator{}
for _, initer := range initers {
Expand Down
4 changes: 2 additions & 2 deletions annotator/list/list_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import (
"testing"

al "github.com/google/osv-scalibr/annotator/list"
cpb "github.com/google/osv-scalibr/binary/proto/config_go_proto"
"github.com/google/osv-scalibr/plugin/config"
)

var (
Expand All @@ -29,7 +29,7 @@ var (
func TestPluginNamesValid(t *testing.T) {
for _, initers := range al.All {
for _, initer := range initers {
p, err := initer(&cpb.PluginConfig{})
p, err := initer(config.DefaultPluginConfig())
if err != nil {
t.Fatalf("initer(): %v", err)
}
Expand Down
15 changes: 9 additions & 6 deletions binary/cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import (
"google.golang.org/protobuf/encoding/prototext"

cpb "github.com/google/osv-scalibr/binary/proto/config_go_proto"
"github.com/google/osv-scalibr/plugin/config"
)

// Array is a type to be passed to flag.Var that supports arrays passed as repeated flags,
Expand Down Expand Up @@ -319,7 +320,7 @@ func validateGlob(arg string) error {

func validateDependency(pluginNames []string, requireExtractors bool) error {
f := &Flags{PluginsToRun: pluginNames}
plugins, _, err := f.pluginsToRun()
plugins, _, err := f.resolvePluginsAndConfig()
if err != nil {
return err
}
Expand Down Expand Up @@ -356,7 +357,7 @@ type extractorOverride struct {

// GetScanConfig constructs a SCALIBR scan config from the provided CLI flags.
func (f *Flags) GetScanConfig() (*scalibr.ScanConfig, error) {
plugins, pluginCFG, err := f.pluginsToRun()
plugins, pluginCFG, err := f.resolvePluginsAndConfig()
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -526,13 +527,15 @@ func (f *Flags) WriteScanResults(result *scalibr.ScanResult) error {
}

// TODO(b/279413691): Allow commas in argument names.
func (f *Flags) pluginsToRun() ([]plugin.Plugin, *cpb.PluginConfig, error) {
func (f *Flags) resolvePluginsAndConfig() ([]plugin.Plugin, *config.PluginConfig, error) {
result := make([]plugin.Plugin, 0, len(f.PluginsToRun))
pluginNames := multiStringToList(f.PluginsToRun)
pluginCFG, err := pluginCFGFromFlags(f.PluginCFG)
protoCFG, err := pluginProtoCFGFromFlags(f.PluginCFG)
if err != nil {
return nil, nil, err
}
pluginCFG := config.DefaultPluginConfig()
pluginCFG.ProtoConfig = protoCFG

extractorNames := addPluginPrefixToGroups("extractors/", multiStringToList(f.ExtractorsToRun))
detectorNames := addPluginPrefixToGroups("detectors/", multiStringToList(f.DetectorsToRun))
Expand Down Expand Up @@ -570,9 +573,9 @@ func addPluginPrefixToGroups(prefix string, pluginNames []string) []string {
return result
}

// pluginCFGFromFlags parses individually provided
// pluginProtoCFGFromFlags parses individually provided
// plugin config strings into one proto.
func pluginCFGFromFlags(flags []string) (*cpb.PluginConfig, error) {
func pluginProtoCFGFromFlags(flags []string) (*cpb.PluginConfig, error) {
var cfgString strings.Builder
for _, flag := range flags {
pluginCFG := &cpb.PluginConfig{}
Expand Down
39 changes: 24 additions & 15 deletions binary/cli/cli_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"github.com/google/osv-scalibr/binary/cli"
"github.com/google/osv-scalibr/extractor/filesystem/language/golang/gobinary"
"github.com/google/osv-scalibr/plugin"
"github.com/google/osv-scalibr/plugin/config"
"google.golang.org/protobuf/testing/protocmp"

cpb "github.com/google/osv-scalibr/binary/proto/config_go_proto"
Expand Down Expand Up @@ -580,25 +581,29 @@ func TestGetScanConfig_PluginConfig(t *testing.T) {
for _, tc := range []struct {
desc string
cfgFlags []string
wantCFG *cpb.PluginConfig
wantCFG *config.PluginConfig
wantMaxFileSizeBytes int64
wantVersionFromContent bool
}{
{
desc: "single_setting_in_one_flag",
cfgFlags: []string{"max_file_size_bytes:1234"},
wantCFG: &cpb.PluginConfig{
MaxFileSizeBytes: 1234,
wantCFG: &config.PluginConfig{
ProtoConfig: &cpb.PluginConfig{
MaxFileSizeBytes: 1234,
},
},
wantMaxFileSizeBytes: 1234,
},
{
desc: "multiple_settings_in_one_flag",
cfgFlags: []string{"max_file_size_bytes:1234 plugin_specific:{go_binary:{version_from_content:true}}"},
wantCFG: &cpb.PluginConfig{
MaxFileSizeBytes: 1234,
PluginSpecific: []*cpb.PluginSpecificConfig{
{Config: &cpb.PluginSpecificConfig_GoBinary{GoBinary: &cpb.GoBinaryConfig{VersionFromContent: true}}},
wantCFG: &config.PluginConfig{
ProtoConfig: &cpb.PluginConfig{
MaxFileSizeBytes: 1234,
PluginSpecific: []*cpb.PluginSpecificConfig{
{Config: &cpb.PluginSpecificConfig_GoBinary{GoBinary: &cpb.GoBinaryConfig{VersionFromContent: true}}},
},
},
},
wantMaxFileSizeBytes: 1234,
Expand All @@ -610,10 +615,12 @@ func TestGetScanConfig_PluginConfig(t *testing.T) {
"max_file_size_bytes:1234",
"plugin_specific:{go_binary:{version_from_content:true}}",
},
wantCFG: &cpb.PluginConfig{
MaxFileSizeBytes: 1234,
PluginSpecific: []*cpb.PluginSpecificConfig{
{Config: &cpb.PluginSpecificConfig_GoBinary{GoBinary: &cpb.GoBinaryConfig{VersionFromContent: true}}},
wantCFG: &config.PluginConfig{
ProtoConfig: &cpb.PluginConfig{
MaxFileSizeBytes: 1234,
PluginSpecific: []*cpb.PluginSpecificConfig{
{Config: &cpb.PluginSpecificConfig_GoBinary{GoBinary: &cpb.GoBinaryConfig{VersionFromContent: true}}},
},
},
},
wantMaxFileSizeBytes: 1234,
Expand All @@ -622,9 +629,11 @@ func TestGetScanConfig_PluginConfig(t *testing.T) {
{
desc: "plugin_specific_config_short_version",
cfgFlags: []string{"go_binary:{version_from_content:true}"},
wantCFG: &cpb.PluginConfig{
PluginSpecific: []*cpb.PluginSpecificConfig{
{Config: &cpb.PluginSpecificConfig_GoBinary{GoBinary: &cpb.GoBinaryConfig{VersionFromContent: true}}},
wantCFG: &config.PluginConfig{
ProtoConfig: &cpb.PluginConfig{
PluginSpecific: []*cpb.PluginSpecificConfig{
{Config: &cpb.PluginSpecificConfig_GoBinary{GoBinary: &cpb.GoBinaryConfig{VersionFromContent: true}}},
},
},
},
wantVersionFromContent: true,
Expand All @@ -641,7 +650,7 @@ func TestGetScanConfig_PluginConfig(t *testing.T) {
t.Errorf("%v.GetScanConfig(): %v", flags, err)
}

if diff := cmp.Diff(tc.wantCFG, scanConfig.RequiredPluginConfig, protocmp.Transform()); diff != "" {
if diff := cmp.Diff(tc.wantCFG.ProtoConfig, scanConfig.RequiredPluginConfig.ProtoConfig, protocmp.Transform()); diff != "" {
t.Errorf("%v.GetScanConfig() ScanRoots got diff (-want +got):\n%s", flags, diff)
}
if len(scanConfig.Plugins) != 1 {
Expand Down
10 changes: 10 additions & 0 deletions clients/datasource/insights.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,16 @@ func NewCachedInsightsClient(addr string, userAgent string) (*CachedInsightsClie
}, nil
}

// NewCachedInsightsClientWithConn creates a CachedInsightsClient with a provided connection.
func NewCachedInsightsClientWithConn(conn grpc.ClientConnInterface) *CachedInsightsClient {
return &CachedInsightsClient{
InsightsClient: pb.NewInsightsClient(conn),
packageCache: NewRequestCache[packageKey, *pb.Package](),
versionCache: NewRequestCache[versionKey, *pb.Version](),
requirementsCache: NewRequestCache[versionKey, *pb.Requirements](),
}
}

// GetPackage returns metadata about a package by querying deps.dev API.
func (c *CachedInsightsClient) GetPackage(ctx context.Context, in *pb.GetPackageRequest, opts ...grpc.CallOption) (*pb.Package, error) {
return c.packageCache.Get(makePackageKey(in.GetPackageKey()), func() (*pb.Package, error) {
Expand Down
50 changes: 30 additions & 20 deletions detector/list/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,70 +39,80 @@ import (
"github.com/google/osv-scalibr/detector/weakcredentials/etcshadow"
"github.com/google/osv-scalibr/detector/weakcredentials/filebrowser"
"github.com/google/osv-scalibr/detector/weakcredentials/winlocal"
"github.com/google/osv-scalibr/plugin/config"

cpb "github.com/google/osv-scalibr/binary/proto/config_go_proto"
)

// InitFn is the detector initializer function.
type InitFn func(cfg *cpb.PluginConfig) (detector.Detector, error)
type InitFn func(cfg *config.PluginConfig) (detector.Detector, error)

func protoCfg(f func(cfg *cpb.PluginConfig) (detector.Detector, error)) InitFn {
return func(cfg *config.PluginConfig) (detector.Detector, error) {
if cfg == nil || cfg.ProtoConfig == nil {
return f(&cpb.PluginConfig{})
}
return f(cfg.ProtoConfig)
}
}

// InitMap is a map of detector names to their initers.
type InitMap map[string][]InitFn

// CIS scanning related detectors.
var CIS = InitMap{
etcpasswdpermissions.Name: {etcpasswdpermissions.New},
etcpasswdpermissions.Name: {protoCfg(etcpasswdpermissions.New)},
}

// Govulncheck detectors.
var Govulncheck = InitMap{binary.Name: {binary.New}}
var Govulncheck = InitMap{binary.Name: {protoCfg(binary.New)}}

// EndOfLife detectors.
var EndOfLife = InitMap{linuxdistro.Name: {linuxdistro.New}}
var EndOfLife = InitMap{linuxdistro.Name: {protoCfg(linuxdistro.New)}}

// Untested CVE scanning related detectors - since they don't have proper testing they
// might not work as expected in the future.
// TODO(b/405223999): Add tests.
var Untested = InitMap{
// CVE-2023-38408 OpenSSH detector.
cve202338408.Name: {cve202338408.New},
cve202338408.Name: {protoCfg(cve202338408.New)},
// CVE-2022-33891 Spark UI detector.
cve202233891.Name: {cve202233891.New},
cve202233891.Name: {protoCfg(cve202233891.New)},
// CVE-2020-16846 Salt detector.
cve202016846.Name: {cve202016846.New},
cve202016846.Name: {protoCfg(cve202016846.New)},
// CVE-2023-6019 Ray Dashboard detector.
cve20236019.Name: {cve20236019.New},
cve20236019.Name: {protoCfg(cve20236019.New)},
// CVE-2020-11978 Apache Airflow detector.
cve202011978.Name: {cve202011978.New},
cve202011978.Name: {protoCfg(cve202011978.New)},
// CVE-2024-2912 BentoML detector.
cve20242912.Name: {cve20242912.New},
cve20242912.Name: {protoCfg(cve20242912.New)},
}

// Weakcredentials detectors for weak credentials.
var Weakcredentials = InitMap{
codeserver.Name: {codeserver.New},
etcshadow.Name: {etcshadow.New},
filebrowser.Name: {filebrowser.New},
winlocal.Name: {winlocal.New},
codeserver.Name: {protoCfg(codeserver.New)},
etcshadow.Name: {protoCfg(etcshadow.New)},
filebrowser.Name: {protoCfg(filebrowser.New)},
winlocal.Name: {protoCfg(winlocal.New)},
}

// Misc detectors for miscellaneous security issues.
var Misc = InitMap{
cronjobprivesc.Name: {cronjobprivesc.New},
dockersocket.Name: {dockersocket.New},
pammisconfig.Name: {pammisconfig.New},
cronjobprivesc.Name: {protoCfg(cronjobprivesc.New)},
dockersocket.Name: {protoCfg(dockersocket.New)},
pammisconfig.Name: {protoCfg(pammisconfig.New)},
}

// CVE for vulnerabilities that have a CVE associated
var CVE = InitMap{
// CVE-2025-7775 detector
cve20257775.Name: {cve20257775.New},
cve20257775.Name: {protoCfg(cve20257775.New)},
}

// SupplyChain related vulnerability detectors.
var SupplyChain = InitMap{
// Malicious NPM for CanisterWorm
canisterworm.Name: {canisterworm.New},
canisterworm.Name: {protoCfg(canisterworm.New)},
}

// Default detectors that are recommended to be enabled.
Expand Down Expand Up @@ -148,7 +158,7 @@ func vals(initMap InitMap) []InitFn {
}

// DetectorsFromName returns a list of detectors from a name.
func DetectorsFromName(name string, cfg *cpb.PluginConfig) ([]detector.Detector, error) {
func DetectorsFromName(name string, cfg *config.PluginConfig) ([]detector.Detector, error) {
if initers, ok := detectorNames[name]; ok {
result := []detector.Detector{}
for _, initer := range initers {
Expand Down
6 changes: 3 additions & 3 deletions detector/list/list_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ import (

"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
cpb "github.com/google/osv-scalibr/binary/proto/config_go_proto"
dl "github.com/google/osv-scalibr/detector/list"
"github.com/google/osv-scalibr/plugin/config"
)

var (
Expand All @@ -31,7 +31,7 @@ var (
func TestPluginNamesValid(t *testing.T) {
for _, initers := range dl.All {
for _, initer := range initers {
p, err := initer(&cpb.PluginConfig{})
p, err := initer(config.DefaultPluginConfig())
if err != nil {
t.Fatalf("initer(): %v", err)
}
Expand Down Expand Up @@ -85,7 +85,7 @@ func TestDetectorsFromName(t *testing.T) {

for _, tc := range testCases {
t.Run(tc.desc, func(t *testing.T) {
got, err := dl.DetectorsFromName(tc.name, &cpb.PluginConfig{})
got, err := dl.DetectorsFromName(tc.name, config.DefaultPluginConfig())
if diff := cmp.Diff(tc.wantErr, err, cmpopts.EquateErrors()); diff != "" {
t.Errorf("dl.DetectorsFromName(%v) error got diff (-want +got):\n%s", tc.name, diff)
}
Expand Down
Loading
Loading