Skip to content
This repository has been archived by the owner on Oct 14, 2024. It is now read-only.

Commit

Permalink
feat: add scanner config options (#1928)
Browse files Browse the repository at this point in the history
  • Loading branch information
ramizpolic authored Jul 17, 2024
1 parent b913ab1 commit a5cbdda
Show file tree
Hide file tree
Showing 4 changed files with 315 additions and 31 deletions.
12 changes: 12 additions & 0 deletions scanner/common/input.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,18 @@ func (s InputType) GetSource(localImage bool) string {
}
}

// IsOnFilesystem returns true if the InputType can be found on the filesystem.
func (s InputType) IsOnFilesystem() bool {
switch s {
case IMAGE:
return false
case ROOTFS, DIR, DOCKERARCHIVE, OCIARCHIVE, OCIDIR, FILE, SBOM, CSV:
fallthrough
default:
return true
}
}

// IsOneOf returns true if one of provided input types matches the actual type.
func (s InputType) IsOneOf(types ...InputType) bool {
for _, typ := range types {
Expand Down
192 changes: 168 additions & 24 deletions scanner/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,13 @@
package scanner

import (
"path/filepath"

"gopkg.in/yaml.v3"

"github.com/openclarity/vmclarity/core/to"
"github.com/openclarity/vmclarity/scanner/common"
"github.com/openclarity/vmclarity/scanner/families"
exploittypes "github.com/openclarity/vmclarity/scanner/families/exploits/types"
infofindertypes "github.com/openclarity/vmclarity/scanner/families/infofinder/types"
malwaretypes "github.com/openclarity/vmclarity/scanner/families/malware/types"
Expand All @@ -29,6 +34,8 @@ import (
vulnerabilitytypes "github.com/openclarity/vmclarity/scanner/families/vulnerabilities/types"
)

type ConfigOption func(*Config)

type Config struct {
// Analyzers
SBOM sbomtypes.Config `json:"sbom" yaml:"sbom" mapstructure:"sbom"`
Expand All @@ -48,25 +55,11 @@ type Config struct {
Plugins plugintypes.Config `json:"plugins" yaml:"plugins" mapstructure:"plugins"`
}

func NewConfig() *Config {
return &Config{
SBOM: sbomtypes.Config{},
Vulnerabilities: vulnerabilitytypes.Config{},
Secrets: secrettypes.Config{},
Rootkits: rootkittypes.Config{},
Malware: malwaretypes.Config{},
Misconfiguration: misconfigurationtypes.Config{},
InfoFinder: infofindertypes.Config{},
Exploits: exploittypes.Config{},
Plugins: plugintypes.Config{},
}
}

func (c *Config) AddInputs(inputType common.InputType, inputs []string) {
for _, mountDir := range inputs {
for _, input := range inputs {
if c.SBOM.Enabled {
c.SBOM.Inputs = append(c.SBOM.Inputs, common.ScanInput{
Input: mountDir,
Input: input,
InputType: inputType,
})
}
Expand All @@ -76,7 +69,7 @@ func (c *Config) AddInputs(inputType common.InputType, inputs []string) {
c.Vulnerabilities.InputFromSbom = true
} else {
c.Vulnerabilities.Inputs = append(c.Vulnerabilities.Inputs, common.ScanInput{
Input: mountDir,
Input: input,
InputType: inputType,
})
}
Expand All @@ -85,56 +78,207 @@ func (c *Config) AddInputs(inputType common.InputType, inputs []string) {
if c.Secrets.Enabled {
c.Secrets.Inputs = append(c.Secrets.Inputs, common.ScanInput{
StripPathFromResult: to.Ptr(true),
Input: mountDir,
Input: input,
InputType: inputType,
})
}

if c.Exploits.Enabled {
c.Exploits.Inputs = append(c.Exploits.Inputs, common.ScanInput{
StripPathFromResult: to.Ptr(true),
Input: mountDir,
Input: input,
InputType: inputType,
})
}

if c.Misconfiguration.Enabled {
c.Misconfiguration.Inputs = append(c.Misconfiguration.Inputs, common.ScanInput{
StripPathFromResult: to.Ptr(true),
Input: mountDir,
Input: input,
InputType: inputType,
})
}

if c.InfoFinder.Enabled {
c.InfoFinder.Inputs = append(c.InfoFinder.Inputs, common.ScanInput{
StripPathFromResult: to.Ptr(true),
Input: mountDir,
Input: input,
InputType: inputType,
})
}

if c.Malware.Enabled {
c.Malware.Inputs = append(c.Malware.Inputs, common.ScanInput{
StripPathFromResult: to.Ptr(true),
Input: mountDir,
Input: input,
InputType: inputType,
})
}

if c.Rootkits.Enabled {
c.Rootkits.Inputs = append(c.Rootkits.Inputs, common.ScanInput{
StripPathFromResult: to.Ptr(true),
Input: mountDir,
Input: input,
InputType: inputType,
})
}

if c.Plugins.Enabled {
c.Plugins.Inputs = append(c.Plugins.Inputs, common.ScanInput{
Input: mountDir,
Input: input,
InputType: inputType,
})
}
}
}

func (c *Config) GetFamilyInputs(family families.FamilyType) []common.ScanInput {
switch family {
case families.SBOM:
return c.SBOM.Inputs
case families.Vulnerabilities:
return c.Vulnerabilities.Inputs
case families.Secrets:
return c.Secrets.Inputs
case families.Rootkits:
return c.Rootkits.Inputs
case families.Malware:
return c.Malware.Inputs
case families.Misconfiguration:
return c.Misconfiguration.Inputs
case families.InfoFinder:
return c.InfoFinder.Inputs
case families.Exploits:
return c.Exploits.Inputs
case families.Plugins:
return c.Plugins.Inputs
default:
return nil
}
}

func (c *Config) SetFamilyInputs(family families.FamilyType, inputs []common.ScanInput) {
switch family {
case families.SBOM:
c.SBOM.Inputs = inputs
case families.Vulnerabilities:
c.Vulnerabilities.Inputs = inputs
case families.Secrets:
c.Secrets.Inputs = inputs
case families.Rootkits:
c.Rootkits.Inputs = inputs
case families.Malware:
c.Malware.Inputs = inputs
case families.Misconfiguration:
c.Misconfiguration.Inputs = inputs
case families.InfoFinder:
c.InfoFinder.Inputs = inputs
case families.Exploits:
c.Exploits.Inputs = inputs
case families.Plugins:
c.Plugins.Inputs = inputs
default:
}
}

func NewConfig(opts ...ConfigOption) *Config {
config := &Config{
SBOM: sbomtypes.Config{},
Vulnerabilities: vulnerabilitytypes.Config{},
Secrets: secrettypes.Config{},
Rootkits: rootkittypes.Config{},
Malware: malwaretypes.Config{},
Misconfiguration: misconfigurationtypes.Config{},
InfoFinder: infofindertypes.Config{},
Exploits: exploittypes.Config{},
Plugins: plugintypes.Config{},
}

for _, opt := range opts {
opt(config)
}

return config
}

// WithBaseConfig uses provided config to construct a new Config. It is used when
// trying to apply custom options to an existing Config.
//
// WithBaseConfig should only be used as an argument to NewConfig.
func WithBaseConfig(base Config) ConfigOption {
return func(config *Config) {
data, _ := yaml.Marshal(base)

var cloned Config
_ = yaml.Unmarshal(data, &cloned)

*config = cloned
}
}

// WithInputsMountOverride replaces filesystem inputs for all families with the
// same inputs but for given mount points. Inputs will be duplicated for every
// mount point using the mount point as the input path prefix.
//
// WithInputsMountOverride can only be used after WithBaseConfig and should only
// be used as an argument to NewConfig.
func WithInputsMountOverride(mountpoints ...string) ConfigOption {
// Define input replacer function
replacerFn := func(input common.ScanInput) []common.ScanInput {
// If the input type cannot be found on the filesystem, return it without changes
if !input.InputType.IsOnFilesystem() {
return []common.ScanInput{input}
}

// If the input type can be found on the filesystem, expand it to mounted inputs
// for all mount points
var replacedInputs []common.ScanInput
for _, mountpoint := range mountpoints {
replacedInputs = append(replacedInputs, common.ScanInput{
StripPathFromResult: input.StripPathFromResult,
Input: filepath.Join(mountpoint, input.Input),
InputType: input.InputType,
})
}

return replacedInputs
}

// Return function that applies replacer to all families
return func(config *Config) {
for _, opt := range []ConfigOption{
WithFamilyInputsReplacer(families.SBOM, replacerFn),
WithFamilyInputsReplacer(families.Vulnerabilities, replacerFn),
WithFamilyInputsReplacer(families.Secrets, replacerFn),
WithFamilyInputsReplacer(families.Rootkits, replacerFn),
WithFamilyInputsReplacer(families.Malware, replacerFn),
WithFamilyInputsReplacer(families.Misconfiguration, replacerFn),
WithFamilyInputsReplacer(families.InfoFinder, replacerFn),
WithFamilyInputsReplacer(families.Exploits, replacerFn),
WithFamilyInputsReplacer(families.Plugins, replacerFn),
} {
opt(config)
}
}
}

// WithFamilyInputsReplacer replaces specific family inputs using custom replacer
// function.
//
// WithFamilyInputsReplacer can only be used after WithBaseConfig and should only
// be used as an argument to NewConfig.
func WithFamilyInputsReplacer(family families.FamilyType, replacerFn func(common.ScanInput) []common.ScanInput) ConfigOption {
return func(config *Config) {
// Get the current inputs for the specified family
currentInputs := config.GetFamilyInputs(family)

// Apply the replacer function to each input
var updatedInputs []common.ScanInput
for _, input := range currentInputs {
updatedInputs = append(updatedInputs, replacerFn(input)...)
}

// Set the updated inputs for the specified family
config.SetFamilyInputs(family, updatedInputs)
}
}
Loading

0 comments on commit a5cbdda

Please sign in to comment.