Colorize severity in table output (#1284)

* Colorize severity in table output

- Create flag "--no-color" to allow disabling the color. By default its enabled.
- When "--no-color" not specified highlight severity in its color:
  - Critical -> Bold Red
  - High -> Red
  - Medium -> Yellow
  - Low -> Green
  - Negligible -> Blue
  - Note: Golang doesn't have all colors available. Also, doesn't seem to be able use hex codes properly.
- Add termenv to check if the terminal color profile supports colored output. If it doesn't default to noColor

Closes #225

Signed-off-by: Shane Dell <shanedell100@gmail.com>

* fix: adopt EnvColorProfile to support NO_COLOR

Signed-off-by: Christopher Phillips <christopher.phillips@anchore.com>

* fix linting and update snapshots

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>

---------

Signed-off-by: Shane Dell <shanedell100@gmail.com>
Signed-off-by: Christopher Phillips <christopher.phillips@anchore.com>
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
Co-authored-by: Christopher Phillips <christopher.phillips@anchore.com>
Co-authored-by: Alex Goodman <wagoodman@users.noreply.github.com>
This commit is contained in:
Shane Dell 2023-10-30 09:57:46 -04:00 committed by GitHub
parent 401d67cd96
commit 81edd50e1e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 75 additions and 17 deletions

17
go.mod
View file

@ -37,35 +37,27 @@ require (
github.com/hashicorp/go-version v1.6.0
github.com/knqyf263/go-apk-version v0.0.0-20200609155635-041fdbb8563f
github.com/knqyf263/go-deb-version v0.0.0-20190517075300-09fca494f03d
github.com/masahiro331/go-mvn-version v0.0.0-20210429150710-d3157d602a08
github.com/mholt/archiver/v3 v3.5.1
github.com/mitchellh/go-homedir v1.1.0
github.com/mitchellh/hashstructure/v2 v2.0.2
github.com/mitchellh/mapstructure v1.5.0
github.com/olekukonko/tablewriter v0.0.5
github.com/openvex/go-vex v0.2.5
github.com/pkg/profile v1.7.0 // indirect
github.com/owenrumney/go-sarif v1.1.2-0.20231003122901-1000f5e05554
// pinned to pull in 386 arch fix: https://github.com/scylladb/go-set/commit/cc7b2070d91ebf40d233207b633e28f5bd8f03a5
github.com/scylladb/go-set v1.0.3-0.20200225121959-cc7b2070d91e
github.com/sergi/go-diff v1.3.1
github.com/sirupsen/logrus v1.9.3
github.com/spf13/afero v1.10.0
github.com/spf13/cobra v1.7.0
github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/viper v1.16.0 // indirect
github.com/stretchr/testify v1.8.4
github.com/wagoodman/go-partybus v0.0.0-20230516145632-8ccac152c651
github.com/wagoodman/go-presenter v0.0.0-20211015174752-f9c01afc824b
github.com/wagoodman/go-progress v0.0.0-20230925121702-07e42b3cdba0
github.com/x-cray/logrus-prefixed-formatter v0.5.2
golang.org/x/exp v0.0.0-20230905200255-921286631fa9
golang.org/x/term v0.13.0 // indirect
gorm.io/gorm v1.25.5
modernc.org/sqlite v1.26.0 // indirect
)
require (
github.com/masahiro331/go-mvn-version v0.0.0-20210429150710-d3157d602a08
github.com/owenrumney/go-sarif v1.1.2-0.20231003122901-1000f5e05554
)
require (
@ -196,6 +188,7 @@ require (
github.com/pierrec/lz4/v4 v4.1.15 // indirect
github.com/pjbgf/sha1cd v0.3.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pkg/profile v1.7.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/rivo/uniseg v0.2.0 // indirect
@ -208,6 +201,8 @@ require (
github.com/spdx/tools-golang v0.5.3 // indirect
github.com/spf13/cast v1.5.1 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/viper v1.16.0 // indirect
github.com/subosito/gotenv v1.4.2 // indirect
github.com/sylabs/sif/v2 v2.11.5 // indirect
github.com/sylabs/squashfs v0.6.1 // indirect
@ -236,6 +231,7 @@ require (
golang.org/x/oauth2 v0.8.0 // indirect
golang.org/x/sync v0.3.0 // indirect
golang.org/x/sys v0.13.0 // indirect
golang.org/x/term v0.13.0 // indirect
golang.org/x/text v0.13.0 // indirect
golang.org/x/time v0.2.0 // indirect
golang.org/x/tools v0.13.0 // indirect
@ -253,4 +249,5 @@ require (
modernc.org/libc v1.24.1 // indirect
modernc.org/mathutil v1.5.0 // indirect
modernc.org/memory v1.6.0 // indirect
modernc.org/sqlite v1.26.0 // indirect
)

View file

@ -1,5 +1,15 @@
[TestTablePresenter - 1]
[TestTablePresenter/no_color - 1]
NAME INSTALLED FIXED-IN TYPE VULNERABILITY SEVERITY
package-1 1.1.1 the-next-version rpm CVE-1999-0001 Low
package-2 2.2.2 deb CVE-1999-0002 Critical
---
[TestTablePresenter/with_color - 1]
NAME INSTALLED FIXED-IN TYPE VULNERABILITY SEVERITY
package-1 1.1.1 the-next-version rpm CVE-1999-0001 Low
package-2 2.2.2 deb CVE-1999-0002 Critical
NAME INSTALLED FIXED-IN TYPE VULNERABILITY SEVERITY
package-1 1.1.1 the-next-version rpm CVE-1999-0001 Low
package-2 2.2.2 deb CVE-1999-0002 Critical

View file

@ -6,6 +6,7 @@ import (
"sort"
"strings"
"github.com/charmbracelet/lipgloss"
"github.com/olekukonko/tablewriter"
grypeDb "github.com/anchore/grype/grype/db/v5"
@ -27,6 +28,7 @@ type Presenter struct {
packages []pkg.Package
metadataProvider vulnerability.MetadataProvider
showSuppressed bool
withColor bool
}
// NewPresenter is a *Presenter constructor
@ -37,6 +39,7 @@ func NewPresenter(pb models.PresenterConfig, showSuppressed bool) *Presenter {
packages: pb.Packages,
metadataProvider: pb.MetadataProvider,
showSuppressed: showSuppressed,
withColor: supportsColor(),
}
}
@ -96,12 +99,24 @@ func (pres *Presenter) Present(output io.Writer) error {
table.SetTablePadding(" ")
table.SetNoWhiteSpace(true)
table.AppendBulk(rows)
if pres.withColor {
for _, row := range rows {
severityColor := getSeverityColor(row[len(row)-1])
table.Rich(row, []tablewriter.Colors{{}, {}, {}, {}, {}, severityColor})
}
} else {
table.AppendBulk(rows)
}
table.Render()
return nil
}
func supportsColor() bool {
return lipgloss.NewStyle().Foreground(lipgloss.Color("5")).Render("") != ""
}
func sortRows(rows [][]string) [][]string {
// sort
sort.SliceStable(rows, func(i, j int) bool {
@ -174,3 +189,23 @@ func createRow(m match.Match, metadataProvider vulnerability.MetadataProvider, s
return []string{m.Package.Name, m.Package.Version, fixVersion, string(m.Package.Type), m.Vulnerability.ID, severity}, nil
}
func getSeverityColor(severity string) tablewriter.Colors {
severityFontType, severityColor := tablewriter.Normal, tablewriter.Normal
switch strings.ToLower(severity) {
case "critical":
severityFontType = tablewriter.Bold
severityColor = tablewriter.FgRedColor
case "high":
severityColor = tablewriter.FgRedColor
case "medium":
severityColor = tablewriter.FgYellowColor
case "low":
severityColor = tablewriter.FgGreenColor
case "negligible":
severityColor = tablewriter.FgBlueColor
}
return tablewriter.Colors{severityFontType, severityColor}
}

View file

@ -83,12 +83,25 @@ func TestTablePresenter(t *testing.T) {
pres := NewPresenter(pb, false)
// run presenter
err := pres.Present(&buffer)
require.NoError(t, err)
t.Run("no color", func(t *testing.T) {
pres.withColor = true
actual := buffer.String()
snaps.MatchSnapshot(t, actual)
err := pres.Present(&buffer)
require.NoError(t, err)
actual := buffer.String()
snaps.MatchSnapshot(t, actual)
})
t.Run("with color", func(t *testing.T) {
pres.withColor = false
err := pres.Present(&buffer)
require.NoError(t, err)
actual := buffer.String()
snaps.MatchSnapshot(t, actual)
})
// TODO: add me back in when there is a JSON schema
// validateAgainstDbSchema(t, string(actual))

View file

@ -0,0 +1,3 @@
NAME INSTALLED FIXED-IN TYPE VULNERABILITY SEVERITY
package-1 1.1.1 the-next-version rpm CVE-1999-0001 Low
package-2 2.2.2 deb CVE-1999-0002 Critical