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