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

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