-
Notifications
You must be signed in to change notification settings - Fork 2.3k
/
writer.go
145 lines (122 loc) · 3.37 KB
/
writer.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
package report
import (
"encoding/json"
"fmt"
"io"
"os"
"strings"
"text/template"
"golang.org/x/xerrors"
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
"github.com/aquasecurity/trivy/pkg/types"
"github.com/olekukonko/tablewriter"
)
type Results []Result
type Result struct {
Target string `json:"Target"`
Vulnerabilities []types.DetectedVulnerability `json:"Vulnerabilities"`
}
func WriteResults(format string, output io.Writer, results Results, outputTemplate string, light bool) error {
var writer Writer
switch format {
case "table":
writer = &TableWriter{Output: output, Light: light}
case "json":
writer = &JsonWriter{Output: output}
case "template":
tmpl, err := template.New("output template").Parse(outputTemplate)
if err != nil {
return xerrors.Errorf("error parsing template: %w", err)
}
writer = &TemplateWriter{Output: output, Template: tmpl}
default:
return xerrors.Errorf("unknown format: %v", format)
}
if err := writer.Write(results); err != nil {
return xerrors.Errorf("failed to write results: %w", err)
}
return nil
}
type Writer interface {
Write(Results) error
}
type TableWriter struct {
Output io.Writer
Light bool
}
func (tw TableWriter) Write(results Results) error {
for _, result := range results {
tw.write(result)
}
return nil
}
func (tw TableWriter) write(result Result) {
table := tablewriter.NewWriter(tw.Output)
header := []string{"Library", "Vulnerability ID", "Severity", "Installed Version", "Fixed Version"}
if !tw.Light {
header = append(header, "Title")
}
table.SetHeader(header)
severityCount := map[string]int{}
for _, v := range result.Vulnerabilities {
severityCount[v.Severity]++
title := v.Title
if title == "" {
title = v.Description
}
splittedTitle := strings.Split(title, " ")
if len(splittedTitle) >= 12 {
title = strings.Join(splittedTitle[:12], " ") + "..."
}
var row []string
if tw.Output == os.Stdout {
row = []string{v.PkgName, v.VulnerabilityID, dbTypes.ColorizeSeverity(v.Severity),
v.InstalledVersion, v.FixedVersion}
} else {
row = []string{v.PkgName, v.VulnerabilityID, v.Severity, v.InstalledVersion, v.FixedVersion}
}
if !tw.Light {
row = append(row, title)
}
table.Append(row)
}
var results []string
for _, severity := range dbTypes.SeverityNames {
r := fmt.Sprintf("%s: %d", severity, severityCount[severity])
results = append(results, r)
}
fmt.Printf("\n%s\n", result.Target)
fmt.Println(strings.Repeat("=", len(result.Target)))
fmt.Printf("Total: %d (%s)\n\n", len(result.Vulnerabilities), strings.Join(results, ", "))
if len(result.Vulnerabilities) == 0 {
return
}
table.SetAutoMergeCells(true)
table.SetRowLine(true)
table.Render()
return
}
type JsonWriter struct {
Output io.Writer
}
func (jw JsonWriter) Write(results Results) error {
output, err := json.MarshalIndent(results, "", " ")
if err != nil {
return xerrors.Errorf("failed to marshal json: %w", err)
}
if _, err = fmt.Fprint(jw.Output, string(output)); err != nil {
return xerrors.Errorf("failed to write json: %w", err)
}
return nil
}
type TemplateWriter struct {
Output io.Writer
Template *template.Template
}
func (tw TemplateWriter) Write(results Results) error {
err := tw.Template.Execute(tw.Output, results)
if err != nil {
return xerrors.Errorf("failed to write with template: %w", err)
}
return nil
}