github.com/khulnasoft-lab/defsec@v1.0.5-0.20230827010352-5e9f46893d95/pkg/scanners/dockerfile/scanner.go (about)

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