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

     1  package table
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"strings"
     7  
     8  	"golang.org/x/term"
     9  
    10  	"github.com/aquasecurity/tml"
    11  	dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
    12  	"github.com/devseccon/trivy/pkg/fanal/types"
    13  )
    14  
    15  type secretRenderer struct {
    16  	w          *bytes.Buffer
    17  	target     string
    18  	secrets    []types.SecretFinding
    19  	severities []dbTypes.Severity
    20  	width      int
    21  	ansi       bool
    22  }
    23  
    24  func NewSecretRenderer(target string, secrets []types.SecretFinding, ansi bool, severities []dbTypes.Severity) *secretRenderer {
    25  	width, _, err := term.GetSize(0)
    26  	if err != nil || width == 0 {
    27  		width = 40
    28  	}
    29  	if !ansi {
    30  		tml.DisableFormatting()
    31  	}
    32  	return &secretRenderer{
    33  		w:          bytes.NewBuffer([]byte{}),
    34  		target:     target,
    35  		secrets:    secrets,
    36  		severities: severities,
    37  		width:      width,
    38  		ansi:       ansi,
    39  	}
    40  }
    41  
    42  func (r *secretRenderer) Render() string {
    43  	target := r.target + " (secrets)"
    44  	RenderTarget(r.w, target, r.ansi)
    45  
    46  	severityCount := r.countSeverities()
    47  	total, summaries := summarize(r.severities, severityCount)
    48  
    49  	r.printf("Total: %d (%s)\n\n", total, strings.Join(summaries, ", "))
    50  
    51  	for _, m := range r.secrets {
    52  		r.renderSingle(m)
    53  	}
    54  	return r.w.String()
    55  }
    56  
    57  func (r *secretRenderer) countSeverities() map[string]int {
    58  	severityCount := make(map[string]int)
    59  	for _, secret := range r.secrets {
    60  		severity := secret.Severity
    61  		severityCount[severity]++
    62  	}
    63  	return severityCount
    64  }
    65  
    66  func (r *secretRenderer) printf(format string, args ...interface{}) {
    67  	// nolint
    68  	_ = tml.Fprintf(r.w, format, args...)
    69  }
    70  
    71  func (r *secretRenderer) printDoubleDivider() {
    72  	r.printf("<dim>%s\r\n", strings.Repeat("═", r.width))
    73  }
    74  
    75  func (r *secretRenderer) printSingleDivider() {
    76  	r.printf("<dim>%s\r\n", strings.Repeat("─", r.width))
    77  }
    78  
    79  func (r *secretRenderer) renderSingle(secret types.SecretFinding) {
    80  	r.renderSummary(secret)
    81  	r.renderCode(secret)
    82  	r.printf("\r\n\r\n")
    83  }
    84  
    85  func (r *secretRenderer) renderSummary(secret types.SecretFinding) {
    86  
    87  	// severity
    88  	switch secret.Severity {
    89  	case severityCritical:
    90  		r.printf("<red><bold>%s: ", secret.Severity)
    91  	case severityHigh:
    92  		r.printf("<red>%s: ", secret.Severity)
    93  	case severityMedium:
    94  		r.printf("<yellow>%s: ", secret.Severity)
    95  	case severityLow:
    96  		r.printf("%s: ", secret.Severity)
    97  	default:
    98  		r.printf("<blue>%s: ", secret.Severity)
    99  	}
   100  
   101  	// heading
   102  	r.printf("%s (%s)\r\n", secret.Category, secret.RuleID)
   103  	r.printDoubleDivider()
   104  
   105  	// description
   106  	r.printf("<dim>%s\r\n", secret.Title)
   107  
   108  	r.printSingleDivider()
   109  }
   110  
   111  func (r *secretRenderer) renderCode(secret types.SecretFinding) {
   112  	// highlight code if we can...
   113  	if lines := secret.Code.Lines; len(lines) > 0 {
   114  
   115  		var lineInfo string
   116  		if secret.StartLine > 0 {
   117  			lineInfo = tml.Sprintf("<dim>:</dim><blue>%d", secret.StartLine)
   118  			if secret.EndLine > secret.StartLine {
   119  				lineInfo = tml.Sprintf("%s<blue>-%d", lineInfo, secret.EndLine)
   120  			}
   121  		}
   122  
   123  		var note string
   124  		if c := secret.Layer.CreatedBy; c != "" {
   125  			if len(c) > 40 {
   126  				// Too long
   127  				c = c[:40]
   128  			}
   129  			note = fmt.Sprintf(" (added by '%s')", c)
   130  		} else if secret.Layer.DiffID != "" {
   131  			note = fmt.Sprintf(" (added in layer '%s')", strings.TrimPrefix(secret.Layer.DiffID, "sha256:")[:12])
   132  		}
   133  		r.printf(" <blue>%s%s<magenta>%s\r\n", r.target, lineInfo, note)
   134  		r.printSingleDivider()
   135  
   136  		for i, line := range lines {
   137  			switch {
   138  			case line.Truncated:
   139  				r.printf("<dim>%4s   ", strings.Repeat(".", len(fmt.Sprintf("%d", line.Number))))
   140  			case line.IsCause:
   141  				r.printf("<red>%4d ", line.Number)
   142  				switch {
   143  				case (line.FirstCause && line.LastCause) || len(lines) == 1:
   144  					r.printf("<red>[ ")
   145  				case line.FirstCause || i == 0:
   146  					r.printf("<red>┌ ")
   147  				case line.LastCause || i == len(lines)-1:
   148  					r.printf("<red>└ ")
   149  				default:
   150  					r.printf("<red>│ ")
   151  				}
   152  			default:
   153  				r.printf("<dim>%4d   ", line.Number)
   154  			}
   155  			if r.ansi {
   156  				r.printf("%s\r\n", line.Highlighted)
   157  			} else {
   158  				r.printf("%s\r\n", line.Content)
   159  			}
   160  		}
   161  		r.printSingleDivider()
   162  	}
   163  }