github.com/khulnasoft-lab/defsec@v1.0.5-0.20230827010352-5e9f46893d95/cmd/avd_generator/main.go (about)

     1  package main
     2  
     3  import (
     4  	"fmt"
     5  	goast "go/ast"
     6  	"go/parser"
     7  	"go/token"
     8  	"os"
     9  	"path/filepath"
    10  	"strings"
    11  	"text/template"
    12  
    13  	"github.com/khulnasoft-lab/defsec/internal/rules"
    14  	"github.com/khulnasoft-lab/defsec/pkg/framework"
    15  	_ "github.com/khulnasoft-lab/defsec/pkg/rego"
    16  	registered "github.com/khulnasoft-lab/defsec/pkg/rules"
    17  )
    18  
    19  func main() {
    20  	var generateCount int
    21  
    22  	for _, metadata := range registered.GetRegistered(framework.ALL) {
    23  		writeDocsFile(metadata, "avd_docs")
    24  		generateCount++
    25  	}
    26  
    27  	fmt.Printf("\nGenerated %d files in avd_docs\n", generateCount)
    28  }
    29  
    30  // nolint: cyclop
    31  func writeDocsFile(meta rules.RegisteredRule, path string) {
    32  
    33  	tmpl, err := template.New("defsec").Parse(docsMarkdownTemplate)
    34  	if err != nil {
    35  		fail("error occurred creating the template %v\n", err)
    36  	}
    37  
    38  	docpath := filepath.Join(path,
    39  		strings.ToLower(meta.Rule().Provider.ConstName()),
    40  		strings.ToLower(strings.ReplaceAll(meta.Rule().Service, "-", "")),
    41  		meta.Rule().AVDID,
    42  	)
    43  
    44  	if err := os.MkdirAll(docpath, os.ModePerm); err != nil {
    45  		panic(err)
    46  	}
    47  
    48  	file, err := os.Create(filepath.Join(docpath, "docs.md"))
    49  	if err != nil {
    50  		fail("error occurred creating the docs file for %s", docpath)
    51  	}
    52  
    53  	if err := tmpl.Execute(file, meta.Rule()); err != nil {
    54  		fail("error occurred generating the document %v", err)
    55  	}
    56  	fmt.Printf("Generating docs file for policy %s\n", meta.Rule().AVDID)
    57  
    58  	if meta.Rule().Terraform != nil {
    59  		if len(meta.Rule().Terraform.GoodExamples) > 0 || len(meta.Rule().Terraform.Links) > 0 {
    60  			if meta.Rule().RegoPackage != "" { // get examples from file as rego rules don't have embedded
    61  				value, err := GetExampleValueFromFile(meta.Rule().Terraform.GoodExamples[0], "GoodExamples")
    62  				if err != nil {
    63  					fail("error retrieving examples from metadata: %v\n", err)
    64  				}
    65  				meta.Rule().Terraform.GoodExamples = []string{value}
    66  			}
    67  
    68  			tmpl, err := template.New("terraform").Parse(terraformMarkdownTemplate)
    69  			if err != nil {
    70  				fail("error occurred creating the template %v\n", err)
    71  			}
    72  			file, err := os.Create(filepath.Join(docpath, "Terraform.md"))
    73  			if err != nil {
    74  				fail("error occurred creating the Terraform file for %s", docpath)
    75  			}
    76  			defer func() { _ = file.Close() }()
    77  
    78  			if err := tmpl.Execute(file, meta.Rule()); err != nil {
    79  				fail("error occurred generating the document %v", err)
    80  			}
    81  			fmt.Printf("Generating Terraform file for policy %s\n", meta.Rule().AVDID)
    82  		}
    83  	}
    84  
    85  	if meta.Rule().CloudFormation != nil {
    86  		if len(meta.Rule().CloudFormation.GoodExamples) > 0 || len(meta.Rule().CloudFormation.Links) > 0 {
    87  			if meta.Rule().RegoPackage != "" { // get examples from file as rego rules don't have embedded
    88  				value, err := GetExampleValueFromFile(meta.Rule().CloudFormation.GoodExamples[0], "GoodExamples")
    89  				if err != nil {
    90  					fail("error retrieving examples from metadata: %v\n", err)
    91  				}
    92  				meta.Rule().CloudFormation.GoodExamples = []string{value}
    93  			}
    94  
    95  			tmpl, err := template.New("cloudformation").Parse(cloudformationMarkdownTemplate)
    96  			if err != nil {
    97  				fail("error occurred creating the template %v\n", err)
    98  			}
    99  			file, err := os.Create(filepath.Join(docpath, "CloudFormation.md"))
   100  			if err != nil {
   101  				fail("error occurred creating the CloudFormation file for %s", docpath)
   102  			}
   103  			defer func() { _ = file.Close() }()
   104  
   105  			if err := tmpl.Execute(file, meta.Rule()); err != nil {
   106  				fail("error occurred generating the document %v", err)
   107  			}
   108  			fmt.Printf("Generating CloudFormation file for policy %s\n", meta.Rule().AVDID)
   109  		}
   110  	}
   111  }
   112  
   113  func fail(msg string, args ...interface{}) {
   114  	fmt.Printf(msg, args...)
   115  	os.Exit(1)
   116  }
   117  
   118  func GetExampleValueFromFile(filename string, exampleType string) (string, error) {
   119  	f, err := parser.ParseFile(token.NewFileSet(), filename, nil, parser.AllErrors)
   120  	if err != nil {
   121  		return "", err
   122  	}
   123  
   124  	for _, d := range f.Decls {
   125  		switch decl := d.(type) {
   126  		case *goast.GenDecl:
   127  			for _, spec := range decl.Specs {
   128  				switch spec := spec.(type) {
   129  				case *goast.ValueSpec:
   130  					for _, id := range spec.Names {
   131  						switch v := id.Obj.Decl.(*goast.ValueSpec).Values[0].(type) {
   132  						case *goast.CompositeLit:
   133  							value := v.Elts[0].(*goast.BasicLit).Value
   134  							if strings.Contains(id.Name, exampleType) {
   135  								return strings.ReplaceAll(value, "`", ""), nil
   136  							}
   137  						}
   138  					}
   139  				}
   140  			}
   141  		}
   142  	}
   143  	return "", fmt.Errorf("exampleType %s not found in file: %s", exampleType, filename)
   144  }
   145  
   146  var docsMarkdownTemplate = `
   147  {{ .Explanation }}
   148  
   149  ### Impact
   150  {{ if .Impact }}{{ .Impact }}{{ else }}<!-- Add Impact here -->{{ end }}
   151  
   152  <!-- DO NOT CHANGE -->
   153  {{ ` + "`{{ " + `remediationActions ` + "`}}" + `}}
   154  
   155  {{ if .Links }}### Links{{ range .Links }}
   156  - {{ . }}
   157  {{ end}}
   158  {{ end }}
   159  `
   160  
   161  var terraformMarkdownTemplate = `
   162  {{ .Resolution }}
   163  
   164  {{ if .Terraform.GoodExamples }}{{ range .Terraform.GoodExamples }}` + "```hcl" + `{{ . }}
   165  ` + "```" + `
   166  {{ end}}{{ end }}
   167  {{ if .Terraform.Links }}#### Remediation Links{{ range .Terraform.Links }}
   168   - {{ . }}
   169  {{ end}}{{ end }}
   170  `
   171  
   172  var cloudformationMarkdownTemplate = `
   173  {{ .Resolution }}
   174  
   175  {{ if .CloudFormation.GoodExamples }}{{ range .CloudFormation.GoodExamples }}` + "```yaml" + `{{ . }}
   176  ` + "```" + `
   177  {{ end}}{{ end }}
   178  {{ if .CloudFormation.Links }}#### Remediation Links{{ range .CloudFormation.Links }}
   179   - {{ . }}
   180  {{ end}}{{ end }}
   181  `