github.com/aquasecurity/trivy-iac@v0.8.1-0.20240127024015-3d8e412cf0ab/pkg/scanners/yaml/scanner.go (about)

     1  package yaml
     2  
     3  import (
     4  	"context"
     5  	"io"
     6  	"io/fs"
     7  	"sync"
     8  
     9  	"github.com/aquasecurity/defsec/pkg/debug"
    10  	"github.com/aquasecurity/defsec/pkg/framework"
    11  	"github.com/aquasecurity/defsec/pkg/rego"
    12  	"github.com/aquasecurity/defsec/pkg/scan"
    13  	"github.com/aquasecurity/defsec/pkg/scanners/options"
    14  	"github.com/aquasecurity/defsec/pkg/types"
    15  	"github.com/aquasecurity/trivy-iac/pkg/scanners/yaml/parser"
    16  )
    17  
    18  var _ options.ConfigurableScanner = (*Scanner)(nil)
    19  
    20  type Scanner struct {
    21  	options       []options.ScannerOption
    22  	debug         debug.Logger
    23  	policyDirs    []string
    24  	policyReaders []io.Reader
    25  	parser        *parser.Parser
    26  	regoScanner   *rego.Scanner
    27  	skipRequired  bool
    28  	sync.Mutex
    29  	frameworks            []framework.Framework
    30  	spec                  string
    31  	loadEmbeddedLibraries bool
    32  	loadEmbeddedPolicies  bool
    33  }
    34  
    35  func (s *Scanner) SetRegoOnly(bool) {}
    36  
    37  func (s *Scanner) SetFrameworks(frameworks []framework.Framework) {
    38  	s.frameworks = frameworks
    39  }
    40  
    41  func (s *Scanner) SetSpec(spec string) {
    42  	s.spec = spec
    43  }
    44  
    45  func (s *Scanner) SetUseEmbeddedPolicies(b bool) {
    46  	s.loadEmbeddedPolicies = b
    47  }
    48  
    49  func (s *Scanner) SetUseEmbeddedLibraries(b bool) {
    50  	s.loadEmbeddedLibraries = b
    51  }
    52  
    53  func (s *Scanner) Name() string {
    54  	return "YAML"
    55  }
    56  
    57  func (s *Scanner) SetPolicyReaders(readers []io.Reader) {
    58  	s.policyReaders = readers
    59  }
    60  
    61  func (s *Scanner) SetSkipRequiredCheck(skip bool) {
    62  	s.skipRequired = skip
    63  }
    64  
    65  func (s *Scanner) SetDebugWriter(writer io.Writer) {
    66  	s.debug = debug.New(writer, "yaml", "scanner")
    67  }
    68  
    69  func (s *Scanner) SetTraceWriter(_ io.Writer)        {}
    70  func (s *Scanner) SetPerResultTracingEnabled(_ bool) {}
    71  
    72  func (s *Scanner) SetPolicyDirs(dirs ...string) {
    73  	s.policyDirs = dirs
    74  }
    75  
    76  func (s *Scanner) SetDataDirs(_ ...string)         {}
    77  func (s *Scanner) SetPolicyNamespaces(_ ...string) {}
    78  
    79  func (s *Scanner) SetPolicyFilesystem(_ fs.FS) {
    80  	// handled by rego when option is passed on
    81  }
    82  func (s *Scanner) SetDataFilesystem(_ fs.FS) {
    83  	// handled by rego when option is passed on
    84  }
    85  func (s *Scanner) SetRegoErrorLimit(_ int) {}
    86  
    87  func NewScanner(opts ...options.ScannerOption) *Scanner {
    88  	s := &Scanner{
    89  		options: opts,
    90  	}
    91  	for _, opt := range opts {
    92  		opt(s)
    93  	}
    94  	s.parser = parser.New(options.ParserWithSkipRequiredCheck(s.skipRequired))
    95  	return s
    96  }
    97  
    98  func (s *Scanner) ScanFS(ctx context.Context, fs fs.FS, path string) (scan.Results, error) {
    99  
   100  	fileset, err := s.parser.ParseFS(ctx, fs, path)
   101  	if err != nil {
   102  		return nil, err
   103  	}
   104  
   105  	if len(fileset) == 0 {
   106  		return nil, nil
   107  	}
   108  
   109  	var inputs []rego.Input
   110  	for path, files := range fileset {
   111  		for _, file := range files {
   112  			inputs = append(inputs, rego.Input{
   113  				Path:     path,
   114  				Contents: file,
   115  				FS:       fs,
   116  			})
   117  		}
   118  	}
   119  
   120  	results, err := s.scanRego(ctx, fs, inputs...)
   121  	if err != nil {
   122  		return nil, err
   123  	}
   124  	return results, nil
   125  }
   126  
   127  func (s *Scanner) ScanFile(ctx context.Context, fs fs.FS, path string) (scan.Results, error) {
   128  	parsed, err := s.parser.ParseFile(ctx, fs, path)
   129  	if err != nil {
   130  		return nil, err
   131  	}
   132  	s.debug.Log("Scanning %s...", path)
   133  	return s.scanRego(ctx, fs, rego.Input{
   134  		Path:     path,
   135  		Contents: parsed,
   136  	})
   137  }
   138  
   139  func (s *Scanner) initRegoScanner(srcFS fs.FS) (*rego.Scanner, error) {
   140  	s.Lock()
   141  	defer s.Unlock()
   142  	if s.regoScanner != nil {
   143  		return s.regoScanner, nil
   144  	}
   145  	regoScanner := rego.NewScanner(types.SourceYAML, s.options...)
   146  	regoScanner.SetParentDebugLogger(s.debug)
   147  	if err := regoScanner.LoadPolicies(s.loadEmbeddedLibraries, s.loadEmbeddedPolicies, srcFS, s.policyDirs, s.policyReaders); err != nil {
   148  		return nil, err
   149  	}
   150  	s.regoScanner = regoScanner
   151  	return regoScanner, nil
   152  }
   153  
   154  func (s *Scanner) scanRego(ctx context.Context, srcFS fs.FS, inputs ...rego.Input) (scan.Results, error) {
   155  	regoScanner, err := s.initRegoScanner(srcFS)
   156  	if err != nil {
   157  		return nil, err
   158  	}
   159  	results, err := regoScanner.ScanInput(ctx, inputs...)
   160  	if err != nil {
   161  		return nil, err
   162  	}
   163  	results.SetSourceAndFilesystem("", srcFS, false)
   164  	return results, nil
   165  }