diff --git a/pkg/iac/scanners/dockerfile/parser/parser.go b/pkg/iac/scanners/dockerfile/parser/parser.go index e92116ae3079..128d9515e8b1 100644 --- a/pkg/iac/scanners/dockerfile/parser/parser.go +++ b/pkg/iac/scanners/dockerfile/parser/parser.go @@ -4,76 +4,26 @@ import ( "context" "fmt" "io" - "io/fs" - "path/filepath" "strings" "github.com/moby/buildkit/frontend/dockerfile/instructions" "github.com/moby/buildkit/frontend/dockerfile/parser" "github.com/aquasecurity/trivy/pkg/iac/providers/dockerfile" - "github.com/aquasecurity/trivy/pkg/log" ) -type Parser struct { - logger *log.Logger -} - -// New creates a new Dockerfile parser -func New() *Parser { - return &Parser{ - logger: log.WithPrefix("dockerfile parser"), - } -} - -func (p *Parser) ParseFS(ctx context.Context, target fs.FS, path string) (map[string]*dockerfile.Dockerfile, error) { - - files := make(map[string]*dockerfile.Dockerfile) - if err := fs.WalkDir(target, filepath.ToSlash(path), func(path string, entry fs.DirEntry, err error) error { - select { - case <-ctx.Done(): - return ctx.Err() - default: - } - if err != nil { - return err - } - if entry.IsDir() { - return nil - } - - df, err := p.ParseFile(ctx, target, path) - if err != nil { - p.logger.Error("Failed to parse Dockerfile", log.FilePath(path), log.Err(err)) - return nil - } - files[path] = df - return nil - }); err != nil { - return nil, err - } - return files, nil -} - -// ParseFile parses Dockerfile content from the provided filesystem path. -func (p *Parser) ParseFile(_ context.Context, fsys fs.FS, path string) (*dockerfile.Dockerfile, error) { - f, err := fsys.Open(filepath.ToSlash(path)) - if err != nil { - return nil, err - } - defer func() { _ = f.Close() }() - return p.parse(path, f) -} - -func (p *Parser) parse(path string, r io.Reader) (*dockerfile.Dockerfile, error) { +func Parse(_ context.Context, r io.Reader, path string) (any, error) { parsed, err := parser.Parse(r) if err != nil { return nil, fmt.Errorf("dockerfile parse error: %w", err) } - var parsedFile dockerfile.Dockerfile - var stage dockerfile.Stage - var stageIndex int + var ( + parsedFile dockerfile.Dockerfile + stage dockerfile.Stage + stageIndex int + ) + fromValue := "args" for _, child := range parsed.AST.Children { child.Value = strings.ToLower(child.Value) diff --git a/pkg/iac/scanners/dockerfile/parser/parser_test.go b/pkg/iac/scanners/dockerfile/parser/parser_test.go index 764cb3a0e091..ad1acf193bf3 100644 --- a/pkg/iac/scanners/dockerfile/parser/parser_test.go +++ b/pkg/iac/scanners/dockerfile/parser/parser_test.go @@ -1,11 +1,15 @@ -package parser +package parser_test import ( + "context" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + + "github.com/aquasecurity/trivy/pkg/iac/providers/dockerfile" + "github.com/aquasecurity/trivy/pkg/iac/scanners/dockerfile/parser" ) func Test_Parser(t *testing.T) { @@ -15,12 +19,13 @@ RUN make /app CMD python /app/app.py ` - df, err := New().parse("Dockerfile", strings.NewReader(input)) + res, err := parser.Parse(context.TODO(), strings.NewReader(input), "Dockerfile") require.NoError(t, err) - assert.Len(t, df.Stages, 1) + df, ok := res.(*dockerfile.Dockerfile) + require.True(t, ok) - require.Len(t, df.Stages, 1) + assert.Len(t, df.Stages, 1) assert.Equal(t, "ubuntu:18.04", df.Stages[0].Name) commands := df.Stages[0].Commands diff --git a/pkg/iac/scanners/dockerfile/scanner.go b/pkg/iac/scanners/dockerfile/scanner.go index 1694f28d814a..5637410945eb 100644 --- a/pkg/iac/scanners/dockerfile/scanner.go +++ b/pkg/iac/scanners/dockerfile/scanner.go @@ -1,114 +1,12 @@ package dockerfile import ( - "context" - "io/fs" - "sync" - - "github.com/aquasecurity/trivy/pkg/iac/framework" - "github.com/aquasecurity/trivy/pkg/iac/rego" - "github.com/aquasecurity/trivy/pkg/iac/scan" - "github.com/aquasecurity/trivy/pkg/iac/scanners" "github.com/aquasecurity/trivy/pkg/iac/scanners/dockerfile/parser" + "github.com/aquasecurity/trivy/pkg/iac/scanners/generic" "github.com/aquasecurity/trivy/pkg/iac/scanners/options" "github.com/aquasecurity/trivy/pkg/iac/types" - "github.com/aquasecurity/trivy/pkg/log" ) -var _ scanners.FSScanner = (*Scanner)(nil) -var _ options.ConfigurableScanner = (*Scanner)(nil) - -type Scanner struct { - mu sync.Mutex - logger *log.Logger - parser *parser.Parser - regoScanner *rego.Scanner - options []options.ScannerOption -} - -func (s *Scanner) SetIncludeDeprecatedChecks(bool) {} -func (s *Scanner) SetRegoOnly(bool) {} -func (s *Scanner) SetFrameworks(frameworks []framework.Framework) {} - -func (s *Scanner) Name() string { - return "Dockerfile" -} - -func NewScanner(opts ...options.ScannerOption) *Scanner { - s := &Scanner{ - options: opts, - logger: log.WithPrefix("dockerfile scanner"), - } - for _, opt := range opts { - opt(s) - } - s.parser = parser.New() - return s -} - -func (s *Scanner) ScanFS(ctx context.Context, fsys fs.FS, path string) (scan.Results, error) { - - files, err := s.parser.ParseFS(ctx, fsys, path) - if err != nil { - return nil, err - } - - if len(files) == 0 { - return nil, nil - } - - var inputs []rego.Input - for path, dfile := range files { - inputs = append(inputs, rego.Input{ - Path: path, - FS: fsys, - Contents: dfile.ToRego(), - }) - } - - results, err := s.scanRego(ctx, fsys, inputs...) - if err != nil { - return nil, err - } - return results, nil -} - -func (s *Scanner) ScanFile(ctx context.Context, fsys fs.FS, path string) (scan.Results, error) { - dockerfile, err := s.parser.ParseFile(ctx, fsys, path) - if err != nil { - return nil, err - } - s.logger.Debug("Scanning", log.FilePath(path)) - return s.scanRego(ctx, fsys, rego.Input{ - Path: path, - Contents: dockerfile.ToRego(), - }) -} - -func (s *Scanner) initRegoScanner(srcFS fs.FS) (*rego.Scanner, error) { - s.mu.Lock() - defer s.mu.Unlock() - if s.regoScanner != nil { - return s.regoScanner, nil - } - - regoScanner := rego.NewScanner(types.SourceDockerfile, s.options...) - if err := regoScanner.LoadPolicies(srcFS); err != nil { - return nil, err - } - s.regoScanner = regoScanner - return regoScanner, nil -} - -func (s *Scanner) scanRego(ctx context.Context, srcFS fs.FS, inputs ...rego.Input) (scan.Results, error) { - regoScanner, err := s.initRegoScanner(srcFS) - if err != nil { - return nil, err - } - results, err := regoScanner.ScanInput(ctx, inputs...) - if err != nil { - return nil, err - } - results.SetSourceAndFilesystem("", srcFS, false) - return results, nil +func NewScanner(opts ...options.ScannerOption) *generic.GenericScanner { + return generic.NewScanner("Dockerfile", types.SourceDockerfile, generic.ParseFunc(parser.Parse), opts...) } diff --git a/pkg/iac/scanners/dockerfile/scanner_test.go b/pkg/iac/scanners/dockerfile/scanner_test.go index 2872df1e4ef6..e8c66b27db08 100644 --- a/pkg/iac/scanners/dockerfile/scanner_test.go +++ b/pkg/iac/scanners/dockerfile/scanner_test.go @@ -1,4 +1,4 @@ -package dockerfile +package dockerfile_test import ( "bytes" @@ -13,6 +13,7 @@ import ( "github.com/aquasecurity/trivy/pkg/iac/rego" "github.com/aquasecurity/trivy/pkg/iac/rego/schemas" "github.com/aquasecurity/trivy/pkg/iac/scan" + "github.com/aquasecurity/trivy/pkg/iac/scanners/dockerfile" ) const DS006PolicyWithDockerfileSchema = `# METADATA @@ -219,7 +220,7 @@ USER root "/rules/rule.rego": DS006LegacyWithOldStyleMetadata, }) - scanner := NewScanner(rego.WithPolicyDirs("rules")) + scanner := dockerfile.NewScanner(rego.WithPolicyDirs("rules")) results, err := scanner.ScanFS(context.TODO(), fs, "code") require.NoError(t, err) @@ -563,7 +564,7 @@ COPY --from=dep /binary /` var traceBuf bytes.Buffer - scanner := NewScanner( + scanner := dockerfile.NewScanner( rego.WithPolicyDirs("rules"), rego.WithEmbeddedLibraries(true), rego.WithTrace(&traceBuf), diff --git a/pkg/iac/scanners/generic/scanner.go b/pkg/iac/scanners/generic/scanner.go new file mode 100644 index 000000000000..5a36709d9a04 --- /dev/null +++ b/pkg/iac/scanners/generic/scanner.go @@ -0,0 +1,220 @@ +package generic + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io" + "io/fs" + "path/filepath" + "strings" + "sync" + + "github.com/BurntSushi/toml" + "gopkg.in/yaml.v3" + + "github.com/aquasecurity/trivy/pkg/iac/framework" + "github.com/aquasecurity/trivy/pkg/iac/rego" + "github.com/aquasecurity/trivy/pkg/iac/scan" + "github.com/aquasecurity/trivy/pkg/iac/scanners/options" + "github.com/aquasecurity/trivy/pkg/iac/types" + "github.com/aquasecurity/trivy/pkg/log" +) + +func NewJsonScanner(opts ...options.ScannerOption) *GenericScanner { + return NewScanner("JSON", types.SourceJSON, ParseFunc(parseJson), opts...) +} + +func NewYamlScanner(opts ...options.ScannerOption) *GenericScanner { + return NewScanner("YAML", types.SourceYAML, ParseFunc(parseYaml), opts...) +} + +func NewTomlScanner(opts ...options.ScannerOption) *GenericScanner { + return NewScanner("TOML", types.SourceTOML, ParseFunc(parseTOML), opts...) +} + +type configParser interface { + Parse(ctx context.Context, r io.Reader, path string) (any, error) +} + +// GenericScanner is a scanner that scans a file as is without processing it +type GenericScanner struct { + mu sync.Mutex + name string + source types.Source + logger *log.Logger + options []options.ScannerOption + regoScanner *rego.Scanner + + parser configParser +} + +type ParseFunc func(ctx context.Context, r io.Reader, path string) (any, error) + +func (f ParseFunc) Parse(ctx context.Context, r io.Reader, path string) (any, error) { + return f(ctx, r, path) +} + +func NewScanner(name string, source types.Source, parser configParser, opts ...options.ScannerOption) *GenericScanner { + s := &GenericScanner{ + name: name, + options: opts, + source: source, + logger: log.WithPrefix(fmt.Sprintf("%s scanner", source)), + parser: parser, + } + + for _, opt := range opts { + opt(s) + } + + return s +} + +func (s *GenericScanner) Name() string { + return s.name +} + +func (s *GenericScanner) ScanFS(ctx context.Context, fsys fs.FS, dir string) (scan.Results, error) { + fileset, err := s.parseFS(ctx, fsys, dir) + if err != nil { + return nil, err + } + + if len(fileset) == 0 { + return nil, nil + } + + var inputs []rego.Input + for path, val := range fileset { + switch v := val.(type) { + case interface{ ToRego() any }: + inputs = append(inputs, rego.Input{ + Path: path, + Contents: v.ToRego(), + FS: fsys, + }) + case []any: + for _, file := range v { + inputs = append(inputs, rego.Input{ + Path: path, + Contents: file, + FS: fsys, + }) + } + default: + inputs = append(inputs, rego.Input{ + Path: path, + Contents: v, + FS: fsys, + }) + } + } + + regoScanner, err := s.initRegoScanner(fsys) + if err != nil { + return nil, err + } + + s.logger.Debug("Scanning files...", log.Int("count", len(inputs))) + results, err := regoScanner.ScanInput(ctx, inputs...) + if err != nil { + return nil, err + } + results.SetSourceAndFilesystem("", fsys, false) + return results, nil +} + +func (s *GenericScanner) parseFS(ctx context.Context, fsys fs.FS, path string) (map[string]any, error) { + files := make(map[string]any) + if err := fs.WalkDir(fsys, filepath.ToSlash(path), func(path string, entry fs.DirEntry, err error) error { + select { + case <-ctx.Done(): + return ctx.Err() + default: + } + if err != nil { + return err + } + if entry.IsDir() { + return nil + } + + f, err := fsys.Open(filepath.ToSlash(path)) + if err != nil { + return err + } + defer f.Close() + + df, err := s.parser.Parse(ctx, f, path) + if err != nil { + s.logger.Error("Failed to parse file", log.FilePath(path), log.Err(err)) + return nil + } + files[path] = df + return nil + }); err != nil { + return nil, err + } + return files, nil +} + +func (s *GenericScanner) initRegoScanner(srcFS fs.FS) (*rego.Scanner, error) { + s.mu.Lock() + defer s.mu.Unlock() + if s.regoScanner != nil { + return s.regoScanner, nil + } + regoScanner := rego.NewScanner(s.source, s.options...) + if err := regoScanner.LoadPolicies(srcFS); err != nil { + return nil, err + } + s.regoScanner = regoScanner + return regoScanner, nil +} + +func (*GenericScanner) SetRegoOnly(bool) {} +func (*GenericScanner) SetIncludeDeprecatedChecks(bool) {} +func (*GenericScanner) SetFrameworks([]framework.Framework) {} + +func parseJson(ctx context.Context, r io.Reader, _ string) (any, error) { + var target any + if err := json.NewDecoder(r).Decode(&target); err != nil { + return nil, err + } + return target, nil +} + +func parseYaml(ctx context.Context, r io.Reader, _ string) (any, error) { + contents, err := io.ReadAll(r) + if err != nil { + return nil, err + } + + var results []any + + marker := "\n---\n" + altMarker := "\r\n---\r\n" + if bytes.Contains(contents, []byte(altMarker)) { + marker = altMarker + } + + for _, partial := range strings.Split(string(contents), marker) { + var target any + if err := yaml.Unmarshal([]byte(partial), &target); err != nil { + return nil, err + } + results = append(results, target) + } + + return results, nil +} + +func parseTOML(ctx context.Context, r io.Reader, _ string) (any, error) { + var target any + if _, err := toml.NewDecoder(r).Decode(&target); err != nil { + return nil, err + } + return target, nil +} diff --git a/pkg/iac/scanners/generic/scanner_test.go b/pkg/iac/scanners/generic/scanner_test.go new file mode 100644 index 000000000000..46d0eef1653a --- /dev/null +++ b/pkg/iac/scanners/generic/scanner_test.go @@ -0,0 +1,223 @@ +package generic_test + +import ( + "context" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/aquasecurity/trivy/internal/testutil" + "github.com/aquasecurity/trivy/pkg/iac/framework" + "github.com/aquasecurity/trivy/pkg/iac/rego" + "github.com/aquasecurity/trivy/pkg/iac/scan" + "github.com/aquasecurity/trivy/pkg/iac/scanners/generic" +) + +func TestJsonScanner(t *testing.T) { + fsys := testutil.CreateFS(t, map[string]string{ + "/code/data.json": `{ "x": { "y": 123, "z": ["a", "b", "c"]}}`, + "/rules/rule.rego": `package builtin.json.lol + +__rego_metadata__ := { + "id": "ABC123", + "avd_id": "AVD-AB-0123", + "title": "title", + "short_code": "short", + "severity": "CRITICAL", + "type": "JSON Check", + "description": "description", + "recommended_actions": "actions", + "url": "https://example.com", +} + +__rego_input__ := { + "combine": false, + "selector": [{"type": "json"}], +} + +deny[res] { + input.x.y == 123 + res := { + "msg": "oh no", + "startline": 1, + "endline": 2, + } +} + +`, + }) + + scanner := generic.NewJsonScanner(rego.WithPolicyDirs("rules")) + + results, err := scanner.ScanFS(context.TODO(), fsys, "code") + require.NoError(t, err) + + require.Len(t, results.GetFailed(), 1) + + assert.Equal(t, scan.Rule{ + AVDID: "AVD-AB-0123", + Aliases: []string{"ABC123"}, + ShortCode: "short", + Summary: "title", + Explanation: "description", + Impact: "", + Resolution: "actions", + Provider: "json", + Service: "general", + Links: []string{"https://example.com"}, + Severity: "CRITICAL", + Terraform: &scan.EngineMetadata{}, + CloudFormation: &scan.EngineMetadata{}, + CustomChecks: scan.CustomChecks{ + Terraform: (*scan.TerraformCustomCheck)(nil), + }, + RegoPackage: "data.builtin.json.lol", + Frameworks: map[framework.Framework][]string{ + framework.Default: {}, + }, + }, results.GetFailed()[0].Rule()) +} + +func TestYamlScanner(t *testing.T) { + fsys := testutil.CreateFS(t, map[string]string{ + "/code/data.yaml": `--- +x: + y: 123 + z: + - a + - b + - c +`, + "/rules/rule.rego": `package builtin.yaml.lol + +__rego_metadata__ := { + "id": "ABC123", + "avd_id": "AVD-AB-0123", + "title": "title", + "short_code": "short", + "severity": "CRITICAL", + "type": "YAML Check", + "description": "description", + "recommended_actions": "actions", + "url": "https://example.com", +} + +__rego_input__ := { + "combine": false, + "selector": [{"type": "yaml"}], +} + +deny[res] { + input.x.y == 123 + res := { + "msg": "oh no", + "startline": 1, + "endline": 2, + } +} + +`, + }) + + scanner := generic.NewYamlScanner(rego.WithPolicyDirs("rules")) + + results, err := scanner.ScanFS(context.TODO(), fsys, "code") + require.NoError(t, err) + + require.Len(t, results.GetFailed(), 1) + + assert.Equal(t, scan.Rule{ + AVDID: "AVD-AB-0123", + Aliases: []string{"ABC123"}, + ShortCode: "short", + Summary: "title", + Explanation: "description", + Impact: "", + Resolution: "actions", + Provider: "yaml", + Service: "general", + Links: []string{"https://example.com"}, + Severity: "CRITICAL", + Terraform: &scan.EngineMetadata{}, + CloudFormation: &scan.EngineMetadata{}, + CustomChecks: scan.CustomChecks{ + Terraform: (*scan.TerraformCustomCheck)(nil)}, + RegoPackage: "data.builtin.yaml.lol", + Frameworks: map[framework.Framework][]string{ + framework.Default: {}, + }, + }, + results.GetFailed()[0].Rule(), + ) +} + +func TestTomlParser(t *testing.T) { + fsys := testutil.CreateFS(t, map[string]string{ + "/code/code.toml": ` +[x] +y = 123 +z = ["a", "b", "c"] +`, + "/rules/rule.rego": `package builtin.toml.lol + +__rego_metadata__ := { + "id": "ABC123", + "avd_id": "AVD-AB-0123", + "title": "title", + "short_code": "short", + "severity": "CRITICAL", + "type": "TOML Check", + "description": "description", + "recommended_actions": "actions", + "url": "https://example.com", +} + +__rego_input__ := { + "combine": false, + "selector": [{"type": "toml"}], +} + +deny[res] { + input.x.y == 123 + res := { + "msg": "oh no", + "startline": 1, + "endline": 2, + } +} + +`, + }) + + scanner := generic.NewTomlScanner(rego.WithPolicyDirs("rules")) + + results, err := scanner.ScanFS(context.TODO(), fsys, "code") + require.NoError(t, err) + + require.Len(t, results.GetFailed(), 1) + + assert.Equal(t, scan.Rule{ + AVDID: "AVD-AB-0123", + Aliases: []string{"ABC123"}, + ShortCode: "short", + Summary: "title", + Explanation: "description", + Impact: "", + Resolution: "actions", + Provider: "toml", + Service: "general", + Links: []string{"https://example.com"}, + Severity: "CRITICAL", + Terraform: &scan.EngineMetadata{}, + CloudFormation: &scan.EngineMetadata{}, + CustomChecks: scan.CustomChecks{ + Terraform: (*scan.TerraformCustomCheck)(nil)}, + RegoPackage: "data.builtin.toml.lol", + Frameworks: map[framework.Framework][]string{ + framework.Default: {}, + }, + }, + results.GetFailed()[0].Rule(), + ) +} diff --git a/pkg/iac/scanners/json/parser/parser.go b/pkg/iac/scanners/json/parser/parser.go deleted file mode 100644 index c97e54b40bd9..000000000000 --- a/pkg/iac/scanners/json/parser/parser.go +++ /dev/null @@ -1,65 +0,0 @@ -package parser - -import ( - "context" - "encoding/json" - "io/fs" - "path/filepath" - - "github.com/aquasecurity/trivy/pkg/log" -) - -type Parser struct { - logger *log.Logger -} - -// New creates a new parser -func New() *Parser { - return &Parser{ - logger: log.WithPrefix("json parser"), - } -} - -func (p *Parser) ParseFS(ctx context.Context, target fs.FS, path string) (map[string]any, error) { - - files := make(map[string]any) - if err := fs.WalkDir(target, filepath.ToSlash(path), func(path string, entry fs.DirEntry, err error) error { - select { - case <-ctx.Done(): - return ctx.Err() - default: - } - if err != nil { - return err - } - if entry.IsDir() { - return nil - } - - df, err := p.ParseFile(ctx, target, path) - if err != nil { - p.logger.Error("Parse error", log.FilePath(path), log.Err(err)) - return nil - } - - files[path] = df - return nil - }); err != nil { - return nil, err - } - return files, nil -} - -// ParseFile parses Dockerfile content from the provided filesystem path. -func (p *Parser) ParseFile(_ context.Context, fsys fs.FS, path string) (any, error) { - f, err := fsys.Open(filepath.ToSlash(path)) - if err != nil { - return nil, err - } - defer func() { _ = f.Close() }() - var target any - if err := json.NewDecoder(f).Decode(&target); err != nil { - return nil, err - } - return target, nil -} diff --git a/pkg/iac/scanners/json/parser/parser_test.go b/pkg/iac/scanners/json/parser/parser_test.go deleted file mode 100644 index a47868fad0ed..000000000000 --- a/pkg/iac/scanners/json/parser/parser_test.go +++ /dev/null @@ -1,51 +0,0 @@ -package parser - -import ( - "context" - "testing" - - "github.com/liamg/memoryfs" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func Test_Parser(t *testing.T) { - input := `{ "x": { "y": 123, "z": ["a", "b", "c"]}}` - - memfs := memoryfs.New() - err := memfs.WriteFile("something.json", []byte(input), 0644) - require.NoError(t, err) - - data, err := New().ParseFile(context.TODO(), memfs, "something.json") - require.NoError(t, err) - - msi, ok := data.(map[string]any) - require.True(t, ok) - - xObj, ok := msi["x"] - require.True(t, ok) - - xMsi, ok := xObj.(map[string]any) - require.True(t, ok) - - yRaw, ok := xMsi["y"] - require.True(t, ok) - - y, ok := yRaw.(float64) - require.True(t, ok) - - assert.InEpsilon(t, 123.0, y, 0.0001) - - zRaw, ok := xMsi["z"] - require.True(t, ok) - - z, ok := zRaw.([]any) - require.True(t, ok) - - require.Len(t, z, 3) - - assert.Equal(t, "a", z[0]) - assert.Equal(t, "b", z[1]) - assert.Equal(t, "c", z[2]) - -} diff --git a/pkg/iac/scanners/json/scanner.go b/pkg/iac/scanners/json/scanner.go deleted file mode 100644 index f46f9cc56bc9..000000000000 --- a/pkg/iac/scanners/json/scanner.go +++ /dev/null @@ -1,113 +0,0 @@ -package json - -import ( - "context" - "io/fs" - "sync" - - "github.com/aquasecurity/trivy/pkg/iac/framework" - "github.com/aquasecurity/trivy/pkg/iac/rego" - "github.com/aquasecurity/trivy/pkg/iac/scan" - "github.com/aquasecurity/trivy/pkg/iac/scanners" - "github.com/aquasecurity/trivy/pkg/iac/scanners/json/parser" - "github.com/aquasecurity/trivy/pkg/iac/scanners/options" - "github.com/aquasecurity/trivy/pkg/iac/types" - "github.com/aquasecurity/trivy/pkg/log" -) - -var _ scanners.FSScanner = (*Scanner)(nil) -var _ options.ConfigurableScanner = (*Scanner)(nil) - -type Scanner struct { - mu sync.Mutex - logger *log.Logger - parser *parser.Parser - regoScanner *rego.Scanner - options []options.ScannerOption -} - -func (s *Scanner) SetIncludeDeprecatedChecks(bool) {} -func (s *Scanner) SetRegoOnly(bool) {} -func (s *Scanner) SetFrameworks(frameworks []framework.Framework) {} - -func NewScanner(opts ...options.ScannerOption) *Scanner { - s := &Scanner{ - options: opts, - logger: log.WithPrefix("json scanner"), - parser: parser.New(), - } - for _, opt := range opts { - opt(s) - } - return s -} - -func (s *Scanner) Name() string { - return "JSON" -} - -func (s *Scanner) ScanFS(ctx context.Context, fsys fs.FS, path string) (scan.Results, error) { - - files, err := s.parser.ParseFS(ctx, fsys, path) - if err != nil { - return nil, err - } - - if len(files) == 0 { - return nil, nil - } - - var inputs []rego.Input - for path, file := range files { - inputs = append(inputs, rego.Input{ - Path: path, - FS: fsys, - Contents: file, - }) - } - - results, err := s.scanRego(ctx, fsys, inputs...) - if err != nil { - return nil, err - } - return results, nil -} - -func (s *Scanner) ScanFile(ctx context.Context, fsys fs.FS, path string) (scan.Results, error) { - parsed, err := s.parser.ParseFile(ctx, fsys, path) - if err != nil { - return nil, err - } - s.logger.Debug("Scanning", log.FilePath(path)) - return s.scanRego(ctx, fsys, rego.Input{ - Path: path, - Contents: parsed, - }) -} - -func (s *Scanner) initRegoScanner(srcFS fs.FS) (*rego.Scanner, error) { - s.mu.Lock() - defer s.mu.Unlock() - if s.regoScanner != nil { - return s.regoScanner, nil - } - regoScanner := rego.NewScanner(types.SourceJSON, s.options...) - if err := regoScanner.LoadPolicies(srcFS); err != nil { - return nil, err - } - s.regoScanner = regoScanner - return regoScanner, nil -} - -func (s *Scanner) scanRego(ctx context.Context, srcFS fs.FS, inputs ...rego.Input) (scan.Results, error) { - regoScanner, err := s.initRegoScanner(srcFS) - if err != nil { - return nil, err - } - results, err := regoScanner.ScanInput(ctx, inputs...) - if err != nil { - return nil, err - } - results.SetSourceAndFilesystem("", srcFS, false) - return results, nil -} diff --git a/pkg/iac/scanners/json/scanner_test.go b/pkg/iac/scanners/json/scanner_test.go deleted file mode 100644 index 6656f70b2e25..000000000000 --- a/pkg/iac/scanners/json/scanner_test.go +++ /dev/null @@ -1,80 +0,0 @@ -package json - -import ( - "context" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/aquasecurity/trivy/internal/testutil" - "github.com/aquasecurity/trivy/pkg/iac/framework" - "github.com/aquasecurity/trivy/pkg/iac/rego" - "github.com/aquasecurity/trivy/pkg/iac/scan" -) - -func Test_BasicScan(t *testing.T) { - - fs := testutil.CreateFS(t, map[string]string{ - "/code/data.json": `{ "x": { "y": 123, "z": ["a", "b", "c"]}}`, - "/rules/rule.rego": `package builtin.json.lol - -__rego_metadata__ := { - "id": "ABC123", - "avd_id": "AVD-AB-0123", - "title": "title", - "short_code": "short", - "severity": "CRITICAL", - "type": "JSON Check", - "description": "description", - "recommended_actions": "actions", - "url": "https://example.com", -} - -__rego_input__ := { - "combine": false, - "selector": [{"type": "json"}], -} - -deny[res] { - input.x.y == 123 - res := { - "msg": "oh no", - "startline": 1, - "endline": 2, - } -} - -`, - }) - - scanner := NewScanner(rego.WithPolicyDirs("rules")) - - results, err := scanner.ScanFS(context.TODO(), fs, "code") - require.NoError(t, err) - - require.Len(t, results.GetFailed(), 1) - - assert.Equal(t, scan.Rule{ - AVDID: "AVD-AB-0123", - Aliases: []string{"ABC123"}, - ShortCode: "short", - Summary: "title", - Explanation: "description", - Impact: "", - Resolution: "actions", - Provider: "json", - Service: "general", - Links: []string{"https://example.com"}, - Severity: "CRITICAL", - Terraform: &scan.EngineMetadata{}, - CloudFormation: &scan.EngineMetadata{}, - CustomChecks: scan.CustomChecks{ - Terraform: (*scan.TerraformCustomCheck)(nil), - }, - RegoPackage: "data.builtin.json.lol", - Frameworks: map[framework.Framework][]string{ - framework.Default: {}, - }, - }, results.GetFailed()[0].Rule()) -} diff --git a/pkg/iac/scanners/toml/parser/parser.go b/pkg/iac/scanners/toml/parser/parser.go deleted file mode 100644 index 95444389d74d..000000000000 --- a/pkg/iac/scanners/toml/parser/parser.go +++ /dev/null @@ -1,65 +0,0 @@ -package parser - -import ( - "context" - "io/fs" - "path/filepath" - - "github.com/BurntSushi/toml" - - "github.com/aquasecurity/trivy/pkg/log" -) - -type Parser struct { - logger *log.Logger -} - -// New creates a new parser -func New() *Parser { - return &Parser{ - logger: log.WithPrefix("toml parser"), - } -} - -func (p *Parser) ParseFS(ctx context.Context, target fs.FS, path string) (map[string]any, error) { - - files := make(map[string]any) - if err := fs.WalkDir(target, filepath.ToSlash(path), func(path string, entry fs.DirEntry, err error) error { - select { - case <-ctx.Done(): - return ctx.Err() - default: - } - if err != nil { - return err - } - if entry.IsDir() { - return nil - } - - df, err := p.ParseFile(ctx, target, path) - if err != nil { - p.logger.Error("Parse error", log.FilePath(path), log.Err(err)) - return nil - } - files[path] = df - return nil - }); err != nil { - return nil, err - } - return files, nil -} - -// ParseFile parses toml content from the provided filesystem path. -func (p *Parser) ParseFile(_ context.Context, fsys fs.FS, path string) (any, error) { - f, err := fsys.Open(filepath.ToSlash(path)) - if err != nil { - return nil, err - } - defer func() { _ = f.Close() }() - var target any - if _, err := toml.NewDecoder(f).Decode(&target); err != nil { - return nil, err - } - return target, nil -} diff --git a/pkg/iac/scanners/toml/parser/parser_test.go b/pkg/iac/scanners/toml/parser/parser_test.go deleted file mode 100644 index 1c9e9bdc341e..000000000000 --- a/pkg/iac/scanners/toml/parser/parser_test.go +++ /dev/null @@ -1,55 +0,0 @@ -package parser - -import ( - "context" - "testing" - - "github.com/liamg/memoryfs" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func Test_Parser(t *testing.T) { - input := ` -[x] -y = 123 -z = ["a", "b", "c"] -` - - memfs := memoryfs.New() - err := memfs.WriteFile("something.yaml", []byte(input), 0644) - require.NoError(t, err) - - data, err := New().ParseFile(context.TODO(), memfs, "something.yaml") - require.NoError(t, err) - - msi, ok := data.(map[string]any) - require.True(t, ok) - - xObj, ok := msi["x"] - require.True(t, ok) - - xMsi, ok := xObj.(map[string]any) - require.True(t, ok) - - yRaw, ok := xMsi["y"] - require.True(t, ok) - - y, ok := yRaw.(int64) - require.True(t, ok) - - assert.Equal(t, int64(123), y) - - zRaw, ok := xMsi["z"] - require.True(t, ok) - - z, ok := zRaw.([]any) - require.True(t, ok) - - require.Len(t, z, 3) - - assert.Equal(t, "a", z[0]) - assert.Equal(t, "b", z[1]) - assert.Equal(t, "c", z[2]) - -} diff --git a/pkg/iac/scanners/toml/scanner.go b/pkg/iac/scanners/toml/scanner.go deleted file mode 100644 index 216d0b1f9697..000000000000 --- a/pkg/iac/scanners/toml/scanner.go +++ /dev/null @@ -1,111 +0,0 @@ -package toml - -import ( - "context" - "io/fs" - "sync" - - "github.com/aquasecurity/trivy/pkg/iac/framework" - "github.com/aquasecurity/trivy/pkg/iac/rego" - "github.com/aquasecurity/trivy/pkg/iac/scan" - "github.com/aquasecurity/trivy/pkg/iac/scanners/options" - "github.com/aquasecurity/trivy/pkg/iac/scanners/toml/parser" - "github.com/aquasecurity/trivy/pkg/iac/types" - "github.com/aquasecurity/trivy/pkg/log" -) - -var _ options.ConfigurableScanner = (*Scanner)(nil) - -type Scanner struct { - mu sync.Mutex - logger *log.Logger - options []options.ScannerOption - parser *parser.Parser - regoScanner *rego.Scanner -} - -func (s *Scanner) SetIncludeDeprecatedChecks(bool) {} -func (s *Scanner) SetRegoOnly(bool) {} -func (s *Scanner) SetFrameworks(frameworks []framework.Framework) {} - -func (s *Scanner) Name() string { - return "TOML" -} - -func NewScanner(opts ...options.ScannerOption) *Scanner { - s := &Scanner{ - options: opts, - logger: log.WithPrefix("toml scanner"), - } - for _, opt := range opts { - opt(s) - } - s.parser = parser.New() - return s -} - -func (s *Scanner) ScanFS(ctx context.Context, fsys fs.FS, path string) (scan.Results, error) { - - files, err := s.parser.ParseFS(ctx, fsys, path) - if err != nil { - return nil, err - } - - if len(files) == 0 { - return nil, nil - } - - var inputs []rego.Input - for path, file := range files { - inputs = append(inputs, rego.Input{ - Path: path, - Contents: file, - FS: fsys, - }) - } - - results, err := s.scanRego(ctx, fsys, inputs...) - if err != nil { - return nil, err - } - return results, nil -} - -func (s *Scanner) ScanFile(ctx context.Context, fsys fs.FS, path string) (scan.Results, error) { - parsed, err := s.parser.ParseFile(ctx, fsys, path) - if err != nil { - return nil, err - } - s.logger.Debug("Scanning", log.FilePath(path)) - return s.scanRego(ctx, fsys, rego.Input{ - Path: path, - Contents: parsed, - }) -} - -func (s *Scanner) initRegoScanner(srcFS fs.FS) (*rego.Scanner, error) { - s.mu.Lock() - defer s.mu.Unlock() - if s.regoScanner != nil { - return s.regoScanner, nil - } - regoScanner := rego.NewScanner(types.SourceTOML, s.options...) - if err := regoScanner.LoadPolicies(srcFS); err != nil { - return nil, err - } - s.regoScanner = regoScanner - return regoScanner, nil -} - -func (s *Scanner) scanRego(ctx context.Context, srcFS fs.FS, inputs ...rego.Input) (scan.Results, error) { - regoScanner, err := s.initRegoScanner(srcFS) - if err != nil { - return nil, err - } - results, err := regoScanner.ScanInput(ctx, inputs...) - if err != nil { - return nil, err - } - results.SetSourceAndFilesystem("", srcFS, false) - return results, nil -} diff --git a/pkg/iac/scanners/toml/scanner_test.go b/pkg/iac/scanners/toml/scanner_test.go deleted file mode 100644 index ea5819448288..000000000000 --- a/pkg/iac/scanners/toml/scanner_test.go +++ /dev/null @@ -1,85 +0,0 @@ -package toml - -import ( - "context" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/aquasecurity/trivy/internal/testutil" - "github.com/aquasecurity/trivy/pkg/iac/framework" - "github.com/aquasecurity/trivy/pkg/iac/rego" - "github.com/aquasecurity/trivy/pkg/iac/scan" -) - -func Test_BasicScan(t *testing.T) { - - fs := testutil.CreateFS(t, map[string]string{ - "/code/code.toml": ` -[x] -y = 123 -z = ["a", "b", "c"] -`, - "/rules/rule.rego": `package builtin.toml.lol - -__rego_metadata__ := { - "id": "ABC123", - "avd_id": "AVD-AB-0123", - "title": "title", - "short_code": "short", - "severity": "CRITICAL", - "type": "TOML Check", - "description": "description", - "recommended_actions": "actions", - "url": "https://example.com", -} - -__rego_input__ := { - "combine": false, - "selector": [{"type": "toml"}], -} - -deny[res] { - input.x.y == 123 - res := { - "msg": "oh no", - "startline": 1, - "endline": 2, - } -} - -`, - }) - - scanner := NewScanner(rego.WithPolicyDirs("rules")) - - results, err := scanner.ScanFS(context.TODO(), fs, "code") - require.NoError(t, err) - - require.Len(t, results.GetFailed(), 1) - - assert.Equal(t, scan.Rule{ - AVDID: "AVD-AB-0123", - Aliases: []string{"ABC123"}, - ShortCode: "short", - Summary: "title", - Explanation: "description", - Impact: "", - Resolution: "actions", - Provider: "toml", - Service: "general", - Links: []string{"https://example.com"}, - Severity: "CRITICAL", - Terraform: &scan.EngineMetadata{}, - CloudFormation: &scan.EngineMetadata{}, - CustomChecks: scan.CustomChecks{ - Terraform: (*scan.TerraformCustomCheck)(nil)}, - RegoPackage: "data.builtin.toml.lol", - Frameworks: map[framework.Framework][]string{ - framework.Default: {}, - }, - }, - results.GetFailed()[0].Rule(), - ) -} diff --git a/pkg/iac/scanners/yaml/parser/parser.go b/pkg/iac/scanners/yaml/parser/parser.go deleted file mode 100644 index 9b1f026ae248..000000000000 --- a/pkg/iac/scanners/yaml/parser/parser.go +++ /dev/null @@ -1,86 +0,0 @@ -package parser - -import ( - "bytes" - "context" - "io" - "io/fs" - "path/filepath" - - "gopkg.in/yaml.v3" - - "github.com/aquasecurity/trivy/pkg/log" -) - -type Parser struct { - logger *log.Logger -} - -// New creates a new YAML parser -func New() *Parser { - return &Parser{ - logger: log.WithPrefix("yaml parser"), - } -} - -func (p *Parser) ParseFS(ctx context.Context, target fs.FS, path string) (map[string][]any, error) { - - files := make(map[string][]any) - if err := fs.WalkDir(target, filepath.ToSlash(path), func(path string, entry fs.DirEntry, err error) error { - - select { - case <-ctx.Done(): - return ctx.Err() - default: - } - if err != nil { - return err - } - if entry.IsDir() { - return nil - } - - df, err := p.ParseFile(ctx, target, path) - if err != nil { - p.logger.Error("Parse error", log.FilePath(path), log.Err(err)) - return nil - } - files[path] = df - return nil - }); err != nil { - return nil, err - } - return files, nil -} - -// ParseFile parses yaml content from the provided filesystem path. -func (p *Parser) ParseFile(_ context.Context, fsys fs.FS, path string) ([]any, error) { - f, err := fsys.Open(filepath.ToSlash(path)) - if err != nil { - return nil, err - } - defer func() { _ = f.Close() }() - - contents, err := io.ReadAll(f) - if err != nil { - return nil, err - } - - var results []any - - marker := []byte("\n---\n") - altMarker := []byte("\r\n---\r\n") - if bytes.Contains(contents, altMarker) { - marker = altMarker - } - - for _, partial := range bytes.Split(contents, marker) { - var target any - if err := yaml.Unmarshal(partial, &target); err != nil { - return nil, err - } - results = append(results, target) - } - - return results, nil -} diff --git a/pkg/iac/scanners/yaml/parser/parser_test.go b/pkg/iac/scanners/yaml/parser/parser_test.go deleted file mode 100644 index f7817d5990fa..000000000000 --- a/pkg/iac/scanners/yaml/parser/parser_test.go +++ /dev/null @@ -1,150 +0,0 @@ -package parser - -import ( - "context" - "testing" - - "github.com/liamg/memoryfs" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func Test_Parser(t *testing.T) { - input := `--- -x: - y: 123 - z: - - a - - b - - c -` - - memfs := memoryfs.New() - err := memfs.WriteFile("something.yaml", []byte(input), 0644) - require.NoError(t, err) - - data, err := New().ParseFile(context.TODO(), memfs, "something.yaml") - require.NoError(t, err) - - assert.Len(t, data, 1) - - msi, ok := data[0].(map[string]any) - require.True(t, ok) - - xObj, ok := msi["x"] - require.True(t, ok) - - xMsi, ok := xObj.(map[string]any) - require.True(t, ok) - - yRaw, ok := xMsi["y"] - require.True(t, ok) - - y, ok := yRaw.(int) - require.True(t, ok) - - assert.Equal(t, 123, y) - - zRaw, ok := xMsi["z"] - require.True(t, ok) - - z, ok := zRaw.([]any) - require.True(t, ok) - - require.Len(t, z, 3) - - assert.Equal(t, "a", z[0]) - assert.Equal(t, "b", z[1]) - assert.Equal(t, "c", z[2]) - -} - -func Test_Parser_WithSeparatedContent(t *testing.T) { - input := `--- -x: - y: 123 - z: - - a - - b - - c ---- -x: - y: 456 - z: - - x - - y - - z -` - - memfs := memoryfs.New() - err := memfs.WriteFile("something.yaml", []byte(input), 0644) - require.NoError(t, err) - - data, err := New().ParseFile(context.TODO(), memfs, "something.yaml") - require.NoError(t, err) - - assert.Len(t, data, 2) - - { - msi, ok := data[0].(map[string]any) - require.True(t, ok) - - xObj, ok := msi["x"] - require.True(t, ok) - - xMsi, ok := xObj.(map[string]any) - require.True(t, ok) - - yRaw, ok := xMsi["y"] - require.True(t, ok) - - y, ok := yRaw.(int) - require.True(t, ok) - - assert.Equal(t, 123, y) - - zRaw, ok := xMsi["z"] - require.True(t, ok) - - z, ok := zRaw.([]any) - require.True(t, ok) - - require.Len(t, z, 3) - - assert.Equal(t, "a", z[0]) - assert.Equal(t, "b", z[1]) - assert.Equal(t, "c", z[2]) - } - - { - msi, ok := data[1].(map[string]any) - require.True(t, ok) - - xObj, ok := msi["x"] - require.True(t, ok) - - xMsi, ok := xObj.(map[string]any) - require.True(t, ok) - - yRaw, ok := xMsi["y"] - require.True(t, ok) - - y, ok := yRaw.(int) - require.True(t, ok) - - assert.Equal(t, 456, y) - - zRaw, ok := xMsi["z"] - require.True(t, ok) - - z, ok := zRaw.([]any) - require.True(t, ok) - - require.Len(t, z, 3) - - assert.Equal(t, "x", z[0]) - assert.Equal(t, "y", z[1]) - assert.Equal(t, "z", z[2]) - } - -} diff --git a/pkg/iac/scanners/yaml/scanner.go b/pkg/iac/scanners/yaml/scanner.go deleted file mode 100644 index 565d10df1f83..000000000000 --- a/pkg/iac/scanners/yaml/scanner.go +++ /dev/null @@ -1,113 +0,0 @@ -package yaml - -import ( - "context" - "io/fs" - "sync" - - "github.com/aquasecurity/trivy/pkg/iac/framework" - "github.com/aquasecurity/trivy/pkg/iac/rego" - "github.com/aquasecurity/trivy/pkg/iac/scan" - "github.com/aquasecurity/trivy/pkg/iac/scanners/options" - "github.com/aquasecurity/trivy/pkg/iac/scanners/yaml/parser" - "github.com/aquasecurity/trivy/pkg/iac/types" - "github.com/aquasecurity/trivy/pkg/log" -) - -var _ options.ConfigurableScanner = (*Scanner)(nil) - -type Scanner struct { - mu sync.Mutex - options []options.ScannerOption - logger *log.Logger - parser *parser.Parser - regoScanner *rego.Scanner -} - -func (s *Scanner) SetIncludeDeprecatedChecks(bool) {} -func (s *Scanner) SetRegoOnly(bool) {} -func (s *Scanner) SetFrameworks(frameworks []framework.Framework) {} - -func (s *Scanner) Name() string { - return "YAML" -} - -func NewScanner(opts ...options.ScannerOption) *Scanner { - s := &Scanner{ - options: opts, - logger: log.WithPrefix("yaml scanner"), - parser: parser.New(), - } - for _, opt := range opts { - opt(s) - } - return s -} - -func (s *Scanner) ScanFS(ctx context.Context, fsys fs.FS, path string) (scan.Results, error) { - - fileset, err := s.parser.ParseFS(ctx, fsys, path) - if err != nil { - return nil, err - } - - if len(fileset) == 0 { - return nil, nil - } - - var inputs []rego.Input - for path, files := range fileset { - for _, file := range files { - inputs = append(inputs, rego.Input{ - Path: path, - Contents: file, - FS: fsys, - }) - } - } - - results, err := s.scanRego(ctx, fsys, inputs...) - if err != nil { - return nil, err - } - return results, nil -} - -func (s *Scanner) ScanFile(ctx context.Context, fsys fs.FS, path string) (scan.Results, error) { - parsed, err := s.parser.ParseFile(ctx, fsys, path) - if err != nil { - return nil, err - } - s.logger.Debug("Scanning", log.String("path", path)) - return s.scanRego(ctx, fsys, rego.Input{ - Path: path, - Contents: parsed, - }) -} - -func (s *Scanner) initRegoScanner(srcFS fs.FS) (*rego.Scanner, error) { - s.mu.Lock() - defer s.mu.Unlock() - if s.regoScanner != nil { - return s.regoScanner, nil - } - regoScanner := rego.NewScanner(types.SourceYAML, s.options...) - if err := regoScanner.LoadPolicies(srcFS); err != nil { - return nil, err - } - s.regoScanner = regoScanner - return regoScanner, nil -} - -func (s *Scanner) scanRego(ctx context.Context, srcFS fs.FS, inputs ...rego.Input) (scan.Results, error) { - regoScanner, err := s.initRegoScanner(srcFS) - if err != nil { - return nil, err - } - results, err := regoScanner.ScanInput(ctx, inputs...) - if err != nil { - return nil, err - } - results.SetSourceAndFilesystem("", srcFS, false) - return results, nil -} diff --git a/pkg/iac/scanners/yaml/scanner_test.go b/pkg/iac/scanners/yaml/scanner_test.go deleted file mode 100644 index b7c4ec623887..000000000000 --- a/pkg/iac/scanners/yaml/scanner_test.go +++ /dev/null @@ -1,88 +0,0 @@ -package yaml - -import ( - "context" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/aquasecurity/trivy/internal/testutil" - "github.com/aquasecurity/trivy/pkg/iac/framework" - "github.com/aquasecurity/trivy/pkg/iac/rego" - "github.com/aquasecurity/trivy/pkg/iac/scan" -) - -func Test_BasicScan(t *testing.T) { - - fs := testutil.CreateFS(t, map[string]string{ - "/code/data.yaml": `--- -x: - y: 123 - z: - - a - - b - - c -`, - "/rules/rule.rego": `package builtin.yaml.lol - -__rego_metadata__ := { - "id": "ABC123", - "avd_id": "AVD-AB-0123", - "title": "title", - "short_code": "short", - "severity": "CRITICAL", - "type": "YAML Check", - "description": "description", - "recommended_actions": "actions", - "url": "https://example.com", -} - -__rego_input__ := { - "combine": false, - "selector": [{"type": "yaml"}], -} - -deny[res] { - input.x.y == 123 - res := { - "msg": "oh no", - "startline": 1, - "endline": 2, - } -} - -`, - }) - - scanner := NewScanner(rego.WithPolicyDirs("rules")) - - results, err := scanner.ScanFS(context.TODO(), fs, "code") - require.NoError(t, err) - - require.Len(t, results.GetFailed(), 1) - - assert.Equal(t, scan.Rule{ - AVDID: "AVD-AB-0123", - Aliases: []string{"ABC123"}, - ShortCode: "short", - Summary: "title", - Explanation: "description", - Impact: "", - Resolution: "actions", - Provider: "yaml", - Service: "general", - Links: []string{"https://example.com"}, - Severity: "CRITICAL", - Terraform: &scan.EngineMetadata{}, - CloudFormation: &scan.EngineMetadata{}, - CustomChecks: scan.CustomChecks{ - Terraform: (*scan.TerraformCustomCheck)(nil)}, - RegoPackage: "data.builtin.yaml.lol", - Frameworks: map[framework.Framework][]string{ - framework.Default: {}, - }, - }, - results.GetFailed()[0].Rule(), - ) -} diff --git a/pkg/misconf/scanner.go b/pkg/misconf/scanner.go index 7bec3ed6fe14..04fc28bc5296 100644 --- a/pkg/misconf/scanner.go +++ b/pkg/misconf/scanner.go @@ -24,14 +24,13 @@ import ( cfscanner "github.com/aquasecurity/trivy/pkg/iac/scanners/cloudformation" cfparser "github.com/aquasecurity/trivy/pkg/iac/scanners/cloudformation/parser" dfscanner "github.com/aquasecurity/trivy/pkg/iac/scanners/dockerfile" + "github.com/aquasecurity/trivy/pkg/iac/scanners/generic" "github.com/aquasecurity/trivy/pkg/iac/scanners/helm" - jsonscanner "github.com/aquasecurity/trivy/pkg/iac/scanners/json" k8sscanner "github.com/aquasecurity/trivy/pkg/iac/scanners/kubernetes" "github.com/aquasecurity/trivy/pkg/iac/scanners/options" "github.com/aquasecurity/trivy/pkg/iac/scanners/terraform" tfprawscanner "github.com/aquasecurity/trivy/pkg/iac/scanners/terraformplan/snapshot" tfpjsonscanner "github.com/aquasecurity/trivy/pkg/iac/scanners/terraformplan/tfjson" - yamlscanner "github.com/aquasecurity/trivy/pkg/iac/scanners/yaml" "github.com/aquasecurity/trivy/pkg/log" "github.com/aquasecurity/trivy/pkg/mapfs" @@ -118,9 +117,9 @@ func NewScanner(t detection.FileType, opt ScannerOption) (*Scanner, error) { case detection.FileTypeTerraformPlanSnapshot: scanner = tfprawscanner.New(opts...) case detection.FileTypeYAML: - scanner = yamlscanner.NewScanner(opts...) + scanner = generic.NewYamlScanner(opts...) case detection.FileTypeJSON: - scanner = jsonscanner.NewScanner(opts...) + scanner = generic.NewJsonScanner(opts...) default: return nil, xerrors.Errorf("unknown file type: %s", t) }