Files
trivy/pkg/k8s/writer_test.go
chenk 35c4262d0b feat(k8s): cyclonedx kbom support (#4557)
* feat: cyclonedx kbom support

Signed-off-by: chenk <hen.keinan@gmail.com>

* feat: cyclonedx kbom support

Signed-off-by: chenk <hen.keinan@gmail.com>

* feat: kubernetes bill of materials

Signed-off-by: chenk <hen.keinan@gmail.com>

* feat: kubernetes bill of materials

Signed-off-by: chenk <hen.keinan@gmail.com>

* feat: kubernetes bill of materials

Signed-off-by: chenk <hen.keinan@gmail.com>

* feat: kubernetes bill of materials

Signed-off-by: chenk <hen.keinan@gmail.com>

* feat: kubernetes bill of materials

Signed-off-by: chenk <hen.keinan@gmail.com>

* feat: kubernetes bill of materials

Signed-off-by: chenk <hen.keinan@gmail.com>

* chore: update sum db

Signed-off-by: chenk <hen.keinan@gmail.com>

* chore: update sum db

Signed-off-by: chenk <hen.keinan@gmail.com>

* feat: kubernetes bill of materials

Signed-off-by: chenk <hen.keinan@gmail.com>

* feat: kubernetes bill of materials

Signed-off-by: chenk <hen.keinan@gmail.com>

* chore: update sumdb

Signed-off-by: chenk <hen.keinan@gmail.com>

* chore: update sumdb

Signed-off-by: chenk <hen.keinan@gmail.com>

* feat: kubernetes bill of materials

Signed-off-by: chenk <hen.keinan@gmail.com>

* feat: kubernetes bill of materials

Signed-off-by: chenk <hen.keinan@gmail.com>

---------

Signed-off-by: chenk <hen.keinan@gmail.com>
2023-06-19 10:48:26 +00:00

410 lines
16 KiB
Go

package k8s
import (
"bytes"
"regexp"
"strings"
"testing"
"github.com/stretchr/testify/assert"
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/k8s/report"
"github.com/aquasecurity/trivy/pkg/types"
)
const (
AllReport = "all"
SummaryReport = "summary"
tableFormat = "table"
jsonFormat = "json"
cycloneDXFormat = "cyclonedx"
workloadComponent = "workload"
infraComponent = "infra"
)
var (
roleWithMisconfig = report.Resource{
Namespace: "default",
Kind: "Role",
Name: "system::leader-locking-kube-controller-manager",
Results: types.Results{
{
Misconfigurations: []types.DetectedMisconfiguration{
{
ID: "ID100",
Status: types.StatusFailure,
Severity: "MEDIUM",
},
},
},
},
}
apiseverPodWithMisconfigAndInfra = report.Resource{
Namespace: "kube-system",
Kind: "Pod",
Name: "kube-apiserver",
Results: types.Results{
{
Misconfigurations: []types.DetectedMisconfiguration{
{
ID: "KSV-ID100",
Status: types.StatusFailure,
Severity: "LOW",
},
{
ID: "KSV-ID101",
Status: types.StatusFailure,
Severity: "MEDIUM",
},
{
ID: "KSV-ID102",
Status: types.StatusFailure,
Severity: "HIGH",
},
{
ID: "KCV-ID100",
Status: types.StatusFailure,
Severity: "LOW",
},
{
ID: "KCV-ID101",
Status: types.StatusFailure,
Severity: "MEDIUM",
},
},
},
},
}
deployLuaWithSecrets = report.Resource{
Namespace: "default",
Kind: "Deploy",
Name: "lua",
Results: types.Results{
{
Secrets: []ftypes.SecretFinding{
{
RuleID: "secret1",
Severity: "CRITICAL",
},
{
RuleID: "secret2",
Severity: "MEDIUM",
},
},
},
},
}
deployOrionWithMisconfigs = report.Resource{
Namespace: "default",
Kind: "Deploy",
Name: "orion",
Results: types.Results{
{
Misconfigurations: []types.DetectedMisconfiguration{
{
ID: "ID100",
Status: types.StatusFailure,
Severity: "LOW",
},
{
ID: "ID101",
Status: types.StatusFailure,
Severity: "MEDIUM",
},
{
ID: "ID102",
Status: types.StatusFailure,
Severity: "HIGH",
},
{
ID: "ID103",
Status: types.StatusFailure,
Severity: "CRITICAL",
},
{
ID: "ID104",
Status: types.StatusFailure,
Severity: "UNKNOWN",
},
{
ID: "ID105",
Status: types.StatusFailure,
Severity: "LOW",
},
{
ID: "ID106",
Status: types.StatusFailure,
Severity: "HIGH",
},
},
},
},
}
deployOrionWithVulns = report.Resource{
Namespace: "default",
Kind: "Deploy",
Name: "orion",
Results: types.Results{
{
Vulnerabilities: []types.DetectedVulnerability{
{
VulnerabilityID: "CVE-2022-1111",
Vulnerability: dbTypes.Vulnerability{Severity: "LOW"},
},
{
VulnerabilityID: "CVE-2022-2222",
Vulnerability: dbTypes.Vulnerability{Severity: "MEDIUM"},
},
{
VulnerabilityID: "CVE-2022-3333",
Vulnerability: dbTypes.Vulnerability{Severity: "HIGH"},
},
{
VulnerabilityID: "CVE-2022-4444",
Vulnerability: dbTypes.Vulnerability{Severity: "CRITICAL"},
},
{
VulnerabilityID: "CVE-2022-5555",
Vulnerability: dbTypes.Vulnerability{Severity: "UNKNOWN"},
},
{
VulnerabilityID: "CVE-2022-6666",
Vulnerability: dbTypes.Vulnerability{Severity: "CRITICAL"},
},
{
VulnerabilityID: "CVE-2022-7777",
Vulnerability: dbTypes.Vulnerability{Severity: "MEDIUM"},
},
},
},
},
}
)
func TestReportWrite_Summary(t *testing.T) {
allSeverities := []dbTypes.Severity{
dbTypes.SeverityUnknown,
dbTypes.SeverityLow,
dbTypes.SeverityMedium,
dbTypes.SeverityHigh,
dbTypes.SeverityCritical,
}
tests := []struct {
name string
report report.Report
opt report.Option
scanners types.Scanners
components []string
severities []dbTypes.Severity
expectedOutput string
}{
{
name: "Only config, all serverities",
report: report.Report{
ClusterName: "test",
Resources: []report.Resource{deployOrionWithMisconfigs},
},
scanners: types.Scanners{types.MisconfigScanner},
components: []string{workloadComponent},
severities: allSeverities,
expectedOutput: `Summary Report for test
=======================
Workload Assessment
┌───────────┬──────────────┬───────────────────┐
│ Namespace │ Resource │ Misconfigurations │
│ │ ├───┬───┬───┬───┬───┤
│ │ │ C │ H │ M │ L │ U │
├───────────┼──────────────┼───┼───┼───┼───┼───┤
│ default │ Deploy/orion │ 1 │ 2 │ 1 │ 2 │ 1 │
└───────────┴──────────────┴───┴───┴───┴───┴───┘
Severities: C=CRITICAL H=HIGH M=MEDIUM L=LOW U=UNKNOWN`,
},
{
name: "Only vuln, all serverities",
report: report.Report{
ClusterName: "test",
Resources: []report.Resource{deployOrionWithVulns},
},
scanners: types.Scanners{types.VulnerabilityScanner},
severities: allSeverities,
expectedOutput: `Summary Report for test
=======================
Workload Assessment
┌───────────┬──────────────┬───────────────────┐
│ Namespace │ Resource │ Vulnerabilities │
│ │ ├───┬───┬───┬───┬───┤
│ │ │ C │ H │ M │ L │ U │
├───────────┼──────────────┼───┼───┼───┼───┼───┤
│ default │ Deploy/orion │ 2 │ 1 │ 2 │ 1 │ 1 │
└───────────┴──────────────┴───┴───┴───┴───┴───┘
Severities: C=CRITICAL H=HIGH M=MEDIUM L=LOW U=UNKNOWN`,
},
{
name: "Only rbac, all serverities",
report: report.Report{
ClusterName: "test",
Resources: []report.Resource{roleWithMisconfig},
},
scanners: types.Scanners{types.RBACScanner},
severities: allSeverities,
expectedOutput: `Summary Report for test
=======================
RBAC Assessment
┌───────────┬─────────────────────────────────────────────────────┬───────────────────┐
│ Namespace │ Resource │ RBAC Assessment │
│ │ ├───┬───┬───┬───┬───┤
│ │ │ C │ H │ M │ L │ U │
├───────────┼─────────────────────────────────────────────────────┼───┼───┼───┼───┼───┤
│ default │ Role/system::leader-locking-kube-controller-manager │ │ │ 1 │ │ │
└───────────┴─────────────────────────────────────────────────────┴───┴───┴───┴───┴───┘
Severities: C=CRITICAL H=HIGH M=MEDIUM L=LOW U=UNKNOWN`,
},
{
name: "Only secret, all serverities",
report: report.Report{
ClusterName: "test",
Resources: []report.Resource{deployLuaWithSecrets},
},
scanners: types.Scanners{types.SecretScanner},
severities: allSeverities,
expectedOutput: `Summary Report for test
=======================
Workload Assessment
┌───────────┬────────────┬───────────────────┐
│ Namespace │ Resource │ Secrets │
│ │ ├───┬───┬───┬───┬───┤
│ │ │ C │ H │ M │ L │ U │
├───────────┼────────────┼───┼───┼───┼───┼───┤
│ default │ Deploy/lua │ 1 │ │ 1 │ │ │
└───────────┴────────────┴───┴───┴───┴───┴───┘
Severities: C=CRITICAL H=HIGH M=MEDIUM L=LOW U=UNKNOWN`,
},
{
name: "apiserver, only infra and serverities",
report: report.Report{
ClusterName: "test",
Resources: []report.Resource{apiseverPodWithMisconfigAndInfra},
},
scanners: types.Scanners{types.MisconfigScanner},
components: []string{infraComponent},
severities: allSeverities,
expectedOutput: `Summary Report for test
=======================
Infra Assessment
┌─────────────┬────────────────────┬─────────────────────────────┐
│ Namespace │ Resource │ Kubernetes Infra Assessment │
│ │ ├─────┬─────┬─────┬─────┬─────┤
│ │ │ C │ H │ M │ L │ U │
├─────────────┼────────────────────┼─────┼─────┼─────┼─────┼─────┤
│ kube-system │ Pod/kube-apiserver │ │ │ 1 │ 1 │ │
└─────────────┴────────────────────┴─────┴─────┴─────┴─────┴─────┘
Severities: C=CRITICAL H=HIGH M=MEDIUM L=LOW U=UNKNOWN`,
},
{
name: "apiserver, vuln,config,secret and serverities",
report: report.Report{
ClusterName: "test",
Resources: []report.Resource{apiseverPodWithMisconfigAndInfra},
},
scanners: types.Scanners{
types.VulnerabilityScanner,
types.MisconfigScanner,
types.SecretScanner,
},
components: []string{workloadComponent},
severities: allSeverities,
expectedOutput: `Summary Report for test
=======================
Workload Assessment
┌─────────────┬────────────────────┬───────────────────┬───────────────────┬───────────────────┐
│ Namespace │ Resource │ Vulnerabilities │ Misconfigurations │ Secrets │
│ │ ├───┬───┬───┬───┬───┼───┬───┬───┬───┬───┼───┬───┬───┬───┬───┤
│ │ │ C │ H │ M │ L │ U │ C │ H │ M │ L │ U │ C │ H │ M │ L │ U │
├─────────────┼────────────────────┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┤
│ kube-system │ Pod/kube-apiserver │ │ │ │ │ │ │ 1 │ 1 │ 1 │ │ │ │ │ │ │
└─────────────┴────────────────────┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘
Severities: C=CRITICAL H=HIGH M=MEDIUM L=LOW U=UNKNOWN`,
},
{
name: "apiserver, all scanners and serverities",
report: report.Report{
ClusterName: "test",
Resources: []report.Resource{apiseverPodWithMisconfigAndInfra},
},
scanners: types.Scanners{
types.MisconfigScanner,
types.VulnerabilityScanner,
types.RBACScanner,
types.SecretScanner,
},
components: []string{
workloadComponent,
infraComponent,
},
severities: allSeverities,
expectedOutput: `Summary Report for test
=======================
Workload Assessment
┌─────────────┬────────────────────┬───────────────────┬───────────────────┬───────────────────┐
│ Namespace │ Resource │ Vulnerabilities │ Misconfigurations │ Secrets │
│ │ ├───┬───┬───┬───┬───┼───┬───┬───┬───┬───┼───┬───┬───┬───┬───┤
│ │ │ C │ H │ M │ L │ U │ C │ H │ M │ L │ U │ C │ H │ M │ L │ U │
├─────────────┼────────────────────┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┤
│ kube-system │ Pod/kube-apiserver │ │ │ │ │ │ │ 1 │ 1 │ 1 │ │ │ │ │ │ │
└─────────────┴────────────────────┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘
Severities: C=CRITICAL H=HIGH M=MEDIUM L=LOW U=UNKNOWN
Infra Assessment
┌─────────────┬────────────────────┬─────────────────────────────┐
│ Namespace │ Resource │ Kubernetes Infra Assessment │
│ │ ├─────┬─────┬─────┬─────┬─────┤
│ │ │ C │ H │ M │ L │ U │
├─────────────┼────────────────────┼─────┼─────┼─────┼─────┼─────┤
│ kube-system │ Pod/kube-apiserver │ │ │ 1 │ 1 │ │
└─────────────┴────────────────────┴─────┴─────┴─────┴─────┴─────┘
Severities: C=CRITICAL H=HIGH M=MEDIUM L=LOW U=UNKNOWN`,
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
output := bytes.Buffer{}
opt := report.Option{
Format: "table",
Report: "summary",
Output: &output,
Scanners: tc.scanners,
Severities: tc.severities,
Components: tc.components,
}
Write(tc.report, opt)
assert.Equal(t, tc.expectedOutput, stripAnsi(output.String()), tc.name)
})
}
}
const ansi = "[\u001B\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[a-zA-Z\\d]*)*)?\u0007)|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PRZcf-ntqry=><~]))"
var ansiRegexp = regexp.MustCompile(ansi)
func stripAnsi(str string) string {
return strings.TrimSpace(ansiRegexp.ReplaceAllString(str, ""))
}