github.com/aquasecurity/trivy-iac@v0.8.1-0.20240127024015-3d8e412cf0ab/pkg/scanners/yaml/parser/parser.go (about) 1 package parser 2 3 import ( 4 "bytes" 5 "context" 6 "io" 7 "io/fs" 8 "path/filepath" 9 "strings" 10 11 "github.com/aquasecurity/defsec/pkg/debug" 12 "github.com/aquasecurity/defsec/pkg/scanners/options" 13 "github.com/aquasecurity/trivy-iac/pkg/detection" 14 "gopkg.in/yaml.v3" 15 ) 16 17 var _ options.ConfigurableParser = (*Parser)(nil) 18 19 type Parser struct { 20 debug debug.Logger 21 skipRequired bool 22 } 23 24 func (p *Parser) SetDebugWriter(writer io.Writer) { 25 p.debug = debug.New(writer, "yaml", "parser") 26 } 27 28 func (p *Parser) SetSkipRequiredCheck(b bool) { 29 p.skipRequired = b 30 } 31 32 // New creates a new parser 33 func New(opts ...options.ParserOption) *Parser { 34 p := &Parser{} 35 for _, opt := range opts { 36 opt(p) 37 } 38 return p 39 } 40 41 func (p *Parser) ParseFS(ctx context.Context, target fs.FS, path string) (map[string][]interface{}, error) { 42 43 files := make(map[string][]interface{}) 44 if err := fs.WalkDir(target, filepath.ToSlash(path), func(path string, entry fs.DirEntry, err error) error { 45 select { 46 case <-ctx.Done(): 47 return ctx.Err() 48 default: 49 } 50 if err != nil { 51 return err 52 } 53 if entry.IsDir() { 54 return nil 55 } 56 if !p.Required(path) { 57 return nil 58 } 59 df, err := p.ParseFile(ctx, target, path) 60 if err != nil { 61 p.debug.Log("Parse error in '%s': %s", path, err) 62 return nil 63 } 64 files[path] = df 65 return nil 66 }); err != nil { 67 return nil, err 68 } 69 return files, nil 70 } 71 72 // ParseFile parses yaml content from the provided filesystem path. 73 func (p *Parser) ParseFile(_ context.Context, fs fs.FS, path string) ([]interface{}, error) { 74 f, err := fs.Open(filepath.ToSlash(path)) 75 if err != nil { 76 return nil, err 77 } 78 defer func() { _ = f.Close() }() 79 80 contents, err := io.ReadAll(f) 81 if err != nil { 82 return nil, err 83 } 84 85 var results []interface{} 86 87 marker := "\n---\n" 88 altMarker := "\r\n---\r\n" 89 if bytes.Contains(contents, []byte(altMarker)) { 90 marker = altMarker 91 } 92 93 for _, partial := range strings.Split(string(contents), marker) { 94 var target interface{} 95 if err := yaml.Unmarshal([]byte(partial), &target); err != nil { 96 return nil, err 97 } 98 results = append(results, target) 99 } 100 101 return results, nil 102 } 103 104 func (p *Parser) Required(path string) bool { 105 if p.skipRequired { 106 return true 107 } 108 return detection.IsType(path, nil, detection.FileTypeYAML) 109 }