github.com/devseccon/trivy@v0.47.1-0.20231123133102-bd902a0bd996/pkg/report/table/licensing.go (about) 1 package table 2 3 import ( 4 "bytes" 5 "sort" 6 "strings" 7 "sync" 8 9 "github.com/fatih/color" 10 "golang.org/x/text/cases" 11 "golang.org/x/text/language" 12 13 "github.com/aquasecurity/table" 14 "github.com/aquasecurity/tml" 15 dbTypes "github.com/aquasecurity/trivy-db/pkg/types" 16 ftypes "github.com/devseccon/trivy/pkg/fanal/types" 17 "github.com/devseccon/trivy/pkg/types" 18 ) 19 20 type pkgLicenseRenderer struct { 21 w *bytes.Buffer 22 tableWriter *table.Table 23 result types.Result 24 isTerminal bool 25 severities []dbTypes.Severity 26 once *sync.Once 27 } 28 29 func NewPkgLicenseRenderer(result types.Result, isTerminal bool, severities []dbTypes.Severity) pkgLicenseRenderer { 30 buf := bytes.NewBuffer([]byte{}) 31 return pkgLicenseRenderer{ 32 w: buf, 33 tableWriter: newTableWriter(buf, isTerminal), 34 result: result, 35 isTerminal: isTerminal, 36 severities: severities, 37 once: new(sync.Once), 38 } 39 } 40 41 func (r pkgLicenseRenderer) Render() string { 42 r.setHeaders() 43 r.setRows() 44 45 total, summaries := summarize(r.severities, r.countSeverities()) 46 47 target := r.result.Target + " (license)" 48 RenderTarget(r.w, target, r.isTerminal) 49 r.printf("Total: %d (%s)\n\n", total, strings.Join(summaries, ", ")) 50 51 r.tableWriter.Render() 52 53 return r.w.String() 54 } 55 56 func (r pkgLicenseRenderer) setHeaders() { 57 header := []string{"Package", "License", "Classification", "Severity"} 58 r.tableWriter.SetHeaders(header...) 59 } 60 61 func (r pkgLicenseRenderer) setRows() { 62 for _, l := range r.result.Licenses { 63 var row []string 64 if r.isTerminal { 65 row = []string{ 66 l.PkgName, l.Name, colorizeLicenseCategory(l.Category), ColorizeSeverity(l.Severity, l.Severity), 67 } 68 } else { 69 row = []string{ 70 l.PkgName, l.Name, string(l.Category), l.Severity, 71 } 72 } 73 r.tableWriter.AddRow(row...) 74 } 75 } 76 77 func (r pkgLicenseRenderer) countSeverities() map[string]int { 78 severityCount := make(map[string]int) 79 for _, l := range r.result.Licenses { 80 severityCount[l.Severity]++ 81 } 82 return severityCount 83 } 84 85 func (r *pkgLicenseRenderer) printf(format string, args ...interface{}) { 86 // nolint 87 _ = tml.Fprintf(r.w, format, args...) 88 } 89 90 type fileLicenseRenderer struct { 91 w *bytes.Buffer 92 tableWriter *table.Table 93 result types.Result 94 isTerminal bool 95 severities []dbTypes.Severity 96 once *sync.Once 97 } 98 99 func NewFileLicenseRenderer(result types.Result, isTerminal bool, severities []dbTypes.Severity) fileLicenseRenderer { 100 buf := bytes.NewBuffer([]byte{}) 101 return fileLicenseRenderer{ 102 w: buf, 103 tableWriter: newTableWriter(buf, isTerminal), 104 result: result, 105 isTerminal: isTerminal, 106 severities: severities, 107 once: new(sync.Once), 108 } 109 } 110 111 func (r fileLicenseRenderer) Render() string { 112 r.setHeaders() 113 r.setRows() 114 115 total, summaries := summarize(r.severities, r.countSeverities()) 116 117 target := r.result.Target + " (license)" 118 RenderTarget(r.w, target, r.isTerminal) 119 r.printf("Total: %d (%s)\n\n", total, strings.Join(summaries, ", ")) 120 121 r.tableWriter.Render() 122 123 return r.w.String() 124 } 125 126 func (r fileLicenseRenderer) setHeaders() { 127 header := []string{"Classification", "Severity", "License", "File Location"} 128 r.tableWriter.SetHeaders(header...) 129 } 130 131 func (r fileLicenseRenderer) setRows() { 132 sort.Slice(r.result.Licenses, func(i, j int) bool { 133 a := r.result.Licenses[i] 134 b := r.result.Licenses[j] 135 if a.Severity != b.Severity { 136 return 0 < dbTypes.CompareSeverityString(b.Severity, a.Severity) 137 } 138 if a.Category != b.Category { 139 return a.Category > b.Category 140 } 141 if a.Name != b.Name { 142 return a.Name < b.Name 143 } 144 return a.FilePath < b.FilePath 145 }) 146 147 for _, l := range r.result.Licenses { 148 var row []string 149 if r.isTerminal { 150 row = []string{ 151 colorizeLicenseCategory(l.Category), ColorizeSeverity(l.Severity, l.Severity), l.Name, l.FilePath, 152 } 153 } else { 154 row = []string{ 155 string(l.Category), l.Severity, l.Name, l.FilePath, 156 } 157 } 158 r.tableWriter.AddRow(row...) 159 } 160 } 161 162 func (r fileLicenseRenderer) countSeverities() map[string]int { 163 severityCount := make(map[string]int) 164 for _, l := range r.result.Licenses { 165 severityCount[l.Severity]++ 166 } 167 return severityCount 168 } 169 170 func (r *fileLicenseRenderer) printf(format string, args ...interface{}) { 171 // nolint 172 _ = tml.Fprintf(r.w, format, args...) 173 } 174 175 func colorizeLicenseCategory(category ftypes.LicenseCategory) string { 176 switch category { 177 case ftypes.CategoryForbidden: 178 return color.New(color.FgRed).Sprintf("Forbidden") 179 case ftypes.CategoryRestricted: 180 return color.New(color.FgHiRed).Sprintf("Restricted") 181 case ftypes.CategoryUnknown: 182 return color.New(color.FgCyan).Sprintf("Non Standard") 183 } 184 return cases.Title(language.AmericanEnglish).String(string(category)) 185 }