diff --git a/cmd/commands/root.go b/cmd/commands/root.go index c22ac36e..55ea53fb 100644 --- a/cmd/commands/root.go +++ b/cmd/commands/root.go @@ -81,12 +81,11 @@ func runAudit(auditable ...kubeaudit.Auditable) func(cmd *cobra.Command, args [] } if rootConfig.sarifOut != "" { - sarifReport, sarifRun, err := sarif.CreateSarifReport() + sarifReport, sarifRun, err := sarif.New() if err != nil { panic(err) } - sarif.AddSarifRules(report, sarifRun) - sarif.AddSarifResult(report, sarifRun) + sarif.Create(report, sarifRun) sarifReport.WriteFile(rootConfig.sarifOut) } diff --git a/internal/sarif/fixtures/apparmor-disabled.yaml b/internal/sarif/fixtures/apparmor-disabled.yaml index b2593ab1..a67bf336 100644 --- a/internal/sarif/fixtures/apparmor-disabled.yaml +++ b/internal/sarif/fixtures/apparmor-disabled.yaml @@ -5,7 +5,3 @@ metadata: namespace: apparmor-disabled annotations: container.apparmor.security.beta.kubernetes.io/container: badval -spec: - containers: - - name: container - image: scratch diff --git a/internal/sarif/fixtures/capabilities-added.yaml b/internal/sarif/fixtures/capabilities-added.yaml index f5138302..a504c250 100644 --- a/internal/sarif/fixtures/capabilities-added.yaml +++ b/internal/sarif/fixtures/capabilities-added.yaml @@ -1,10 +1,5 @@ apiVersion: apps/v1 kind: Deployment -metadata: - name: deployment - namespace: capabilities-added - annotations: - container.apparmor.security.beta.kubernetes.io/container: badval spec: selector: matchLabels: diff --git a/internal/sarif/sarif.go b/internal/sarif/sarif.go index 71cb55cb..f65825fa 100644 --- a/internal/sarif/sarif.go +++ b/internal/sarif/sarif.go @@ -21,7 +21,7 @@ import ( "github.com/owenrumney/go-sarif/v2/sarif" ) -var AuditorNames = map[string]string{ +var Auditors = map[string]string{ apparmor.Name: "Finds containers that do not have AppArmor enabled", asat.Name: "Finds containers where the deprecated SA field is used or with a mounted default SA", capabilities.Name: "Finds containers that do not drop the recommended capabilities or add new ones", @@ -37,8 +37,8 @@ var AuditorNames = map[string]string{ seccomp.Name: "Finds containers running without seccomp", } -// CreateSarifReport creates a new sarif Report and Run or returns an error -func CreateSarifReport() (*sarif.Report, *sarif.Run, error) { +// New creates a new sarif Report and Run or returns an error +func New() (*sarif.Report, *sarif.Run, error) { // create a new report object report, err := sarif.New(sarif.Version210) if err != nil { @@ -53,7 +53,8 @@ func CreateSarifReport() (*sarif.Report, *sarif.Run, error) { return report, run, nil } -func AddSarifRules(kubeauditReport *kubeaudit.Report, run *sarif.Run) { +// Create adds SARIF rules to the run and adds results to the report +func Create(kubeauditReport *kubeaudit.Report, run *sarif.Run) { var results []*kubeaudit.AuditResult for _, reportResult := range kubeauditReport.Results() { @@ -62,16 +63,18 @@ func AddSarifRules(kubeauditReport *kubeaudit.Report, run *sarif.Run) { } for _, result := range results { + severityLevel := result.Severity.String() auditor := strings.ToLower(result.Auditor) ruleID := strings.ToLower(result.Rule) - var docsURL string + var docsURL string if strings.Contains(ruleID, auditor) { docsURL = "https://github.com/Shopify/kubeaudit/blob/main/docs/auditors/" + auditor + ".md" } - helpMessage := fmt.Sprintf("**Type**: kubernetes\n**Docs**: %s\n**Description:** %s", docsURL, AuditorNames[auditor]) + helpMessage := fmt.Sprintf("**Type**: kubernetes\n**Docs**: %s\n**Description:** %s", docsURL, Auditors[auditor]) + // we only add rules to the report based on the result findings run.AddRule(result.Rule). WithName(result.Auditor). WithMarkdownHelp(helpMessage). @@ -83,32 +86,19 @@ func AddSarifRules(kubeauditReport *kubeaudit.Report, run *sarif.Run) { }, "precision": "very-high", }) - } -} - -func AddSarifResult(kubeauditReport *kubeaudit.Report, run *sarif.Run) { - var results []*kubeaudit.AuditResult - - for _, reportResult := range kubeauditReport.Results() { - r := reportResult.GetAuditResults() - results = append(results, r...) - } - - for _, r := range results { - severityLevel := r.Severity.String() // SARIF specifies the following severity levels: warning, error, note and none // https://docs.oasis-open.org/sarif/sarif/v2.1.0/sarif-v2.1.0.html // so we're converting info to none here so we get valid SARIF output - if r.Severity.String() == "info" { + if result.Severity.String() == "info" { severityLevel = "note" } location := sarif.NewPhysicalLocation(). - WithArtifactLocation(sarif.NewSimpleArtifactLocation(r.FilePath).WithUriBaseId("ROOTPATH")). + WithArtifactLocation(sarif.NewSimpleArtifactLocation(result.FilePath).WithUriBaseId("ROOTPATH")). WithRegion(sarif.NewRegion().WithStartLine(1)) - result := sarif.NewRuleResult(r.Rule). - WithMessage(sarif.NewTextMessage(r.Message)). + result := sarif.NewRuleResult(result.Rule). + WithMessage(sarif.NewTextMessage(result.Message)). WithLevel(severityLevel). WithLocations([]*sarif.Location{sarif.NewLocation().WithPhysicalLocation(location)}) run.AddResult(result) diff --git a/internal/sarif/sarif_test.go b/internal/sarif/sarif_test.go index 07401d3e..b856be31 100644 --- a/internal/sarif/sarif_test.go +++ b/internal/sarif/sarif_test.go @@ -8,34 +8,49 @@ import ( "github.com/Shopify/kubeaudit" "github.com/Shopify/kubeaudit/auditors/apparmor" "github.com/Shopify/kubeaudit/auditors/capabilities" + "github.com/Shopify/kubeaudit/auditors/seccomp" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) -func TestCreateSarifReport(t *testing.T) { - sarifReport, _, err := CreateSarifReport() +func TestNew(t *testing.T) { + sarifReport, _, err := New() require.NoError(t, err) require.Len(t, sarifReport.Runs, 1) assert.Equal(t, "https://github.com/Shopify/kubeaudit", *sarifReport.Runs[0].Tool.Driver.InformationURI) } -func TestAddSarifResultToReport(t *testing.T) { +func TestCreate(t *testing.T) { capabilitiesAuditable := capabilities.New(capabilities.Config{}) apparmorAuditable := apparmor.New() - - auditables := []kubeaudit.Auditable{capabilitiesAuditable, apparmorAuditable} + seccompAuditable := seccomp.New() cases := []struct { - file string - auditor string + file string + auditorName string + auditors []kubeaudit.Auditable + expectedRules int }{ - {"apparmor-disabled.yaml", apparmor.Name}, - {"capabilities-added.yaml", capabilities.Name}, + {"apparmor-disabled.yaml", + apparmor.Name, + []kubeaudit.Auditable{apparmorAuditable}, + 1, + }, + {"capabilities-added.yaml", + capabilities.Name, + []kubeaudit.Auditable{capabilitiesAuditable, seccompAuditable}, + 2, + }, + {"capabilities-added.yaml", + capabilities.Name, + []kubeaudit.Auditable{capabilitiesAuditable}, + 1, + }, } for _, tc := range cases { fixture := filepath.Join("fixtures", tc.file) - auditor, err := kubeaudit.New(auditables) + auditor, err := kubeaudit.New(tc.auditors) require.NoError(t, err) manifest, openErr := os.Open(fixture) @@ -45,6 +60,7 @@ func TestAddSarifResultToReport(t *testing.T) { require.NoError(t, err) // we're only appending sarif to the path here for testing purposes + // this allows us to visualize the sarif output preview correctly for _, reportResult := range kubeAuditReport.Results() { r := reportResult.GetAuditResults() @@ -56,17 +72,12 @@ func TestAddSarifResultToReport(t *testing.T) { // verify that the file path is correct assert.Contains(t, kubeAuditReport.Results()[0].GetAuditResults()[0].FilePath, "sarif/fixtures") - sarifReport, sarifRun, err := CreateSarifReport() - + sarifReport, sarifRun, err := New() require.NoError(t, err) - AddSarifRules(kubeAuditReport, sarifRun) + Create(kubeAuditReport, sarifRun) - // verify that the 2 rules (auditors) enabled have been added to the report - require.Len(t, *&sarifReport.Runs[0].Tool.Driver.Rules, 2) - - AddSarifResult(kubeAuditReport, sarifRun) + // verify that the rules have been added as per report findings + assert.Len(t, sarifReport.Runs[0].Tool.Driver.Rules, tc.expectedRules) } } - -// todo: verify the contents of the report