github.com/devseccon/trivy@v0.47.1-0.20231123133102-bd902a0bd996/pkg/fanal/analyzer/config_analyzer.go (about) 1 package analyzer 2 3 import ( 4 "context" 5 6 v1 "github.com/google/go-containerregistry/pkg/v1" 7 "golang.org/x/exp/slices" 8 "golang.org/x/xerrors" 9 10 "github.com/devseccon/trivy/pkg/fanal/types" 11 "github.com/devseccon/trivy/pkg/log" 12 "github.com/devseccon/trivy/pkg/misconf" 13 ) 14 15 var configAnalyzerConstructors = make(map[Type]configAnalyzerConstructor) 16 17 type configAnalyzerConstructor func(ConfigAnalyzerOptions) (ConfigAnalyzer, error) 18 19 // RegisterConfigAnalyzer adds a constructor of config analyzer 20 func RegisterConfigAnalyzer(t Type, init configAnalyzerConstructor) { 21 configAnalyzerConstructors[t] = init 22 } 23 24 // DeregisterConfigAnalyzer is mainly for testing 25 func DeregisterConfigAnalyzer(t Type) { 26 delete(configAnalyzerConstructors, t) 27 } 28 29 // ConfigAnalyzer defines an interface for analyzer of container image config 30 type ConfigAnalyzer interface { 31 Type() Type 32 Version() int 33 Analyze(ctx context.Context, input ConfigAnalysisInput) (*ConfigAnalysisResult, error) 34 Required(osFound types.OS) bool 35 } 36 37 // ConfigAnalyzerOptions is used to initialize config analyzers 38 type ConfigAnalyzerOptions struct { 39 FilePatterns []string 40 DisabledAnalyzers []Type 41 MisconfScannerOption misconf.ScannerOption 42 SecretScannerOption SecretScannerOption 43 } 44 45 type ConfigAnalysisInput struct { 46 OS types.OS 47 Config *v1.ConfigFile 48 } 49 50 type ConfigAnalysisResult struct { 51 Misconfiguration *types.Misconfiguration 52 Secret *types.Secret 53 HistoryPackages types.Packages 54 } 55 56 func (r *ConfigAnalysisResult) Merge(newResult *ConfigAnalysisResult) { 57 if newResult == nil { 58 return 59 } 60 if newResult.Misconfiguration != nil { 61 r.Misconfiguration = newResult.Misconfiguration 62 } 63 if newResult.Secret != nil { 64 r.Secret = newResult.Secret 65 } 66 if newResult.HistoryPackages != nil { 67 r.HistoryPackages = newResult.HistoryPackages 68 } 69 } 70 71 type ConfigAnalyzerGroup struct { 72 configAnalyzers []ConfigAnalyzer 73 } 74 75 func NewConfigAnalyzerGroup(opts ConfigAnalyzerOptions) (ConfigAnalyzerGroup, error) { 76 var g ConfigAnalyzerGroup 77 for t, newConfigAnalyzer := range configAnalyzerConstructors { 78 // Skip the handler if it is disabled 79 if slices.Contains(opts.DisabledAnalyzers, t) { 80 continue 81 } 82 a, err := newConfigAnalyzer(opts) 83 if err != nil { 84 return ConfigAnalyzerGroup{}, xerrors.Errorf("config analyzer %s initialize error: %w", t, err) 85 } 86 87 g.configAnalyzers = append(g.configAnalyzers, a) 88 } 89 90 return g, nil 91 } 92 93 // AnalyzerVersions returns analyzer version identifier used for cache keys. 94 func (ag *ConfigAnalyzerGroup) AnalyzerVersions() Versions { 95 versions := make(map[string]int) 96 for _, ca := range ag.configAnalyzers { 97 versions[string(ca.Type())] = ca.Version() 98 } 99 return Versions{ 100 Analyzers: versions, 101 } 102 } 103 104 func (ag *ConfigAnalyzerGroup) AnalyzeImageConfig(ctx context.Context, targetOS types.OS, config *v1.ConfigFile) *ConfigAnalysisResult { 105 input := ConfigAnalysisInput{ 106 OS: targetOS, 107 Config: config, 108 } 109 result := new(ConfigAnalysisResult) 110 for _, a := range ag.configAnalyzers { 111 if !a.Required(targetOS) { 112 continue 113 } 114 115 r, err := a.Analyze(ctx, input) 116 if err != nil { 117 log.Logger.Debugf("Image config analysis error: %s", err) 118 continue 119 } 120 121 result.Merge(r) 122 } 123 return result 124 }