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

     1  package terraformplan
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"io"
     7  	"io/fs"
     8  
     9  	doublestar "github.com/bmatcuk/doublestar/v4"
    10  	"github.com/khulnasoft-lab/defsec/pkg/debug"
    11  	"github.com/khulnasoft-lab/defsec/pkg/framework"
    12  	"github.com/khulnasoft-lab/defsec/pkg/scan"
    13  	"github.com/khulnasoft-lab/defsec/pkg/scanners/options"
    14  	terraformScanner "github.com/khulnasoft-lab/defsec/pkg/scanners/terraform"
    15  	"github.com/khulnasoft-lab/defsec/pkg/scanners/terraform/executor"
    16  	"github.com/khulnasoft-lab/defsec/pkg/scanners/terraformplan/parser"
    17  )
    18  
    19  var tfPlanExts = []string{
    20  	"**/*tfplan.json",
    21  	"**/*tf.json",
    22  }
    23  
    24  type Scanner struct {
    25  	parser    parser.Parser
    26  	parserOpt []options.ParserOption
    27  	debug     debug.Logger
    28  
    29  	options                 []options.ScannerOption
    30  	spec                    string
    31  	executorOpt             []executor.Option
    32  	frameworks              []framework.Framework
    33  	loadEmbeddedPolicies    bool
    34  	loadEmbeddedLibraries   bool
    35  	enableEmbeddedLibraries bool
    36  	policyDirs              []string
    37  	policyReaders           []io.Reader
    38  }
    39  
    40  func (s *Scanner) SetUseEmbeddedLibraries(b bool) {
    41  	s.loadEmbeddedLibraries = b
    42  }
    43  
    44  func (s *Scanner) SetSpec(spec string) {
    45  	s.spec = spec
    46  }
    47  
    48  func (s *Scanner) SetRegoOnly(regoOnly bool) {
    49  	s.executorOpt = append(s.executorOpt, executor.OptionWithRegoOnly(regoOnly))
    50  }
    51  
    52  func (s *Scanner) SetFrameworks(frameworks []framework.Framework) {
    53  	s.frameworks = frameworks
    54  }
    55  
    56  func (s *Scanner) SetUseEmbeddedPolicies(b bool) {
    57  	s.loadEmbeddedPolicies = b
    58  }
    59  
    60  func (s *Scanner) SetEmbeddedLibrariesEnabled(enabled bool) {
    61  	s.enableEmbeddedLibraries = enabled
    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.parserOpt = append(s.parserOpt, options.ParserWithSkipRequiredCheck(skip))
    70  }
    71  
    72  func (s *Scanner) SetDebugWriter(writer io.Writer) {
    73  	s.parserOpt = append(s.parserOpt, options.ParserWithDebug(writer))
    74  	s.executorOpt = append(s.executorOpt, executor.OptionWithDebugWriter(writer))
    75  	s.debug = debug.New(writer, "tfplan", "scanner")
    76  }
    77  
    78  func (s *Scanner) SetTraceWriter(_ io.Writer) {
    79  }
    80  
    81  func (s *Scanner) SetPerResultTracingEnabled(_ bool) {
    82  }
    83  
    84  func (s *Scanner) SetPolicyDirs(dirs ...string) {
    85  	s.policyDirs = dirs
    86  }
    87  
    88  func (s *Scanner) SetDataDirs(_ ...string)         {}
    89  func (s *Scanner) SetPolicyNamespaces(_ ...string) {}
    90  
    91  func (s *Scanner) SetPolicyFilesystem(_ fs.FS) {
    92  	// handled by rego when option is passed on
    93  }
    94  
    95  func (s *Scanner) SetDataFilesystem(_ fs.FS) {
    96  	// handled by rego when option is passed on
    97  }
    98  func (s *Scanner) SetRegoErrorLimit(_ int) {}
    99  
   100  func (s *Scanner) Name() string {
   101  	return "Terraform Plan"
   102  }
   103  
   104  func (s *Scanner) ScanFS(ctx context.Context, inputFS fs.FS, dir string) (scan.Results, error) {
   105  	var filesFound []string
   106  
   107  	for _, ext := range tfPlanExts {
   108  		files, err := doublestar.Glob(inputFS, ext, doublestar.WithFilesOnly())
   109  		if err != nil {
   110  			return nil, fmt.Errorf("unable to scan for terraform plan files: %w", err)
   111  		}
   112  		filesFound = append(filesFound, files...)
   113  	}
   114  
   115  	var results scan.Results
   116  	for _, f := range filesFound {
   117  		res, err := s.ScanFile(f, inputFS)
   118  		if err != nil {
   119  			return nil, err
   120  		}
   121  		results = append(results, res...)
   122  	}
   123  	return results, nil
   124  }
   125  
   126  func New(options ...options.ScannerOption) *Scanner {
   127  	scanner := &Scanner{
   128  		parser:  *parser.New(),
   129  		options: options,
   130  	}
   131  	for _, o := range options {
   132  		o(scanner)
   133  	}
   134  	return scanner
   135  }
   136  
   137  func (s *Scanner) ScanFile(filepath string, fs fs.FS) (scan.Results, error) {
   138  
   139  	s.debug.Log("Scanning file %s", filepath)
   140  	file, err := fs.Open(filepath)
   141  	if err != nil {
   142  		return nil, err
   143  	}
   144  	return s.Scan(file)
   145  
   146  }
   147  
   148  func (s *Scanner) Scan(reader io.Reader) (scan.Results, error) {
   149  
   150  	planFile, err := s.parser.Parse(reader)
   151  	if err != nil {
   152  		return nil, err
   153  	}
   154  
   155  	planFS, err := planFile.ToFS()
   156  	if err != nil {
   157  		return nil, err
   158  	}
   159  
   160  	scanner := terraformScanner.New(s.options...)
   161  	for _, o := range s.options {
   162  		o(scanner)
   163  	}
   164  
   165  	return scanner.ScanFS(context.TODO(), planFS, ".")
   166  }