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 }