mirror of
https://github.com/aquasecurity/trivy.git
synced 2025-12-12 15:50:15 -08:00
feat(kubernetes): Add report flag for summary (#2112)
* feat(k8s): Add report flag for summary * chore: add headings to the severity columns * chore: make the default output of k8s summary table Signed-off-by: Owen Rumney <owen.rumney@aquasec.com>
This commit is contained in:
@@ -6,6 +6,8 @@ This feature might change without preserving backwards compatibility.
|
||||
|
||||
Scan your Kubernetes cluster for both Vulnerabilities and Misconfigurations.
|
||||
|
||||
Trivy uses your local kubectl configuration to access the API server to list artifacts.
|
||||
|
||||
Scan a full cluster:
|
||||
|
||||
```
|
||||
@@ -24,13 +26,25 @@ Scan a namespace for only `CRITICAL` Vulnerabilities and Misconfigurations:
|
||||
$ trivy k8s -n default -o results.json --severity CRITICAL
|
||||
```
|
||||
|
||||
Trivy uses your local kubectl configuration to access the API server to list artifacts.
|
||||
At this time, JSON is the only supported output and is intended to be used for automation, other reports will be implemented soon.
|
||||
Scan a cluster and generate a simple summary report. The only outputs currently supported are `all` and `summary`. The default report format is `summary`
|
||||
|
||||
```
|
||||
$ trivy k8s
|
||||
```
|
||||
|
||||

|
||||
|
||||
To get all of the detail the output contains, use `--report all`, to get JSON output:
|
||||
|
||||
```
|
||||
$ trivy k8s --report all
|
||||
```
|
||||
|
||||
|
||||
<details>
|
||||
<summary>Result</summary>
|
||||
|
||||
```
|
||||
```json
|
||||
{
|
||||
"ClusterName": "minikube",
|
||||
"Vulnerabilities": [
|
||||
|
||||
BIN
docs/imgs/k8s-summary.png
Normal file
BIN
docs/imgs/k8s-summary.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 154 KiB |
16
go.mod
16
go.mod
@@ -7,13 +7,12 @@ require (
|
||||
github.com/Masterminds/sprig/v3 v3.2.2
|
||||
github.com/NYTimes/gziphandler v1.1.1
|
||||
github.com/aquasecurity/bolt-fixtures v0.0.0-20200903104109-d34e7f983986
|
||||
github.com/aquasecurity/fanal v0.0.0-20220513163515-33f2cd8392ee
|
||||
github.com/aquasecurity/fanal v0.0.0-20220511115204-32614d79a234
|
||||
github.com/aquasecurity/go-dep-parser v0.0.0-20220503151658-d316f5cc2cff
|
||||
github.com/aquasecurity/go-gem-version v0.0.0-20201115065557-8eed6fe000ce
|
||||
github.com/aquasecurity/go-npm-version v0.0.0-20201110091526-0b796d180798
|
||||
github.com/aquasecurity/go-pep440-version v0.0.0-20210121094942-22b2f8951d46
|
||||
github.com/aquasecurity/go-version v0.0.0-20210121072130-637058cfe492
|
||||
github.com/aquasecurity/table v1.2.0
|
||||
github.com/aquasecurity/trivy-db v0.0.0-20220327074450-74195d9604b2
|
||||
github.com/caarlos0/env/v6 v6.9.1
|
||||
github.com/cenkalti/backoff v2.2.1+incompatible
|
||||
@@ -54,7 +53,7 @@ require (
|
||||
require (
|
||||
cloud.google.com/go v0.99.0 // indirect
|
||||
cloud.google.com/go/storage v1.14.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go v64.0.0+incompatible // indirect
|
||||
github.com/Azure/azure-sdk-for-go v63.0.0+incompatible // indirect
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
|
||||
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
|
||||
github.com/Azure/go-autorest/autorest v0.11.27 // indirect
|
||||
@@ -77,10 +76,9 @@ require (
|
||||
github.com/VividCortex/ewma v1.1.1 // indirect
|
||||
github.com/acomagu/bufpipe v1.0.3 // indirect
|
||||
github.com/agext/levenshtein v1.2.3 // indirect
|
||||
github.com/alecthomas/chroma v0.10.0 // indirect
|
||||
github.com/apparentlymart/go-cidr v1.1.0 // indirect
|
||||
github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect
|
||||
github.com/aquasecurity/defsec v0.57.5
|
||||
github.com/aquasecurity/defsec v0.57.3
|
||||
github.com/aws/aws-sdk-go v1.44.5 // indirect
|
||||
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect
|
||||
github.com/bmatcuk/doublestar v1.3.4 // indirect
|
||||
@@ -93,7 +91,6 @@ require (
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/dimchansky/utfbom v1.1.1 // indirect
|
||||
github.com/dlclark/regexp2 v1.4.0 // indirect
|
||||
github.com/docker/cli v20.10.13+incompatible // indirect
|
||||
github.com/docker/distribution v2.8.0+incompatible // indirect
|
||||
github.com/docker/docker-credential-helpers v0.6.4 // indirect
|
||||
@@ -242,6 +239,13 @@ require gopkg.in/yaml.v2 v2.4.0
|
||||
|
||||
require github.com/aquasecurity/trivy-kubernetes v0.1.0
|
||||
|
||||
require github.com/aquasecurity/table v1.5.1
|
||||
|
||||
require (
|
||||
github.com/alecthomas/chroma v0.10.0 // indirect
|
||||
github.com/dlclark/regexp2 v1.4.0 // indirect
|
||||
)
|
||||
|
||||
// To resolve CVE-2022-23648
|
||||
replace github.com/containerd/containerd v1.5.9 => github.com/containerd/containerd v1.5.10
|
||||
|
||||
|
||||
16
go.sum
16
go.sum
@@ -56,8 +56,8 @@ dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20210715213245-6c3934b029d8/go.mod h1:CzsSbkDixRphAF5hS6wbMKq0eI6ccJRb7/A0M6JBnwg=
|
||||
github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
|
||||
github.com/Azure/azure-sdk-for-go v56.3.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
|
||||
github.com/Azure/azure-sdk-for-go v64.0.0+incompatible h1:WAA77WBDWYtNfCC95V70VvkdzHe+wM/r2MQ9mG7fnQs=
|
||||
github.com/Azure/azure-sdk-for-go v64.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
|
||||
github.com/Azure/azure-sdk-for-go v63.0.0+incompatible h1:whPsa+jCHQSo5wGMPNLw4bz8q9Co2+vnXHzXGctoTaQ=
|
||||
github.com/Azure/azure-sdk-for-go v63.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210608223527-2377c96fe795/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
|
||||
@@ -180,10 +180,10 @@ github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6
|
||||
github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo=
|
||||
github.com/aquasecurity/bolt-fixtures v0.0.0-20200903104109-d34e7f983986 h1:2a30xLN2sUZcMXl50hg+PJCIDdJgIvIbVcKqLJ/ZrtM=
|
||||
github.com/aquasecurity/bolt-fixtures v0.0.0-20200903104109-d34e7f983986/go.mod h1:NT+jyeCzXk6vXR5MTkdn4z64TgGfE5HMLC8qfj5unl8=
|
||||
github.com/aquasecurity/defsec v0.57.5 h1:kOsRgMlQMxdOHYNEF0SCblZevrsdoz7c4fz5qYTTUFY=
|
||||
github.com/aquasecurity/defsec v0.57.5/go.mod h1:42FxKif2itz+MHFlJ3TJjdroL9Jzj3THoexlueBTU5w=
|
||||
github.com/aquasecurity/fanal v0.0.0-20220513163515-33f2cd8392ee h1:O7cN19V4W7u7s7M3kME21/IDUA4iQULDeo9g3DS4gdU=
|
||||
github.com/aquasecurity/fanal v0.0.0-20220513163515-33f2cd8392ee/go.mod h1:1FqeeQo0AKRIgYgv60r0SOBNMBenxBQF3jAnnICEFIE=
|
||||
github.com/aquasecurity/defsec v0.57.3 h1:oiATfUTxOAcxAuXSH31RdgjtXJdQznlVzMJWdVYGmXY=
|
||||
github.com/aquasecurity/defsec v0.57.3/go.mod h1:42FxKif2itz+MHFlJ3TJjdroL9Jzj3THoexlueBTU5w=
|
||||
github.com/aquasecurity/fanal v0.0.0-20220511115204-32614d79a234 h1:NG9Qs4hocUWcGytaA0yhArPRoPmo12EPAUERwYCgvLA=
|
||||
github.com/aquasecurity/fanal v0.0.0-20220511115204-32614d79a234/go.mod h1:bqz0H4eqstkngJB0TJCk39GLXZcUtobMpuNr4ScC1vk=
|
||||
github.com/aquasecurity/go-dep-parser v0.0.0-20220503151658-d316f5cc2cff h1:YNlzRYB0n4mZtfuWx6AWaGEjnLVNekchyoFDlYFZegs=
|
||||
github.com/aquasecurity/go-dep-parser v0.0.0-20220503151658-d316f5cc2cff/go.mod h1:7EOQWQmyavVPY3fScbbPdd3dB/b0Q4ZbJ/NZCvNKrLs=
|
||||
github.com/aquasecurity/go-gem-version v0.0.0-20201115065557-8eed6fe000ce h1:QgBRgJvtEOBtUXilDb1MLi1p1MWoyFDXAu5DEUl5nwM=
|
||||
@@ -195,8 +195,8 @@ github.com/aquasecurity/go-pep440-version v0.0.0-20210121094942-22b2f8951d46/go.
|
||||
github.com/aquasecurity/go-version v0.0.0-20201107203531-5e48ac5d022a/go.mod h1:9Beu8XsUNNfzml7WBf3QmyPToP1wm1Gj/Vc5UJKqTzU=
|
||||
github.com/aquasecurity/go-version v0.0.0-20210121072130-637058cfe492 h1:rcEG5HI490FF0a7zuvxOxen52ddygCfNVjP0XOCMl+M=
|
||||
github.com/aquasecurity/go-version v0.0.0-20210121072130-637058cfe492/go.mod h1:9Beu8XsUNNfzml7WBf3QmyPToP1wm1Gj/Vc5UJKqTzU=
|
||||
github.com/aquasecurity/table v1.2.0 h1:26N9hFB5qttCjWoBgeKIlBtmlCpSwfL01BK7N+IOBN0=
|
||||
github.com/aquasecurity/table v1.2.0/go.mod h1:1MFKrEPJ8NchM917BrVGvsqoXJo1OL1Ja7dF3PgUea4=
|
||||
github.com/aquasecurity/table v1.5.1 h1:y05AuHM3p4BGybbGn/XbcTX3RxpyzeTXAXYMcJve4IE=
|
||||
github.com/aquasecurity/table v1.5.1/go.mod h1:1MFKrEPJ8NchM917BrVGvsqoXJo1OL1Ja7dF3PgUea4=
|
||||
github.com/aquasecurity/testdocker v0.0.0-20210911155206-e1e85f5a1516 h1:moQmzbpLo5dxHQCyEhqzizsDSNrNhn/7uRTCZzo4A1o=
|
||||
github.com/aquasecurity/trivy-db v0.0.0-20220327074450-74195d9604b2 h1:q2Gza4V8uO5C1COzC2HeTbQgJIrmC6dTWaXZ8ujiWu0=
|
||||
github.com/aquasecurity/trivy-db v0.0.0-20220327074450-74195d9604b2/go.mod h1:EwiQRdzVq6k7cKOMjkss8LjWMt2FUW7NaYwE7HfZZvk=
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
|
||||
"github.com/aquasecurity/trivy-db/pkg/metadata"
|
||||
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/commands/artifact"
|
||||
"github.com/aquasecurity/trivy/pkg/commands/option"
|
||||
"github.com/aquasecurity/trivy/pkg/commands/plugin"
|
||||
@@ -215,6 +216,12 @@ var (
|
||||
EnvVars: []string{"TRIVY_K8S_NAMESPACE"},
|
||||
}
|
||||
|
||||
reportFlag = cli.StringFlag{
|
||||
Name: "report",
|
||||
Value: "summary",
|
||||
Usage: "specify a report format for the output. (all,summary default: all)",
|
||||
}
|
||||
|
||||
// TODO: remove this flag after a sufficient deprecation period.
|
||||
lightFlag = cli.BoolFlag{
|
||||
Name: "light",
|
||||
@@ -789,6 +796,7 @@ func NewK8sCommand() *cli.Command {
|
||||
Action: artifact.K8sRun,
|
||||
Flags: []cli.Flag{
|
||||
&namespaceFlag,
|
||||
&reportFlag,
|
||||
&outputFlag,
|
||||
&severityFlag,
|
||||
&exitCodeFlag,
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"github.com/aquasecurity/fanal/analyzer"
|
||||
"github.com/aquasecurity/fanal/cache"
|
||||
"github.com/aquasecurity/trivy-db/pkg/db"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
pkgReport "github.com/aquasecurity/trivy/pkg/report"
|
||||
k8sReport "github.com/aquasecurity/trivy/pkg/report/k8s"
|
||||
@@ -76,9 +77,9 @@ func K8sRun(ctx *cli.Context) error {
|
||||
report.ClusterName = cluster.GetCurrentContext()
|
||||
|
||||
if err = k8sReport.Write(report, pkgReport.Option{
|
||||
Format: "json", // for now json is the default
|
||||
Format: opt.KubernetesOption.ReportFormat, // for now json is the default
|
||||
Output: opt.Output,
|
||||
}); err != nil {
|
||||
}, opt.Severities); err != nil {
|
||||
return xerrors.Errorf("unable to write results: %w", err)
|
||||
}
|
||||
|
||||
|
||||
@@ -6,12 +6,14 @@ import (
|
||||
|
||||
// KubernetesOption holds the options for Kubernetes scanning
|
||||
type KubernetesOption struct {
|
||||
Namespace string
|
||||
Namespace string
|
||||
ReportFormat string
|
||||
}
|
||||
|
||||
// NewKubernetesOption is the factory method to return Kubernetes options
|
||||
func NewKubernetesOption(c *cli.Context) KubernetesOption {
|
||||
return KubernetesOption{
|
||||
Namespace: c.String("namespace"),
|
||||
Namespace: c.String("namespace"),
|
||||
ReportFormat: c.String("report"),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ package k8s
|
||||
import (
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/report"
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
)
|
||||
@@ -15,26 +17,33 @@ type Report struct {
|
||||
Misconfigurations []Resource `json:",omitempty"`
|
||||
}
|
||||
|
||||
// ConsolidatedReport represents a kubernetes scan report with consolidated findings
|
||||
type ConsolidatedReport struct {
|
||||
SchemaVersion int `json:",omitempty"`
|
||||
ClusterName string
|
||||
Findings []Resource `json:",omitempty"`
|
||||
}
|
||||
|
||||
// Resource represents a kubernetes resource report
|
||||
type Resource struct {
|
||||
Namespace string `json:",omitempty"`
|
||||
Kind string
|
||||
Name string
|
||||
//TODO(josedonizetti): should add metadata? per report? per Result?
|
||||
//Metadata Metadata `json:",omitempty"`
|
||||
// TODO(josedonizetti): should add metadata? per report? per Result?
|
||||
// Metadata Metadata `json:",omitempty"`
|
||||
Results types.Results `json:",omitempty"`
|
||||
Error string `json:",omitempty"`
|
||||
}
|
||||
|
||||
// Failed returns whether the k8s report includes any vulnerabilities or misconfigurations
|
||||
func (report Report) Failed() bool {
|
||||
for _, r := range report.Vulnerabilities {
|
||||
func (r Report) Failed() bool {
|
||||
for _, r := range r.Vulnerabilities {
|
||||
if r.Results.Failed() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
for _, r := range report.Misconfigurations {
|
||||
for _, r := range r.Misconfigurations {
|
||||
if r.Results.Failed() {
|
||||
return true
|
||||
}
|
||||
@@ -43,17 +52,47 @@ func (report Report) Failed() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (r Report) consolidate() ConsolidatedReport {
|
||||
consolidated := ConsolidatedReport{
|
||||
SchemaVersion: r.SchemaVersion,
|
||||
ClusterName: r.ClusterName,
|
||||
}
|
||||
|
||||
for _, m := range r.Misconfigurations {
|
||||
found := false
|
||||
for _, v := range r.Vulnerabilities {
|
||||
if v.Kind == m.Kind && v.Name == m.Name && v.Namespace == m.Namespace {
|
||||
consolidated.Findings = append(consolidated.Findings, Resource{
|
||||
Namespace: v.Namespace,
|
||||
Kind: v.Kind,
|
||||
Name: v.Name,
|
||||
Results: append(v.Results, m.Results...),
|
||||
Error: v.Error,
|
||||
})
|
||||
found = true
|
||||
continue
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
consolidated.Findings = append(consolidated.Findings, m)
|
||||
}
|
||||
}
|
||||
return consolidated
|
||||
}
|
||||
|
||||
// Writer defines the result write operation
|
||||
type Writer interface {
|
||||
Write(Report) error
|
||||
}
|
||||
|
||||
// Write writes the results in the give format
|
||||
func Write(report Report, option report.Option) error {
|
||||
func Write(report Report, option report.Option, severities []dbTypes.Severity) error {
|
||||
var writer Writer
|
||||
switch option.Format {
|
||||
case "json":
|
||||
case "all":
|
||||
writer = &JSONWriter{Output: option.Output}
|
||||
case "summary":
|
||||
writer = NewSummaryWriter(option.Output, severities)
|
||||
default:
|
||||
return xerrors.Errorf("unknown format: %v", option.Format)
|
||||
}
|
||||
|
||||
159
pkg/report/k8s/summary.go
Normal file
159
pkg/report/k8s/summary.go
Normal file
@@ -0,0 +1,159 @@
|
||||
package k8s
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/aquasecurity/table"
|
||||
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||
|
||||
"github.com/liamg/tml"
|
||||
)
|
||||
|
||||
type SummaryWriter struct {
|
||||
Output io.Writer
|
||||
Severities []string
|
||||
SeverityHeadings []string
|
||||
}
|
||||
|
||||
func NewSummaryWriter(output io.Writer, requiredSevs []dbTypes.Severity) SummaryWriter {
|
||||
var severities []string
|
||||
var severityHeadings []string
|
||||
severities, severityHeadings = getRequiredSeverities(requiredSevs)
|
||||
return SummaryWriter{
|
||||
Output: output,
|
||||
Severities: severities,
|
||||
SeverityHeadings: severityHeadings,
|
||||
}
|
||||
}
|
||||
|
||||
// Write writes the results in a summarized table format
|
||||
func (s SummaryWriter) Write(report Report) error {
|
||||
consolidated := report.consolidate()
|
||||
_, _ = fmt.Fprintln(s.Output)
|
||||
_, _ = fmt.Fprintf(s.Output, "Summary Report for %s\n", consolidated.ClusterName)
|
||||
|
||||
t := table.New(s.Output)
|
||||
t.SetRowLines(false)
|
||||
configureHeader(s, t)
|
||||
|
||||
sort.Slice(consolidated.Findings, func(i, j int) bool {
|
||||
return consolidated.Findings[i].Namespace > consolidated.Findings[j].Namespace
|
||||
})
|
||||
|
||||
for _, finding := range consolidated.Findings {
|
||||
if !finding.Results.Failed() {
|
||||
continue
|
||||
}
|
||||
vCount, mCount, sCount := accumulateSeverityCounts(finding)
|
||||
name := fmt.Sprintf("%s/%s", finding.Kind, finding.Name)
|
||||
rowParts := []string{finding.Namespace, name}
|
||||
rowParts = append(rowParts, s.generateSummary(vCount)...)
|
||||
rowParts = append(rowParts, s.generateSummary(mCount)...)
|
||||
rowParts = append(rowParts, s.generateSummary(sCount)...)
|
||||
|
||||
t.AddRow(rowParts...)
|
||||
}
|
||||
|
||||
t.Render()
|
||||
|
||||
keyParts := []string{"Severities:"}
|
||||
for _, s := range s.Severities {
|
||||
keyParts = append(keyParts, fmt.Sprintf("%s=%s", s[:1], colourSeverityValue(s, s)))
|
||||
}
|
||||
|
||||
_, _ = fmt.Fprintln(s.Output, strings.Join(keyParts, " "))
|
||||
_, _ = fmt.Fprintln(s.Output)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s SummaryWriter) generateSummary(sevCount map[string]int) []string {
|
||||
var parts []string
|
||||
|
||||
for _, sev := range s.Severities {
|
||||
if count, ok := sevCount[sev]; ok {
|
||||
parts = append(parts, colourSeverityValue(strconv.Itoa(count), sev))
|
||||
} else {
|
||||
parts = append(parts, " ")
|
||||
}
|
||||
}
|
||||
|
||||
return parts
|
||||
}
|
||||
|
||||
func getRequiredSeverities(requiredSevs []dbTypes.Severity) ([]string, []string) {
|
||||
requiredSevOrder := []dbTypes.Severity{dbTypes.SeverityCritical,
|
||||
dbTypes.SeverityHigh, dbTypes.SeverityMedium,
|
||||
dbTypes.SeverityLow, dbTypes.SeverityUnknown}
|
||||
var severities []string
|
||||
var severityHeadings []string
|
||||
for _, sev := range requiredSevOrder {
|
||||
for _, p := range requiredSevs {
|
||||
if p == sev {
|
||||
severities = append(severities, sev.String())
|
||||
severityHeadings = append(severityHeadings, strings.ToUpper(sev.String()[:1]))
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
return severities, severityHeadings
|
||||
}
|
||||
|
||||
func accumulateSeverityCounts(finding Resource) (map[string]int, map[string]int, map[string]int) {
|
||||
vCount := make(map[string]int)
|
||||
mCount := make(map[string]int)
|
||||
sCount := make(map[string]int)
|
||||
for _, r := range finding.Results {
|
||||
for _, rv := range r.Vulnerabilities {
|
||||
vCount[rv.Severity] = vCount[rv.Severity] + 1
|
||||
}
|
||||
for _, rv := range r.Misconfigurations {
|
||||
mCount[rv.Severity] = mCount[rv.Severity] + 1
|
||||
}
|
||||
for _, rv := range r.Secrets {
|
||||
sCount[rv.Severity] = sCount[rv.Severity] + 1
|
||||
}
|
||||
}
|
||||
return vCount, mCount, sCount
|
||||
}
|
||||
|
||||
func configureHeader(s SummaryWriter, t *table.Table) {
|
||||
sevCount := len(s.Severities)
|
||||
|
||||
headerRow := []string{"Namespace", "Resource"}
|
||||
// vulnerabilities headings
|
||||
headerRow = append(headerRow, s.SeverityHeadings...)
|
||||
// misconfig headings
|
||||
headerRow = append(headerRow, s.SeverityHeadings...)
|
||||
// secrets headings
|
||||
headerRow = append(headerRow, s.SeverityHeadings...)
|
||||
headerAlignment := []table.Alignment{table.AlignLeft, table.AlignLeft}
|
||||
|
||||
for i := 0; i < len(headerRow)-2; i++ {
|
||||
headerAlignment = append(headerAlignment, table.AlignCenter)
|
||||
}
|
||||
|
||||
t.SetHeaders("Namespace", "Resource", "Vulnerabilities", "Misconfigurations", "Secrets")
|
||||
t.AddHeaders(headerRow...)
|
||||
t.SetAlignment(headerAlignment...)
|
||||
t.SetAutoMergeHeaders(true)
|
||||
t.SetHeaderColSpans(0, 1, 1, sevCount, sevCount, sevCount)
|
||||
}
|
||||
|
||||
func colourSeverityValue(value string, severity string) string {
|
||||
switch severity {
|
||||
case "CRITICAL":
|
||||
return tml.Sprintf("<bold><red>%s</red></bold>", value)
|
||||
case "HIGH":
|
||||
return tml.Sprintf("<red>%s</red>", value)
|
||||
case "MEDIUM":
|
||||
return tml.Sprintf("<yellow>%s</yellow>", value)
|
||||
case "UNKNOWN":
|
||||
return tml.Sprintf("<blue>%s</blue>", value)
|
||||
default:
|
||||
return tml.Sprintf("%s", value)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user