github.com/devseccon/trivy@v0.47.1-0.20231123133102-bd902a0bd996/pkg/report/template_test.go (about) 1 package report_test 2 3 import ( 4 "bytes" 5 "os" 6 "testing" 7 "time" 8 9 "github.com/stretchr/testify/assert" 10 "github.com/stretchr/testify/require" 11 12 dbTypes "github.com/aquasecurity/trivy-db/pkg/types" 13 "github.com/devseccon/trivy/pkg/clock" 14 "github.com/devseccon/trivy/pkg/report" 15 "github.com/devseccon/trivy/pkg/types" 16 ) 17 18 func TestReportWriter_Template(t *testing.T) { 19 testCases := []struct { 20 name string 21 detectedVulns []types.DetectedVulnerability 22 template string 23 expected string 24 }{ 25 { 26 name: "happy path", 27 detectedVulns: []types.DetectedVulnerability{ 28 { 29 VulnerabilityID: "CVE-2019-0000", 30 PkgName: "foo", 31 Vulnerability: dbTypes.Vulnerability{ 32 Severity: dbTypes.SeverityHigh.String(), 33 VendorSeverity: map[dbTypes.SourceID]dbTypes.Severity{ 34 "nvd": 1, 35 }, 36 }, 37 }, 38 { 39 VulnerabilityID: "CVE-2019-0000", 40 PkgName: "bar", 41 Vulnerability: dbTypes.Vulnerability{ 42 Severity: dbTypes.SeverityHigh.String()}, 43 }, 44 { 45 VulnerabilityID: "CVE-2019-0001", 46 PkgName: "baz", 47 Vulnerability: dbTypes.Vulnerability{ 48 Severity: dbTypes.SeverityCritical.String(), 49 }, 50 }, 51 }, 52 template: "{{ range . }}{{ range .Vulnerabilities}}{{ println .VulnerabilityID .Severity }}{{ end }}{{ end }}", 53 expected: "CVE-2019-0000 HIGH\nCVE-2019-0000 HIGH\nCVE-2019-0001 CRITICAL\n", 54 }, 55 { 56 name: "happy path", 57 detectedVulns: []types.DetectedVulnerability{ 58 { 59 VulnerabilityID: "123", 60 PkgName: `foo \ test`, 61 InstalledVersion: "1.2.3", 62 FixedVersion: "3.4.5", 63 Vulnerability: dbTypes.Vulnerability{ 64 Title: `gcc: POWER9 "DARN" RNG intrinsic produces repeated output`, 65 Description: `curl version curl \X 7.20.0 to and including curl 7.59.0 contains a CWE-126: Buffer Over-read vulnerability in denial of service that can result in curl can be tricked into reading data beyond the end of a heap based buffer used to store downloaded RTSP content.. This vulnerability appears to have been fixed in curl < 7.20.0 and curl >= 7.60.0.`, 66 Severity: "HIGH", 67 }, 68 }, 69 }, 70 template: `<testsuites> 71 {{- range . -}} 72 {{- $failures := len .Vulnerabilities }} 73 <testsuite tests="{{ $failures }}" failures="{{ $failures }}" name="{{ .Target }}" errors="0" skipped="0" time=""> 74 {{- if not (eq .Type "") }} 75 <properties> 76 <property name="type" value="{{ .Type }}"></property> 77 </properties> 78 {{- end -}} 79 {{ range .Vulnerabilities }} 80 <testcase classname="{{ .PkgName }}-{{ .InstalledVersion }}" name="[{{ .Vulnerability.Severity }}] {{ .VulnerabilityID }}" time=""> 81 <failure message="{{ escapeXML .Title }}" type="description">{{ escapeXML .Description }}</failure> 82 </testcase> 83 {{- end }} 84 </testsuite> 85 {{- end }} 86 </testsuites>`, 87 88 expected: `<testsuites> 89 <testsuite tests="1" failures="1" name="foojunit" errors="0" skipped="0" time=""> 90 <properties> 91 <property name="type" value="test"></property> 92 </properties> 93 <testcase classname="foo \ test-1.2.3" name="[HIGH] 123" time=""> 94 <failure message="gcc: POWER9 "DARN" RNG intrinsic produces repeated output" type="description">curl version curl \X 7.20.0 to and including curl 7.59.0 contains a CWE-126: Buffer Over-read vulnerability in denial of service that can result in curl can be tricked into reading data beyond the end of a heap based buffer used to store downloaded RTSP content.. This vulnerability appears to have been fixed in curl < 7.20.0 and curl >= 7.60.0.</failure> 95 </testcase> 96 </testsuite> 97 </testsuites>`, 98 }, 99 { 100 name: "happy path with/without period description should return with period", 101 detectedVulns: []types.DetectedVulnerability{ 102 { 103 VulnerabilityID: "CVE-2019-0000", 104 PkgName: "foo", 105 Vulnerability: dbTypes.Vulnerability{ 106 Description: "without period", 107 }, 108 }, 109 { 110 VulnerabilityID: "CVE-2019-0000", 111 PkgName: "bar", 112 Vulnerability: dbTypes.Vulnerability{ 113 Description: "with period.", 114 }, 115 }, 116 { 117 VulnerabilityID: "CVE-2019-0000", 118 PkgName: "bar", 119 Vulnerability: dbTypes.Vulnerability{ 120 Description: `with period and unescaped string curl: Use-after-free when closing 'easy' handle in Curl_close().`, 121 }, 122 }, 123 }, 124 template: `{{ range . }}{{ range .Vulnerabilities}}{{.VulnerabilityID}} {{ endWithPeriod (escapeString .Description) | printf "%q" }}{{ end }}{{ end }}`, 125 expected: `CVE-2019-0000 "without period."CVE-2019-0000 "with period."CVE-2019-0000 "with period and unescaped string curl: Use-after-free when closing 'easy' handle in Curl_close()."`, 126 }, 127 { 128 name: "Calculate using sprig", 129 detectedVulns: []types.DetectedVulnerability{ 130 { 131 VulnerabilityID: "CVE-2019-0000", 132 PkgName: "foo", 133 Vulnerability: dbTypes.Vulnerability{ 134 Description: "without period", 135 Severity: dbTypes.SeverityCritical.String(), 136 }, 137 }, 138 { 139 VulnerabilityID: "CVE-2019-0000", 140 PkgName: "bar", 141 Vulnerability: dbTypes.Vulnerability{ 142 Description: "with period.", 143 Severity: dbTypes.SeverityCritical.String(), 144 }, 145 }, 146 { 147 VulnerabilityID: "CVE-2019-0000", 148 PkgName: "bar", 149 Vulnerability: dbTypes.Vulnerability{ 150 Description: `with period and unescaped string curl: Use-after-free when closing 'easy' handle in Curl_close().`, 151 Severity: dbTypes.SeverityHigh.String(), 152 }, 153 }, 154 }, 155 template: `{{ $high := 0 }}{{ $critical := 0 }}{{ range . }}{{ range .Vulnerabilities}}{{ if eq .Severity "HIGH" }}{{ $high = add $high 1 }}{{ end }}{{ if eq .Severity "CRITICAL" }}{{ $critical = add $critical 1 }}{{ end }}{{ end }}Critical: {{ $critical }}, High: {{ $high }}{{ end }}`, 156 expected: `Critical: 2, High: 1`, 157 }, 158 { 159 name: "happy path: env var parsing", 160 detectedVulns: []types.DetectedVulnerability{}, 161 template: `{{ lower (env "AWS_ACCOUNT_ID") }}`, 162 expected: `123456789012`, 163 }, 164 } 165 for _, tc := range testCases { 166 t.Run(tc.name, func(t *testing.T) { 167 clock.SetFakeTime(t, time.Date(2020, 8, 10, 7, 28, 17, 958601, time.UTC)) 168 169 os.Setenv("AWS_ACCOUNT_ID", "123456789012") 170 got := bytes.Buffer{} 171 inputReport := types.Report{ 172 Results: types.Results{ 173 { 174 Target: "foojunit", 175 Type: "test", 176 Vulnerabilities: tc.detectedVulns, 177 }, 178 }, 179 } 180 181 w, err := report.NewTemplateWriter(&got, tc.template) 182 require.NoError(t, err) 183 err = w.Write(inputReport) 184 assert.NoError(t, err) 185 assert.Equal(t, tc.expected, got.String()) 186 }) 187 } 188 }