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 `