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