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  }