From c37356d2a1869ceadb81fd6d3e69c32b8340be26 Mon Sep 17 00:00:00 2001 From: knqyf263 Date: Tue, 6 Sep 2022 14:40:40 +0300 Subject: [PATCH 1/6] bump xerrors --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index aed2118ab46..6cbb210ef48 100644 --- a/go.mod +++ b/go.mod @@ -64,7 +64,7 @@ require ( go.etcd.io/bbolt v1.3.6 go.uber.org/zap v1.22.0 golang.org/x/exp v0.0.0-20220407100705-7b9b53b0aca4 - golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df + golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f google.golang.org/protobuf v1.28.1 gopkg.in/yaml.v3 v3.0.1 k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 diff --git a/go.sum b/go.sum index ac103fe7ae7..43e9063f5d2 100644 --- a/go.sum +++ b/go.sum @@ -2138,6 +2138,8 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df h1:5Pf6pFKu98ODmgnpvkJ3kFUOQGGLIzLIkbzUHp47618= golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f h1:uF6paiQQebLeSXkrTqHqz0MXhXXS1KgF41eUdBNvxK0= +golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= gonum.org/v1/gonum v0.7.0 h1:Hdks0L0hgznZLG9nzXb8vZ0rRvqNvAcgAp84y7Mwkgw= gonum.org/v1/gonum v0.7.0/go.mod h1:L02bwd0sqlsvRv41G7wGWFCsVNZFv/k1xzGIxeANHGM= From ced76621866cc24a2ec8f9bdc3c4e65d9586f089 Mon Sep 17 00:00:00 2001 From: knqyf263 Date: Tue, 6 Sep 2022 15:01:33 +0300 Subject: [PATCH 2/6] Add a new interface for initializing analyzers Signed-off-by: knqyf263 --- pkg/commands/artifact/run.go | 3 +- pkg/fanal/analyzer/all/import.go | 1 - pkg/fanal/analyzer/analyzer.go | 64 +++++++++++++++++++----- pkg/fanal/analyzer/analyzer_test.go | 18 +++++-- pkg/fanal/analyzer/secret/secret.go | 47 ++++++++++------- pkg/fanal/analyzer/secret/secret_test.go | 11 ++-- pkg/fanal/artifact/artifact.go | 3 +- pkg/fanal/artifact/image/image.go | 50 +++++++++--------- pkg/fanal/artifact/image/image_test.go | 1 + pkg/fanal/artifact/local/fs.go | 13 +++-- pkg/fanal/artifact/local/fs_test.go | 2 +- pkg/fanal/artifact/remote/git_test.go | 1 + pkg/fanal/secret/scanner.go | 43 +++++++++------- pkg/fanal/secret/scanner_test.go | 8 +-- pkg/module/module_test.go | 2 +- 15 files changed, 169 insertions(+), 98 deletions(-) diff --git a/pkg/commands/artifact/run.go b/pkg/commands/artifact/run.go index d27bb6222f3..5d1620927fd 100644 --- a/pkg/commands/artifact/run.go +++ b/pkg/commands/artifact/run.go @@ -16,7 +16,6 @@ import ( "github.com/aquasecurity/trivy/pkg/commands/operation" "github.com/aquasecurity/trivy/pkg/fanal/analyzer" "github.com/aquasecurity/trivy/pkg/fanal/analyzer/config" - "github.com/aquasecurity/trivy/pkg/fanal/analyzer/secret" "github.com/aquasecurity/trivy/pkg/fanal/artifact" "github.com/aquasecurity/trivy/pkg/fanal/cache" "github.com/aquasecurity/trivy/pkg/flag" @@ -516,7 +515,7 @@ func initScannerConfig(opts flag.Options, cacheClient cache.Cache) (ScannerConfi MisconfScannerOption: configScannerOptions, // For secret scanning - SecretScannerOption: secret.ScannerOption{ + SecretScannerOption: analyzer.SecretScannerOption{ ConfigPath: opts.SecretConfigPath, }, }, diff --git a/pkg/fanal/analyzer/all/import.go b/pkg/fanal/analyzer/all/import.go index f3009ee68ee..034d63cb506 100644 --- a/pkg/fanal/analyzer/all/import.go +++ b/pkg/fanal/analyzer/all/import.go @@ -36,5 +36,4 @@ import ( _ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/pkg/dpkg" _ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/pkg/rpm" _ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/repo/apk" - _ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/secret" ) diff --git a/pkg/fanal/analyzer/analyzer.go b/pkg/fanal/analyzer/analyzer.go index 02016b33634..5a1b3e58f24 100644 --- a/pkg/fanal/analyzer/analyzer.go +++ b/pkg/fanal/analyzer/analyzer.go @@ -32,17 +32,29 @@ var ( ErrNoPkgsDetected = xerrors.New("no packages detected") ) -type AnalysisInput struct { - Dir string - FilePath string - Info os.FileInfo - Content dio.ReadSeekerAt +////////////////////// +// Analyzer options // +////////////////////// + +// AnalyzerOptions is used to initialize analyzers +type AnalyzerOptions struct { + Group Group + FilePatterns []string + DisabledAnalyzers []Type + SecretScannerOption SecretScannerOption +} - Options AnalysisOptions +type SecretScannerOption struct { + ConfigPath string } -type AnalysisOptions struct { - Offline bool +//////////////// +// Interfaces // +//////////////// + +// Initializer represents analyzers that need to take parameters from users +type Initializer interface { + Init(AnalyzerOptions) error } type analyzer interface { @@ -59,6 +71,10 @@ type configAnalyzer interface { Required(osFound types.OS) bool } +//////////////////// +// Analyzer group // +//////////////////// + type Group string const GroupBuiltin Group = "builtin" @@ -95,6 +111,23 @@ type AnalyzerGroup struct { filePatterns map[Type][]*regexp.Regexp } +/////////////////////////// +// Analyzer input/output // +/////////////////////////// + +type AnalysisInput struct { + Dir string + FilePath string + Info os.FileInfo + Content dio.ReadSeekerAt + + Options AnalysisOptions +} + +type AnalysisOptions struct { + Offline bool +} + type AnalysisResult struct { m sync.Mutex OS *types.OS @@ -270,7 +303,8 @@ func belongToGroup(groupName Group, analyzerType Type, disabledAnalyzers []Type, const separator = ":" -func NewAnalyzerGroup(groupName Group, disabledAnalyzers []Type, filePatterns []string) (AnalyzerGroup, error) { +func NewAnalyzerGroup(opt AnalyzerOptions) (AnalyzerGroup, error) { + groupName := opt.Group if groupName == "" { groupName = GroupBuiltin } @@ -278,7 +312,7 @@ func NewAnalyzerGroup(groupName Group, disabledAnalyzers []Type, filePatterns [] group := AnalyzerGroup{ filePatterns: map[Type][]*regexp.Regexp{}, } - for _, p := range filePatterns { + for _, p := range opt.FilePatterns { // e.g. "dockerfile:my_dockerfile_*" s := strings.SplitN(p, separator, 2) if len(s) != 2 { @@ -299,14 +333,20 @@ func NewAnalyzerGroup(groupName Group, disabledAnalyzers []Type, filePatterns [] } for analyzerType, a := range analyzers { - if !belongToGroup(groupName, analyzerType, disabledAnalyzers, a) { + if !belongToGroup(groupName, analyzerType, opt.DisabledAnalyzers, a) { continue } + // Initialize only scanners that have Init() + if ini, ok := a.(Initializer); ok { + if err := ini.Init(opt); err != nil { + return AnalyzerGroup{}, xerrors.Errorf("analyzer initialization error: %w", err) + } + } group.analyzers = append(group.analyzers, a) } for analyzerType, a := range configAnalyzers { - if slices.Contains(disabledAnalyzers, analyzerType) { + if slices.Contains(opt.DisabledAnalyzers, analyzerType) { continue } group.configAnalyzers = append(group.configAnalyzers, a) diff --git a/pkg/fanal/analyzer/analyzer_test.go b/pkg/fanal/analyzer/analyzer_test.go index 92b7dd9346b..c4d98b74cde 100644 --- a/pkg/fanal/analyzer/analyzer_test.go +++ b/pkg/fanal/analyzer/analyzer_test.go @@ -441,7 +441,10 @@ func TestAnalyzeFile(t *testing.T) { limit := semaphore.NewWeighted(3) got := new(analyzer.AnalysisResult) - a, err := analyzer.NewAnalyzerGroup(analyzer.GroupBuiltin, tt.args.disabledAnalyzers, tt.args.filePatterns) + a, err := analyzer.NewAnalyzerGroup(analyzer.AnalyzerOptions{ + FilePatterns: tt.args.filePatterns, + DisabledAnalyzers: tt.args.disabledAnalyzers, + }) if err != nil && tt.wantErr != "" { require.NotNil(t, err) assert.Contains(t, err.Error(), tt.wantErr) @@ -530,7 +533,10 @@ func TestAnalyzeConfig(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - a, err := analyzer.NewAnalyzerGroup(analyzer.GroupBuiltin, tt.args.disabledAnalyzers, tt.args.filePatterns) + a, err := analyzer.NewAnalyzerGroup(analyzer.AnalyzerOptions{ + FilePatterns: tt.args.filePatterns, + DisabledAnalyzers: tt.args.disabledAnalyzers, + }) require.NoError(t, err) got := a.AnalyzeImageConfig(tt.args.targetOS, tt.args.configBlob) assert.Equal(t, tt.want, got) @@ -566,7 +572,9 @@ func TestAnalyzer_AnalyzerVersions(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - a, err := analyzer.NewAnalyzerGroup(analyzer.GroupBuiltin, tt.disabled, nil) + a, err := analyzer.NewAnalyzerGroup(analyzer.AnalyzerOptions{ + DisabledAnalyzers: tt.disabled, + }) require.NoError(t, err) got := a.AnalyzerVersions() fmt.Printf("%v\n", got) @@ -599,7 +607,9 @@ func TestAnalyzer_ImageConfigAnalyzerVersions(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - a, err := analyzer.NewAnalyzerGroup(analyzer.GroupBuiltin, tt.disabled, nil) + a, err := analyzer.NewAnalyzerGroup(analyzer.AnalyzerOptions{ + DisabledAnalyzers: tt.disabled, + }) require.NoError(t, err) got := a.ImageConfigAnalyzerVersions() assert.Equal(t, tt.want, got) diff --git a/pkg/fanal/analyzer/secret/secret.go b/pkg/fanal/analyzer/secret/secret.go index f8b3a0888fa..4e245ef8ca7 100644 --- a/pkg/fanal/analyzer/secret/secret.go +++ b/pkg/fanal/analyzer/secret/secret.go @@ -9,6 +9,7 @@ import ( "path/filepath" "strings" + "github.com/samber/lo" "golang.org/x/exp/slices" "golang.org/x/xerrors" @@ -18,6 +19,9 @@ import ( "github.com/aquasecurity/trivy/pkg/fanal/types" ) +// To make sure SecretAnalyzer implements analyzer.Initializer +var _ analyzer.Initializer = &SecretAnalyzer{} + const version = 1 var ( @@ -37,8 +41,9 @@ var ( } ) -type ScannerOption struct { - ConfigPath string +func init() { + // The scanner will be initialized later via InitScanner() + analyzer.RegisterAnalyzer(NewSecretAnalyzer(secret.Scanner{}, "")) } // SecretAnalyzer is an analyzer for secrets @@ -47,27 +52,31 @@ type SecretAnalyzer struct { configPath string } -func RegisterSecretAnalyzer(opt ScannerOption) error { - a, err := newSecretAnalyzer(opt.ConfigPath) - if err != nil { - return xerrors.Errorf("secret scanner init error: %w", err) +func NewSecretAnalyzer(s secret.Scanner, configPath string) *SecretAnalyzer { + return &SecretAnalyzer{ + scanner: s, + configPath: configPath, } - analyzer.RegisterAnalyzer(a) - return nil } -func newSecretAnalyzer(configPath string) (SecretAnalyzer, error) { - s, err := secret.NewScanner(configPath) +// Init initializes and sets a secret scanner +func (a *SecretAnalyzer) Init(opt analyzer.AnalyzerOptions) error { + if !lo.IsEmpty(a.scanner) { + // This check is for tools importing Trivy and customize analyzers + // Never reach here in Trivy OSS + return nil + } + configPath := opt.SecretScannerOption.ConfigPath + c, err := secret.ParseConfig(configPath) if err != nil { - return SecretAnalyzer{}, xerrors.Errorf("secret scanner error: %w", err) + return xerrors.Errorf("secret config error: %w", err) } - return SecretAnalyzer{ - scanner: s, - configPath: configPath, - }, nil + a.scanner = secret.NewScanner(c) + a.configPath = configPath + return nil } -func (a SecretAnalyzer) Analyze(_ context.Context, input analyzer.AnalysisInput) (*analyzer.AnalysisResult, error) { +func (a *SecretAnalyzer) Analyze(_ context.Context, input analyzer.AnalysisInput) (*analyzer.AnalysisResult, error) { // Do not scan binaries binary, err := isBinary(input.Content, input.Info.Size()) if binary || err != nil { @@ -121,7 +130,7 @@ func isBinary(content dio.ReadSeekerAt, fileSize int64) (bool, error) { return false, nil } -func (a SecretAnalyzer) Required(filePath string, fi os.FileInfo) bool { +func (a *SecretAnalyzer) Required(filePath string, fi os.FileInfo) bool { // Skip small files if fi.Size() < 10 { return false @@ -161,10 +170,10 @@ func (a SecretAnalyzer) Required(filePath string, fi os.FileInfo) bool { return true } -func (a SecretAnalyzer) Type() analyzer.Type { +func (a *SecretAnalyzer) Type() analyzer.Type { return analyzer.TypeSecret } -func (a SecretAnalyzer) Version() int { +func (a *SecretAnalyzer) Version() int { return version } diff --git a/pkg/fanal/analyzer/secret/secret_test.go b/pkg/fanal/analyzer/secret/secret_test.go index 5c2f238d722..516b5804fb4 100644 --- a/pkg/fanal/analyzer/secret/secret_test.go +++ b/pkg/fanal/analyzer/secret/secret_test.go @@ -1,4 +1,4 @@ -package secret +package secret_test import ( "context" @@ -9,6 +9,7 @@ import ( "github.com/stretchr/testify/require" "github.com/aquasecurity/trivy/pkg/fanal/analyzer" + "github.com/aquasecurity/trivy/pkg/fanal/analyzer/secret" "github.com/aquasecurity/trivy/pkg/fanal/types" ) @@ -150,7 +151,10 @@ func TestSecretAnalyzer(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - a, err := newSecretAnalyzer(tt.configPath) + a := &secret.SecretAnalyzer{} + err := a.Init(analyzer.AnalyzerOptions{ + SecretScannerOption: analyzer.SecretScannerOption{ConfigPath: tt.configPath}, + }) require.NoError(t, err) content, err := os.Open(tt.filePath) require.NoError(t, err) @@ -205,7 +209,8 @@ func TestSecretRequire(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - a, err := newSecretAnalyzer("") + a := secret.SecretAnalyzer{} + err := a.Init(analyzer.AnalyzerOptions{}) require.NoError(t, err) fi, err := os.Stat(tt.filePath) diff --git a/pkg/fanal/artifact/artifact.go b/pkg/fanal/artifact/artifact.go index cee5ad00469..2f89811624d 100644 --- a/pkg/fanal/artifact/artifact.go +++ b/pkg/fanal/artifact/artifact.go @@ -6,7 +6,6 @@ import ( "github.com/aquasecurity/trivy/pkg/fanal/analyzer" misconf "github.com/aquasecurity/trivy/pkg/fanal/analyzer/config" - "github.com/aquasecurity/trivy/pkg/fanal/analyzer/secret" "github.com/aquasecurity/trivy/pkg/fanal/types" ) @@ -26,7 +25,7 @@ type Option struct { RepoTag string MisconfScannerOption misconf.ScannerOption - SecretScannerOption secret.ScannerOption + SecretScannerOption analyzer.SecretScannerOption } func (o *Option) Sort() { diff --git a/pkg/fanal/artifact/image/image.go b/pkg/fanal/artifact/image/image.go index 028a0bed7ec..21d52db069f 100644 --- a/pkg/fanal/artifact/image/image.go +++ b/pkg/fanal/artifact/image/image.go @@ -15,7 +15,6 @@ import ( "golang.org/x/xerrors" "github.com/aquasecurity/trivy/pkg/fanal/analyzer" - "github.com/aquasecurity/trivy/pkg/fanal/analyzer/secret" "github.com/aquasecurity/trivy/pkg/fanal/artifact" "github.com/aquasecurity/trivy/pkg/fanal/cache" "github.com/aquasecurity/trivy/pkg/fanal/handler" @@ -45,12 +44,12 @@ func NewArtifact(img types.Image, c cache.ArtifactCache, opt artifact.Option) (a return nil, xerrors.Errorf("handler init error: %w", err) } - // Register secret analyzer - if err = secret.RegisterSecretAnalyzer(opt.SecretScannerOption); err != nil { - return nil, xerrors.Errorf("secret scanner error: %w", err) - } - - a, err := analyzer.NewAnalyzerGroup(opt.AnalyzerGroup, opt.DisabledAnalyzers, opt.FilePatterns) + a, err := analyzer.NewAnalyzerGroup(analyzer.AnalyzerOptions{ + Group: opt.AnalyzerGroup, + FilePatterns: opt.FilePatterns, + DisabledAnalyzers: opt.DisabledAnalyzers, + SecretScannerOption: opt.SecretScannerOption, + }) if err != nil { return nil, xerrors.Errorf("analyzer group error: %w", err) } @@ -327,29 +326,32 @@ func (a Artifact) inspectConfig(imageID string, osFound types.OS) error { // Guess layers in base image (call base layers). // // e.g. In the following example, we should detect layers in debian:8. -// FROM debian:8 -// RUN apt-get update -// COPY mysecret / -// ENTRYPOINT ["entrypoint.sh"] -// CMD ["somecmd"] +// +// FROM debian:8 +// RUN apt-get update +// COPY mysecret / +// ENTRYPOINT ["entrypoint.sh"] +// CMD ["somecmd"] // // debian:8 may be like -// ADD file:5d673d25da3a14ce1f6cf66e4c7fd4f4b85a3759a9d93efb3fd9ff852b5b56e4 in / -// CMD ["/bin/sh"] +// +// ADD file:5d673d25da3a14ce1f6cf66e4c7fd4f4b85a3759a9d93efb3fd9ff852b5b56e4 in / +// CMD ["/bin/sh"] // // In total, it would be like: -// ADD file:5d673d25da3a14ce1f6cf66e4c7fd4f4b85a3759a9d93efb3fd9ff852b5b56e4 in / -// CMD ["/bin/sh"] # empty layer (detected) -// RUN apt-get update -// COPY mysecret / -// ENTRYPOINT ["entrypoint.sh"] # empty layer (skipped) -// CMD ["somecmd"] # empty layer (skipped) +// +// ADD file:5d673d25da3a14ce1f6cf66e4c7fd4f4b85a3759a9d93efb3fd9ff852b5b56e4 in / +// CMD ["/bin/sh"] # empty layer (detected) +// RUN apt-get update +// COPY mysecret / +// ENTRYPOINT ["entrypoint.sh"] # empty layer (skipped) +// CMD ["somecmd"] # empty layer (skipped) // // This method tries to detect CMD in the second line and assume the first line is a base layer. -// 1. Iterate histories from the bottom. -// 2. Skip all the empty layers at the bottom. In the above example, "entrypoint.sh" and "somecmd" will be skipped -// 3. If it finds CMD, it assumes that it is the end of base layers. -// 4. It gets all the layers as base layers above the CMD found in #3. +// 1. Iterate histories from the bottom. +// 2. Skip all the empty layers at the bottom. In the above example, "entrypoint.sh" and "somecmd" will be skipped +// 3. If it finds CMD, it assumes that it is the end of base layers. +// 4. It gets all the layers as base layers above the CMD found in #3. func (a Artifact) guessBaseLayers(diffIDs []string, configFile *v1.ConfigFile) []string { if configFile == nil { return nil diff --git a/pkg/fanal/artifact/image/image_test.go b/pkg/fanal/artifact/image/image_test.go index 5fd45975e85..997c975205f 100644 --- a/pkg/fanal/artifact/image/image_test.go +++ b/pkg/fanal/artifact/image/image_test.go @@ -28,6 +28,7 @@ import ( _ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/pkg/apk" _ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/pkg/dpkg" _ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/repo/apk" + _ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/secret" _ "github.com/aquasecurity/trivy/pkg/fanal/handler/misconf" _ "github.com/aquasecurity/trivy/pkg/fanal/handler/sysfile" ) diff --git a/pkg/fanal/artifact/local/fs.go b/pkg/fanal/artifact/local/fs.go index 8b0c3cf1186..8cff99e2c5b 100644 --- a/pkg/fanal/artifact/local/fs.go +++ b/pkg/fanal/artifact/local/fs.go @@ -14,7 +14,6 @@ import ( "golang.org/x/xerrors" "github.com/aquasecurity/trivy/pkg/fanal/analyzer" - "github.com/aquasecurity/trivy/pkg/fanal/analyzer/secret" "github.com/aquasecurity/trivy/pkg/fanal/artifact" "github.com/aquasecurity/trivy/pkg/fanal/cache" "github.com/aquasecurity/trivy/pkg/fanal/handler" @@ -42,12 +41,12 @@ func NewArtifact(rootPath string, c cache.ArtifactCache, opt artifact.Option) (a return nil, xerrors.Errorf("handler initialize error: %w", err) } - // Register secret analyzer - if err = secret.RegisterSecretAnalyzer(opt.SecretScannerOption); err != nil { - return nil, xerrors.Errorf("secret scanner error: %w", err) - } - - a, err := analyzer.NewAnalyzerGroup(opt.AnalyzerGroup, opt.DisabledAnalyzers, opt.FilePatterns) + a, err := analyzer.NewAnalyzerGroup(analyzer.AnalyzerOptions{ + Group: opt.AnalyzerGroup, + FilePatterns: opt.FilePatterns, + DisabledAnalyzers: opt.DisabledAnalyzers, + SecretScannerOption: opt.SecretScannerOption, + }) if err != nil { return nil, xerrors.Errorf("analyzer group error: %w", err) } diff --git a/pkg/fanal/artifact/local/fs_test.go b/pkg/fanal/artifact/local/fs_test.go index 7c2c451abfc..0c38b510e81 100644 --- a/pkg/fanal/artifact/local/fs_test.go +++ b/pkg/fanal/artifact/local/fs_test.go @@ -6,7 +6,6 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" "github.com/aquasecurity/trivy/pkg/fanal/analyzer" @@ -19,6 +18,7 @@ import ( _ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language/python/pip" _ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/os/alpine" _ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/pkg/apk" + _ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/secret" _ "github.com/aquasecurity/trivy/pkg/fanal/handler/misconf" _ "github.com/aquasecurity/trivy/pkg/fanal/handler/sysfile" ) diff --git a/pkg/fanal/artifact/remote/git_test.go b/pkg/fanal/artifact/remote/git_test.go index f3d042f277e..27afffb641e 100644 --- a/pkg/fanal/artifact/remote/git_test.go +++ b/pkg/fanal/artifact/remote/git_test.go @@ -10,6 +10,7 @@ import ( "github.com/stretchr/testify/require" _ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/config/all" + _ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/secret" "github.com/aquasecurity/trivy/pkg/fanal/artifact" "github.com/aquasecurity/trivy/pkg/fanal/cache" "github.com/aquasecurity/trivy/pkg/fanal/types" diff --git a/pkg/fanal/secret/scanner.go b/pkg/fanal/secret/scanner.go index fb101c79ae3..9166c091794 100644 --- a/pkg/fanal/secret/scanner.go +++ b/pkg/fanal/secret/scanner.go @@ -263,36 +263,39 @@ func (b *Blocks) find() { } } -func NewScanner(configPath string) (Scanner, error) { - // Set default values - global := Global{ - Rules: builtinRules, - AllowRules: builtinAllowRules, - } - +func ParseConfig(configPath string) (*Config, error) { // If no config is passed, use built-in rules and allow rules. if configPath == "" { - return Scanner{&global}, nil + return nil, nil } f, err := os.Open(configPath) if errors.Is(err, os.ErrNotExist) { // If the specified file doesn't exist, it just uses built-in rules and allow rules. log.Logger.Debugf("No secret config detected: %s", configPath) - return Scanner{&global}, nil + return nil, nil } else if err != nil { - return Scanner{}, xerrors.Errorf("file open error %s: %w", configPath, err) + return nil, xerrors.Errorf("file open error %s: %w", configPath, err) } defer f.Close() log.Logger.Infof("Loading %s for secret scanning...", configPath) - // reset global - global = Global{} - var config Config if err = yaml.NewDecoder(f).Decode(&config); err != nil { - return Scanner{}, xerrors.Errorf("secrets config decode error: %w", err) + return nil, xerrors.Errorf("secrets config decode error: %w", err) + } + + return &config, nil +} + +func NewScanner(config *Config) Scanner { + // Use the default rules + if config == nil { + return Scanner{Global: &Global{ + Rules: builtinRules, + AllowRules: builtinAllowRules, + }} } enabledRules := builtinRules @@ -307,19 +310,21 @@ func NewScanner(configPath string) (Scanner, error) { enabledRules = append(enabledRules, config.CustomRules...) // Disable specified rules - global.Rules = lo.Filter(enabledRules, func(v Rule, _ int) bool { + rules := lo.Filter(enabledRules, func(v Rule, _ int) bool { return !slices.Contains(config.DisableRuleIDs, v.ID) }) // Disable specified allow rules allowRules := append(builtinAllowRules, config.CustomAllowRules...) - global.AllowRules = lo.Filter(allowRules, func(v AllowRule, _ int) bool { + allowRules = lo.Filter(allowRules, func(v AllowRule, _ int) bool { return !slices.Contains(config.DisableAllowRuleIDs, v.ID) }) - global.ExcludeBlock = config.ExcludeBlock - - return Scanner{Global: &global}, nil + return Scanner{Global: &Global{ + Rules: rules, + AllowRules: allowRules, + ExcludeBlock: config.ExcludeBlock, + }} } type ScanArgs struct { diff --git a/pkg/fanal/secret/scanner_test.go b/pkg/fanal/secret/scanner_test.go index 01f4669c8b9..769e836d2bd 100644 --- a/pkg/fanal/secret/scanner_test.go +++ b/pkg/fanal/secret/scanner_test.go @@ -678,15 +678,17 @@ func TestSecretScanner(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - s, err := secret.NewScanner(tt.configPath) + content, err := os.ReadFile(tt.inputFilePath) require.NoError(t, err) - content, err := os.ReadFile(tt.inputFilePath) + c, err := secret.ParseConfig(tt.configPath) require.NoError(t, err) + s := secret.NewScanner(c) got := s.Scan(secret.ScanArgs{ FilePath: tt.inputFilePath, - Content: content}, + Content: content, + }, ) assert.Equal(t, tt.want, got) }) diff --git a/pkg/module/module_test.go b/pkg/module/module_test.go index d9faa044a60..5e4eff26442 100644 --- a/pkg/module/module_test.go +++ b/pkg/module/module_test.go @@ -92,7 +92,7 @@ func TestManager_Register(t *testing.T) { }() // Confirm the analyzer is registered - a, err := analyzer.NewAnalyzerGroup("", nil, nil) + a, err := analyzer.NewAnalyzerGroup(analyzer.AnalyzerOptions{}) require.NoError(t, err) got := a.AnalyzerVersions() From 1b40dbb608a6da883c5a5b392d10fa05cef03068 Mon Sep 17 00:00:00 2001 From: knqyf263 Date: Tue, 6 Sep 2022 16:30:03 +0300 Subject: [PATCH 3/6] go mod tidy --- go.sum | 1 - 1 file changed, 1 deletion(-) diff --git a/go.sum b/go.sum index 43e9063f5d2..5feaee4af12 100644 --- a/go.sum +++ b/go.sum @@ -2136,7 +2136,6 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df h1:5Pf6pFKu98ODmgnpvkJ3kFUOQGGLIzLIkbzUHp47618= golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f h1:uF6paiQQebLeSXkrTqHqz0MXhXXS1KgF41eUdBNvxK0= golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= From 21ced14a23840ba7a50b159ad6991a13ee6881bc Mon Sep 17 00:00:00 2001 From: knqyf263 Date: Tue, 6 Sep 2022 17:00:55 +0300 Subject: [PATCH 4/6] Add a missing import --- pkg/fanal/analyzer/all/import.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/fanal/analyzer/all/import.go b/pkg/fanal/analyzer/all/import.go index 034d63cb506..f3009ee68ee 100644 --- a/pkg/fanal/analyzer/all/import.go +++ b/pkg/fanal/analyzer/all/import.go @@ -36,4 +36,5 @@ import ( _ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/pkg/dpkg" _ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/pkg/rpm" _ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/repo/apk" + _ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/secret" ) From da78e85e68dd18ad83b5a868025ec2c99d5ad18c Mon Sep 17 00:00:00 2001 From: knqyf263 Date: Tue, 6 Sep 2022 17:58:17 +0300 Subject: [PATCH 5/6] sort secret findings --- pkg/fanal/secret/scanner.go | 10 +++++++++- pkg/fanal/secret/scanner_test.go | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/pkg/fanal/secret/scanner.go b/pkg/fanal/secret/scanner.go index 9166c091794..021a5a31745 100644 --- a/pkg/fanal/secret/scanner.go +++ b/pkg/fanal/secret/scanner.go @@ -5,6 +5,7 @@ import ( "errors" "os" "regexp" + "sort" "strings" "sync" @@ -337,7 +338,7 @@ type Match struct { Location Location } -func (s Scanner) Scan(args ScanArgs) types.Secret { +func (s *Scanner) Scan(args ScanArgs) types.Secret { // Global allowed paths if s.AllowPath(args.FilePath) { return types.Secret{ @@ -401,6 +402,13 @@ func (s Scanner) Scan(args ScanArgs) types.Secret { return types.Secret{} } + sort.Slice(findings, func(i, j int) bool { + if findings[i].RuleID != findings[j].RuleID { + return findings[i].RuleID < findings[j].RuleID + } + return findings[i].Match < findings[j].Match + }) + return types.Secret{ FilePath: args.FilePath, Findings: findings, diff --git a/pkg/fanal/secret/scanner_test.go b/pkg/fanal/secret/scanner_test.go index 769e836d2bd..81de00e68c5 100644 --- a/pkg/fanal/secret/scanner_test.go +++ b/pkg/fanal/secret/scanner_test.go @@ -495,7 +495,7 @@ func TestSecretScanner(t *testing.T) { inputFilePath: "testdata/aws-secrets.txt", want: types.Secret{ FilePath: "testdata/aws-secrets.txt", - Findings: []types.SecretFinding{wantFinding5, wantFinding9, wantFinding10}, + Findings: []types.SecretFinding{wantFinding5, wantFinding10, wantFinding9}, }, }, { From 77c8465f07cf397b43de40848db10ea585492b37 Mon Sep 17 00:00:00 2001 From: knqyf263 Date: Wed, 7 Sep 2022 08:55:58 +0300 Subject: [PATCH 6/6] Check if the config path is the same --- pkg/fanal/analyzer/secret/secret.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/fanal/analyzer/secret/secret.go b/pkg/fanal/analyzer/secret/secret.go index 4e245ef8ca7..f948e702cf8 100644 --- a/pkg/fanal/analyzer/secret/secret.go +++ b/pkg/fanal/analyzer/secret/secret.go @@ -61,7 +61,7 @@ func NewSecretAnalyzer(s secret.Scanner, configPath string) *SecretAnalyzer { // Init initializes and sets a secret scanner func (a *SecretAnalyzer) Init(opt analyzer.AnalyzerOptions) error { - if !lo.IsEmpty(a.scanner) { + if opt.SecretScannerOption.ConfigPath == a.configPath && !lo.IsEmpty(a.scanner) { // This check is for tools importing Trivy and customize analyzers // Never reach here in Trivy OSS return nil