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