Skip to content

Commit

Permalink
Merge pull request #25 from adevinta/user-friendly-printer-cr
Browse files Browse the repository at this point in the history
internal/report: simplify human-readable printer
  • Loading branch information
jroimartin authored Oct 24, 2023
2 parents 5ec3b56 + 5099064 commit f5c4a34
Show file tree
Hide file tree
Showing 5 changed files with 171 additions and 155 deletions.
99 changes: 33 additions & 66 deletions internal/report/humanprinter.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,89 +17,56 @@ import (
// humanPrinter represents a human-readable report printer.
type humanPrinter struct{}

// colorFuncs stores common function to colorize texts.
var commonFuncs = template.FuncMap{
"magenta": color.New(color.FgMagenta).SprintfFunc(),
"red": color.New(color.FgRed).SprintfFunc(),
"yellow": color.New(color.FgYellow).SprintfFunc(),
"cyan": color.New(color.FgCyan).SprintfFunc(),
"bold": color.New(color.Bold).SprintfFunc(),
"upper": strings.ToUpper,
}
var (
//go:embed templates/human.tmpl
humanReport string

// Print renders the scan results in human-readable format.
func (prn humanPrinter) Print(w io.Writer, vulns []vulnerability, sum summary) error {
if err := printSummary(w, sum); err != nil {
return fmt.Errorf("print summary: %w", err)
}
if len(vulns) > 0 {
_, err := fmt.Fprint(w, "\nVulnerabilities details:\n")
if err != nil {
return fmt.Errorf("print vulnerability details: %w", err)
}
}
for _, v := range vulns {
if err := printVulnerability(w, v); err != nil {
return fmt.Errorf("print vulnerability: %w", err)
}
// humanTmplFuncs stores the functions called from the
// template used to render the human-readable report.
humanTmplFuncs = template.FuncMap{
"magenta": color.New(color.FgMagenta).SprintfFunc(),
"red": color.New(color.FgRed).SprintfFunc(),
"yellow": color.New(color.FgYellow).SprintfFunc(),
"cyan": color.New(color.FgCyan).SprintfFunc(),
"bold": color.New(color.Bold).SprintfFunc(),
"underline": color.New(color.Underline).SprintfFunc(),
"upper": strings.ToUpper,
"trim": strings.TrimSpace,
}
return nil
}

//go:embed templates/humansum.tmpl
var humanSummary string
// humanTmpl is the template used to render the human-readable
// report.
humanTmpl = template.Must(template.New("").Funcs(humanTmplFuncs).Parse(humanReport))
)

// printSummary renders the summary table with the vulnerability stats.
func printSummary(writer io.Writer, sum summary) error {
var total int
// Print renders the scan results in a human-readable format.
func (prn humanPrinter) Print(w io.Writer, vulns []vulnerability, sum summary) error {
// count the total non-excluded vulnerabilities found.
var total int
for _, ss := range sum.count {
total += ss
}

type severityCount struct {
Name string
Count int
}

var sevCounts []severityCount
for sev := config.SeverityCritical; sev >= config.SeverityInfo; sev-- {
sevCount := severityCount{
Name: sev.String(),
Count: sum.count[sev],
}
sevCounts = append(sevCounts, sevCount)
stats := make(map[string]int)
for s := config.SeverityCritical; s >= config.SeverityInfo; s-- {
stats[s.String()] = sum.count[s]
}

data := struct {
SevCounts []severityCount
Total int
Excluded int
Stats map[string]int
Total int
Excluded int
Vulns []vulnerability
}{
SevCounts: sevCounts,
Total: total,
Excluded: sum.excluded,
Stats: stats,
Total: total,
Excluded: sum.excluded,
Vulns: vulns,
}

sumTmpl := template.New("summary")
sumTmpl = sumTmpl.Funcs(commonFuncs)
sumTmpl = template.Must(sumTmpl.Parse(humanSummary))
if err := sumTmpl.Execute(writer, data); err != nil {
if err := humanTmpl.Execute(w, data); err != nil {
return fmt.Errorf("execute template summary: %w", err)
}
return nil
}

//go:embed templates/humanvuln.tmpl
var humanVuln string

// printVulnerability renders a vulnerability in a human-readable format.
func printVulnerability(writer io.Writer, v vulnerability) error {
vulnTmpl := template.New("vulnerability")
vulnTmpl = vulnTmpl.Funcs(commonFuncs)
vulnTmpl = template.Must(vulnTmpl.Parse(humanVuln))
if err := vulnTmpl.Execute(writer, v); err != nil {
return fmt.Errorf("execute template vulnerability: %w", err)
}
return nil
}
6 changes: 3 additions & 3 deletions internal/report/humanprinter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,17 +155,17 @@ func TestUserFriendlyPrinter_Print(t *testing.T) {
excluded: 3,
},
want: []string{
"Summary of the last scan:",
"SUMMARY",
"Number of excluded vulnerabilities not included in the summary table: 3",
"Vulnerabilities details:",
"VULNERABILITIES",
"Vulnerability Summary 1",
},
},
{
name: "No vulnerabilities",
vulnerabilities: nil,
want: []string{
"No vulnerabilities found during the Lava scan.",
"No vulnerabilities found during the scan.",
},
},
}
Expand Down
135 changes: 135 additions & 0 deletions internal/report/templates/human.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
{{- /* report is the template used to render the full scan report. */ -}}
{{- define "report" -}}
{{"SUMMARY" | bold | underline}}
{{if .Total}}
{{template "summary" .}}
{{else}}
No vulnerabilities found during the scan.
{{end}}
{{- if .Vulns}}
{{template "vulns" . -}}
{{end -}}
{{- end -}}


{{- /* summary is the template used to render the scan summary. */ -}}
{{- define "summary" -}}
{{"CRITICAL" | bold | magenta}}: {{index .Stats "critical"}}
{{"HIGH" | bold | red}}: {{index .Stats "high"}}
{{"MEDIUM" | bold | yellow}}: {{index .Stats "medium"}}
{{"LOW" | bold | cyan}}: {{index .Stats "low"}}
{{"INFO" | bold}}: {{index .Stats "info"}}

Number of excluded vulnerabilities not included in the summary table: {{.Excluded}}
{{- end -}}


{{- /* vulns is the template used to render all the vulnerability reports. */ -}}
{{- define "vulns" -}}
{{"VULNERABILITIES" | bold | underline}}
{{range .Vulns}}
{{template "vuln" . -}}
{{end}}
{{- end -}}


{{- /* vuln is the template used to render one vulnerability report */ -}}
{{- define "vuln" -}}
{{template "vulnTitle" .}}

{{"TARGET" | bold}}
{{.CheckData.Target | trim}}
{{""}}

{{- $affectedResource:= .AffectedResourceString -}}
{{- if not $affectedResource -}}
{{- $affectedResource = .AffectedResource -}}
{{- end -}}
{{- if $affectedResource}}
{{"AFFECTED RESOURCE" | bold}}
{{$affectedResource | trim}}
{{end -}}

{{- if .Description}}
{{"DESCRIPTION" | bold}}
{{.Description | trim}}
{{end -}}

{{- if .Details}}
{{"DETAILS" | bold}}
{{.Details | trim}}
{{end -}}

{{- if .ImpactDetails}}
{{"IMPACT" | bold}}
{{.ImpactDetails | trim}}
{{end -}}

{{- if .Recommendations}}
{{template "vulnRecoms" .}}
{{end -}}

{{- if .References}}
{{template "vulnRefs" .}}
{{end -}}

{{- if .Resources}}
{{template "vulnRscs" .}}
{{end -}}
{{- end -}}


{{- /* vulnTitle is the template used to render the title of a vulnerability. */ -}}
{{- define "vulnTitle" -}}
{{- if eq .Severity.String "critical" -}}
{{printf "=== %v (%v) ===" (trim .Summary) (upper .Severity.String) | bold | magenta}}
{{- else if eq .Severity.String "high" -}}
{{printf "=== %v (%v) ===" (trim .Summary) (upper .Severity.String) | bold | red}}
{{- else if eq .Severity.String "medium" -}}
{{printf "=== %v (%v) ===" (trim .Summary) (upper .Severity.String) | bold | yellow}}
{{- else if eq .Severity.String "low" -}}
{{printf "=== %v (%v) ===" (trim .Summary) (upper .Severity.String) | bold | cyan}}
{{- else -}}
{{printf "=== %v (%v) ===" (trim .Summary) (upper .Severity.String) | bold}}
{{- end -}}
{{- end -}}


{{- /* vulnRecoms is the template used to render the recommendations to fix a vulnerability. */ -}}
{{- define "vulnRecoms" -}}
{{"RECOMMENDATIONS" | bold}}
{{- range .Recommendations}}
- {{. | trim -}}
{{end}}
{{- end -}}


{{- /* vulnRefs is the template used to render a list of references with more details about the vulnerability. */ -}}
{{- define "vulnRefs" -}}
{{"REFERENCES" | bold}}
{{- range .References}}
- {{. | trim -}}
{{end}}
{{- end -}}


{{- /* vulnRscs is the template used to render the list of affected resources. */ -}}
{{- define "vulnRscs" -}}
{{"RESOURCES" | bold}}
{{- range $resource := .Resources}}
{{template "vulnRsc" . -}}
{{end}}
{{- end -}}


{{- /* vulnRsc is the template used to render the details of a single resource. */ -}}
{{- define "vulnRsc" -}}
{{- $rsc := . -}}
- {{$rsc.Name | bold}}:
{{- range $row := $rsc.Rows}}{{range $header := $rsc.Header}}
{{$header | trim | bold}}: {{index $row $header | trim -}}
{{end}}{{end}}
{{- end -}}


{{- template "report" . -}}
19 changes: 0 additions & 19 deletions internal/report/templates/humansum.tmpl

This file was deleted.

67 changes: 0 additions & 67 deletions internal/report/templates/humanvuln.tmpl

This file was deleted.

0 comments on commit f5c4a34

Please sign in to comment.