github.com/devseccon/trivy@v0.47.1-0.20231123133102-bd902a0bd996/pkg/cloud/report/resource.go (about)

     1  package report
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"sort"
     7  	"strconv"
     8  
     9  	"golang.org/x/term"
    10  
    11  	"github.com/aquasecurity/table"
    12  	"github.com/aquasecurity/tml"
    13  	pkgReport "github.com/devseccon/trivy/pkg/report/table"
    14  	"github.com/devseccon/trivy/pkg/types"
    15  )
    16  
    17  type sortableRow struct {
    18  	name   string
    19  	counts map[string]int
    20  }
    21  
    22  func writeResourceTable(report *Report, results types.Results, output io.Writer, service string) error {
    23  
    24  	termWidth, _, err := term.GetSize(0)
    25  	if err != nil {
    26  		termWidth = 80
    27  	}
    28  	maxWidth := termWidth - 48
    29  	if maxWidth < 20 {
    30  		maxWidth = 20
    31  	}
    32  
    33  	t := table.New(output)
    34  	t.SetColumnMaxWidth(maxWidth)
    35  	t.SetHeaders("Resource", "Misconfigurations")
    36  	t.AddHeaders("Resource", "Critical", "High", "Medium", "Low", "Unknown")
    37  	t.SetHeaderVerticalAlignment(table.AlignBottom)
    38  	t.SetHeaderAlignment(table.AlignLeft, table.AlignCenter, table.AlignCenter, table.AlignCenter, table.AlignCenter, table.AlignCenter)
    39  	t.SetAlignment(table.AlignLeft, table.AlignRight, table.AlignRight, table.AlignRight, table.AlignRight, table.AlignRight)
    40  	t.SetRowLines(false)
    41  	t.SetAutoMergeHeaders(true)
    42  	t.SetHeaderColSpans(0, 1, 5)
    43  
    44  	// map resource -> severity -> count
    45  	grouped := make(map[string]map[string]int)
    46  	for _, result := range results {
    47  		for _, misconfiguration := range result.Misconfigurations {
    48  			if misconfiguration.CauseMetadata.Service != service {
    49  				continue
    50  			}
    51  			if _, ok := grouped[misconfiguration.CauseMetadata.Resource]; !ok {
    52  				grouped[misconfiguration.CauseMetadata.Resource] = make(map[string]int)
    53  			}
    54  			grouped[misconfiguration.CauseMetadata.Resource][misconfiguration.Severity]++
    55  		}
    56  	}
    57  
    58  	var sortable []sortableRow
    59  	for resource, severityCounts := range grouped {
    60  		sortable = append(sortable, sortableRow{
    61  			name:   resource,
    62  			counts: severityCounts,
    63  		})
    64  	}
    65  	sort.Slice(sortable, func(i, j int) bool { return sortable[i].name < sortable[j].name })
    66  	for _, row := range sortable {
    67  		t.AddRow(
    68  			row.name,
    69  			pkgReport.ColorizeSeverity(strconv.Itoa(row.counts["CRITICAL"]), "CRITICAL"),
    70  			pkgReport.ColorizeSeverity(strconv.Itoa(row.counts["HIGH"]), "HIGH"),
    71  			pkgReport.ColorizeSeverity(strconv.Itoa(row.counts["MEDIUM"]), "MEDIUM"),
    72  			pkgReport.ColorizeSeverity(strconv.Itoa(row.counts["LOW"]), "LOW"),
    73  			pkgReport.ColorizeSeverity(strconv.Itoa(row.counts["UNKNOWN"]), "UNKNOWN"),
    74  		)
    75  	}
    76  
    77  	// render scan title
    78  	_ = tml.Fprintf(output, "\n<bold>Resource Summary for Service '%s' (%s Account %s)</bold>\n", service, report.Provider, report.AccountID)
    79  
    80  	// render table
    81  	if len(sortable) > 0 {
    82  		t.Render()
    83  	} else {
    84  		_, _ = fmt.Fprint(output, "\nNo problems detected.\n")
    85  	}
    86  
    87  	return nil
    88  }