diff --git a/internal/log/policy_report_logger.go b/internal/log/policy_report_logger.go new file mode 100644 index 00000000..0c191a70 --- /dev/null +++ b/internal/log/policy_report_logger.go @@ -0,0 +1,67 @@ +package log + +import ( + "github.com/kubewarden/audit-scanner/internal/report" + "github.com/rs/zerolog" + "github.com/rs/zerolog/log" +) + +type PolicyReportLogger struct { +} + +// LogClusterPolicyReport will create a log line per each cluster-wide scanned resource +func (l *PolicyReportLogger) LogClusterPolicyReport(report *report.ClusterPolicyReport) { + log.Info(). + Dict("dict", zerolog.Dict(). + Int("pass", report.Summary.Pass). + Int("fail", report.Summary.Fail). + Int("warn", report.Summary.Warn). + Int("error", report.Summary.Error). + Int("skip", report.Summary.Skip)). + Msg("ClusterPolicyReport summary") + + for _, result := range report.Results { + log.Info(). + Dict("dict", zerolog.Dict(). + Str("policy", result.Policy). + Str("rule", result.Rule). + Str("result", string(result.Result)). + Str("message", result.Description). + // although subjects is a list, there's only 1 element + Str("resource_api_version", result.Subjects[0].APIVersion). + Str("resource_kind", result.Subjects[0].Kind). + Str("resource_namespace", result.Subjects[0].Namespace). + Str("resource_name", result.Subjects[0].Name). + Str("resource_version", result.Subjects[0].ResourceVersion)). + Send() + } +} + +// LogPolicyReport will create a log line per each namespace scanned resource. +func (l *PolicyReportLogger) LogPolicyReport(report *report.PolicyReport) { + log.Info(). + Dict("dict", zerolog.Dict(). + Str("name", report.GetName()). + Int("pass", report.Summary.Pass). + Int("fail", report.Summary.Fail). + Int("warn", report.Summary.Warn). + Int("error", report.Summary.Error). + Int("skip", report.Summary.Skip)). + Msg("PolicyReport summary") + + for _, result := range report.Results { + log.Info(). + Dict("dict", zerolog.Dict(). + Str("policy", result.Policy). + Str("rule", result.Rule). + Str("result", string(result.Result)). + Str("message", result.Description). + // although subjects is a list, there's only 1 element + Str("resource_api_version", result.Subjects[0].APIVersion). + Str("resource_kind", result.Subjects[0].Kind). + Str("resource_namespace", result.Subjects[0].Namespace). + Str("resource_name", result.Subjects[0].Name). + Str("resource_version", result.Subjects[0].ResourceVersion)). + Send() + } +} diff --git a/internal/report/store.go b/internal/report/store.go index fcc2dda4..af766e89 100644 --- a/internal/report/store.go +++ b/internal/report/store.go @@ -25,7 +25,4 @@ type PolicyReportStore interface { // SaveClusterPolicyReport instantiates the ClusterPolicyReport if it doesn't exist, or // updates it one is found SaveClusterPolicyReport(report *ClusterPolicyReport) error - - // ToJSON marshals the contents of the store into a JSON string - ToJSON() (string, error) } diff --git a/internal/report/store_kubernetes.go b/internal/report/store_kubernetes.go index c2678da7..2c8836b6 100644 --- a/internal/report/store_kubernetes.go +++ b/internal/report/store_kubernetes.go @@ -2,7 +2,6 @@ package report import ( "context" - "encoding/json" "errors" "fmt" "strings" @@ -13,7 +12,6 @@ import ( errorMachinery "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/util/retry" @@ -208,41 +206,3 @@ func (s *KubernetesPolicyReportStore) SaveClusterPolicyReport(report *ClusterPol } return nil } - -func (s *KubernetesPolicyReportStore) listPolicyReports() ([]PolicyReport, error) { - reportList := polReport.PolicyReportList{} - err := s.client.List(context.Background(), &reportList, &client.ListOptions{ - LabelSelector: labels.SelectorFromSet(labels.Set{LabelAppManagedBy: LabelApp}), - }) - if err != nil { - if errorMachinery.IsNotFound(err) { - return []PolicyReport{}, constants.ErrResourceNotFound - } - return []PolicyReport{}, err - } - results := make([]PolicyReport, 0, len(reportList.Items)) - for _, item := range reportList.Items { - results = append(results, PolicyReport{item}) - } - return results, nil -} - -func (s *KubernetesPolicyReportStore) ToJSON() (string, error) { - recapJSON := make(map[string]interface{}) - clusterReport, err := s.GetClusterPolicyReport(constants.DefaultClusterwideReportName) - if err != nil { - log.Error().Err(err).Msg("error fetching ClusterPolicyReport. Ignoring this error to allow user to read the namespaced reports") - } - recapJSON["cluster"] = clusterReport - nsReports, err := s.listPolicyReports() - if err != nil { - return "", err - } - recapJSON["namespaces"] = nsReports - - marshaled, err := json.Marshal(recapJSON) - if err != nil { - return "", err - } - return string(marshaled), nil -} diff --git a/internal/report/store_memory.go b/internal/report/store_memory.go index 6ad561fc..c6213d41 100644 --- a/internal/report/store_memory.go +++ b/internal/report/store_memory.go @@ -1,13 +1,10 @@ package report import ( - "encoding/json" "errors" "fmt" "strings" - "golang.org/x/exp/maps" - "github.com/kubewarden/audit-scanner/internal/constants" "github.com/rs/zerolog" "github.com/rs/zerolog/log" @@ -134,27 +131,3 @@ func (s *MemoryPolicyReportStore) SaveClusterPolicyReport(report *ClusterPolicyR latestReport.Results = report.Results return s.updateClusterPolicyReport(&latestReport) } - -func (s *MemoryPolicyReportStore) listPolicyReports() ([]PolicyReport, error) { //nolint:unparam // respect the interface - return maps.Values(s.prCache), nil -} - -func (s *MemoryPolicyReportStore) ToJSON() (string, error) { - recapJSON := make(map[string]interface{}) - clusterReport, err := s.GetClusterPolicyReport(constants.DefaultClusterwideReportName) - if err != nil { - log.Error().Err(err).Msg("error fetching ClusterPolicyReport. Ignoring this error to allow user to read the namespaced reports") - } - recapJSON["cluster"] = clusterReport - nsReports, err := s.listPolicyReports() - if err != nil { - return "", err - } - recapJSON["namespaces"] = nsReports - - marshaled, err := json.Marshal(recapJSON) - if err != nil { - return "", err - } - return string(marshaled), nil -} diff --git a/internal/scanner/scanner.go b/internal/scanner/scanner.go index abf0f7d0..2981d68b 100644 --- a/internal/scanner/scanner.go +++ b/internal/scanner/scanner.go @@ -13,6 +13,8 @@ import ( "net/url" "os" + reportLogger "github.com/kubewarden/audit-scanner/internal/log" + "github.com/kubewarden/audit-scanner/internal/constants" "github.com/kubewarden/audit-scanner/internal/report" "github.com/kubewarden/audit-scanner/internal/resources" @@ -49,6 +51,7 @@ type Scanner struct { policiesFetcher PoliciesFetcher resourcesFetcher ResourcesFetcher reportStore report.PolicyReportStore + reportLogger reportLogger.PolicyReportLogger // http client used to make requests against the Policy Server httpClient http.Client outputScan bool @@ -112,6 +115,7 @@ func NewScanner( policiesFetcher: policiesFetcher, resourcesFetcher: resourcesFetcher, reportStore: store, + reportLogger: reportLogger.PolicyReportLogger{}, httpClient: httpClient, outputScan: outputScan, }, nil @@ -180,11 +184,7 @@ func (s *Scanner) ScanNamespace(nsName string) error { log.Info().Str("namespace", nsName).Msg("namespace scan finished") if s.outputScan { - str, err := s.reportStore.ToJSON() - if err != nil { - log.Error().Err(err).Msg("error marshaling reportStore to JSON") - } - fmt.Println(str) //nolint:forbidigo + s.reportLogger.LogPolicyReport(&namespacedsReport) } return nil @@ -251,11 +251,7 @@ func (s *Scanner) ScanClusterWideResources() error { log.Info().Msg("clusterwide resources scan finished") if s.outputScan { - str, err := s.reportStore.ToJSON() - if err != nil { - log.Error().Err(err).Msg("error marshaling reportStore to JSON") - } - fmt.Println(str) //nolint:forbidigo + s.reportLogger.LogClusterPolicyReport(&clusterReport) } return nil