From d714dec985ac2cfb53f4dd1f0917ae1e1fd27eef Mon Sep 17 00:00:00 2001 From: Christoph Hartmann Date: Wed, 3 Apr 2024 23:34:27 +0200 Subject: [PATCH 1/3] =?UTF-8?q?=F0=9F=A7=B9=20refactor=20reporter=20format?= =?UTF-8?q?=20constants?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cli/reporter/aws_sqs_handler.go | 4 +- cli/reporter/azure_service_bus_handler.go | 6 +- cli/reporter/cli_reporter.go | 32 +++++----- cli/reporter/cli_reporter_test.go | 67 ++------------------- cli/reporter/json_test.go | 72 +++++++++++++++++++++++ cli/reporter/print.go | 36 ++++++------ 6 files changed, 116 insertions(+), 101 deletions(-) create mode 100644 cli/reporter/json_test.go diff --git a/cli/reporter/aws_sqs_handler.go b/cli/reporter/aws_sqs_handler.go index 2800c6cd..3aaf9b14 100644 --- a/cli/reporter/aws_sqs_handler.go +++ b/cli/reporter/aws_sqs_handler.go @@ -47,9 +47,9 @@ func (h *awsSqsHandler) WriteReport(ctx context.Context, report *policy.ReportCo func (h *awsSqsHandler) convertReport(report *policy.ReportCollection) ([]byte, error) { switch h.format { - case YAML: + case FormatYAML: return reportToYaml(report) - case JSON: + case FormatJSON: return reportToJson(report) default: return nil, fmt.Errorf("'%s' is not supported in the aws sqs handler, please use one of the other formats", string(h.format)) diff --git a/cli/reporter/azure_service_bus_handler.go b/cli/reporter/azure_service_bus_handler.go index 3ea193fc..9f688d2a 100644 --- a/cli/reporter/azure_service_bus_handler.go +++ b/cli/reporter/azure_service_bus_handler.go @@ -58,7 +58,7 @@ func (h *azureSbusHandler) WriteReport(ctx context.Context, report *policy.Repor msg := &azservicebus.Message{ Body: data, } - if h.format == JSON { + if h.format == FormatJSON { typ := "application/json" msg.ContentType = &typ } @@ -74,9 +74,9 @@ func (h *azureSbusHandler) WriteReport(ctx context.Context, report *policy.Repor func (h *azureSbusHandler) convertReport(report *policy.ReportCollection) ([]byte, error) { switch h.format { - case YAML: + case FormatYAML: return reportToYaml(report) - case JSON: + case FormatJSON: return reportToJson(report) default: return nil, fmt.Errorf("'%s' is not supported in the azure service bus handler, please use one of the other formats", string(h.format)) diff --git a/cli/reporter/cli_reporter.go b/cli/reporter/cli_reporter.go index 1ec51872..44066f34 100644 --- a/cli/reporter/cli_reporter.go +++ b/cli/reporter/cli_reporter.go @@ -109,7 +109,7 @@ func (r *Reporter) WithOutput(out io.Writer) *Reporter { func (r *Reporter) WriteReport(ctx context.Context, data *policy.ReportCollection) error { switch r.Format { - case Compact: + case FormatCompact: rr := &defaultReporter{ Reporter: r, isCompact: true, @@ -117,7 +117,7 @@ func (r *Reporter) WriteReport(ctx context.Context, data *policy.ReportCollectio data: data, } return rr.print() - case Summary: + case FormatSummary: rr := &defaultReporter{ Reporter: r, isCompact: true, @@ -126,7 +126,7 @@ func (r *Reporter) WriteReport(ctx context.Context, data *policy.ReportCollectio data: data, } return rr.print() - case Full: + case FormatFull: rr := &defaultReporter{ Reporter: r, isCompact: false, @@ -134,14 +134,14 @@ func (r *Reporter) WriteReport(ctx context.Context, data *policy.ReportCollectio data: data, } return rr.print() - case Report: + case FormatReport: rr := &reportRenderer{ printer: r.Printer, out: r.out, data: data, } return rr.print() - case YAML: + case FormatYAML: yaml, err := reportToYaml(data) if err != nil { return err @@ -150,13 +150,13 @@ func (r *Reporter) WriteReport(ctx context.Context, data *policy.ReportCollectio _, err = r.out.Write(yaml) return err - case JSON: + case FormatJSON: writer := shared.IOWriter{Writer: r.out} return ReportCollectionToJSON(data, &writer) - case JUnit: + case FormatJUnit: writer := shared.IOWriter{Writer: r.out} return ReportCollectionToJunit(data, &writer) - // case CSV: + // case FormatCSV: // res, err = data.ToCsv() default: return errors.New("unknown reporter type, don't recognize this Format") @@ -165,7 +165,7 @@ func (r *Reporter) WriteReport(ctx context.Context, data *policy.ReportCollectio func (r *Reporter) PrintVulns(data *mvd.VulnReport, target string) error { switch r.Format { - case Compact: + case FormatCompact: rr := &defaultVulnReporter{ Reporter: r, isCompact: true, @@ -174,7 +174,7 @@ func (r *Reporter) PrintVulns(data *mvd.VulnReport, target string) error { target: target, } return rr.print() - case Summary: + case FormatSummary: rr := &defaultVulnReporter{ Reporter: r, isCompact: true, @@ -184,7 +184,7 @@ func (r *Reporter) PrintVulns(data *mvd.VulnReport, target string) error { target: target, } return rr.print() - case Full: + case FormatFull: rr := &defaultVulnReporter{ Reporter: r, isCompact: false, @@ -193,14 +193,14 @@ func (r *Reporter) PrintVulns(data *mvd.VulnReport, target string) error { target: target, } return rr.print() - case Report: + case FormatReport: return errors.New("'report' is not supported for vuln reports, please use one of the other formats") - case JUnit: + case FormatJUnit: return errors.New("'junit' is not supported for vuln reports, please use one of the other formats") - case CSV: + case FormatCSV: writer := shared.IOWriter{Writer: r.out} return VulnReportToCSV(data, &writer) - case YAML: + case FormatYAML: raw := bytes.Buffer{} writer := shared.IOWriter{Writer: &raw} err := VulnReportToJSON(target, data, &writer) @@ -214,7 +214,7 @@ func (r *Reporter) PrintVulns(data *mvd.VulnReport, target string) error { } _, err = r.out.Write(json) return err - case JSON: + case FormatJSON: writer := shared.IOWriter{Writer: r.out} return VulnReportToJSON(target, data, &writer) default: diff --git a/cli/reporter/cli_reporter_test.go b/cli/reporter/cli_reporter_test.go index 7508ca75..4505187e 100644 --- a/cli/reporter/cli_reporter_test.go +++ b/cli/reporter/cli_reporter_test.go @@ -5,7 +5,6 @@ package reporter import ( "bytes" - "context" "encoding/json" "os" "testing" @@ -31,7 +30,7 @@ func TestCompactReporter(t *testing.T) { writer := shared.IOWriter{Writer: &buf} r := &Reporter{ - Format: Compact, + Format: FormatCompact, Printer: &printer.DefaultPrinter, Colors: &colors.DefaultColorTheme, } @@ -61,7 +60,7 @@ func TestVulnReporter(t *testing.T) { buf := bytes.Buffer{} writer := shared.IOWriter{Writer: &buf} - r := NewReporter(Summary, false) + r := NewReporter(FormatSummary, false) r.out = &writer require.NoError(t, err) @@ -69,7 +68,7 @@ func TestVulnReporter(t *testing.T) { err = r.PrintVulns(report, target) require.NoError(t, err) - r = NewReporter(Compact, false) + r = NewReporter(FormatCompact, false) r.out = &writer err = r.PrintVulns(report, target) require.NoError(t, err) @@ -77,7 +76,7 @@ func TestVulnReporter(t *testing.T) { assert.Contains(t, buf.String(), "5.5 libblkid1 2.34-0.1ubuntu9.1") assert.NotContains(t, buf.String(), "USN-5279-1") - r = NewReporter(Full, false) + r = NewReporter(FormatFull, false) r.out = &writer require.NoError(t, err) @@ -87,7 +86,7 @@ func TestVulnReporter(t *testing.T) { assert.Contains(t, buf.String(), "5.5 libblkid1 2.34-0.1ubuntu9.1") assert.Contains(t, buf.String(), "USN-5279-1") - r = NewReporter(YAML, false) + r = NewReporter(FormatYAML, false) r.out = &writer require.NoError(t, err) @@ -99,59 +98,3 @@ func TestVulnReporter(t *testing.T) { assert.Contains(t, buf.String(), "installed: 2.34-0.1ubuntu9.1") assert.Contains(t, buf.String(), "advisory: USN-5279-1") } - -func TestJsonOutput(t *testing.T) { - reportCollectionRaw, err := os.ReadFile("./testdata/report-ubuntu.json") - require.NoError(t, err) - - yr := &policy.ReportCollection{} - err = json.Unmarshal(reportCollectionRaw, yr) - require.NoError(t, err) - - buf := bytes.Buffer{} - writer := shared.IOWriter{Writer: &buf} - - r := &Reporter{ - Format: JSON, - Printer: &printer.DefaultPrinter, - Colors: &colors.DefaultColorTheme, - out: &writer, - } - - err = r.WriteReport(context.Background(), yr) - require.NoError(t, err) - valid := json.Valid(buf.Bytes()) - require.True(t, valid) - - assert.Contains(t, buf.String(), "//policy.api.mondoo.app/queries/mondoo-linux-security-permissions-on-etcgshadow-are-configured\":{\"score\":100,\"status\":\"pass\"}") - assert.Contains(t, buf.String(), "\"errors\":{}") -} - -func TestJsonOutputOnlyErrors(t *testing.T) { - reportCollectionRaw, err := os.ReadFile("./testdata/report-k8s.json") - require.NoError(t, err) - - yr := &policy.ReportCollection{} - err = json.Unmarshal(reportCollectionRaw, yr) - require.NoError(t, err) - - buf := bytes.Buffer{} - writer := shared.IOWriter{Writer: &buf} - - r := &Reporter{ - Format: JSON, - Printer: &printer.DefaultPrinter, - Colors: &colors.DefaultColorTheme, - out: &writer, - } - - err = r.WriteReport(context.Background(), yr) - require.NoError(t, err) - valid := json.Valid(buf.Bytes()) - require.True(t, valid) - - assert.NotContains(t, buf.String(), "{\"score\":100,\"status\":\"pass\"}") - assert.NotContains(t, buf.String(), "\"errors\":{}\"") - - assert.Contains(t, buf.String(), "\"data\":{},\"scores\":{},\"errors\":{\"//policy") -} diff --git a/cli/reporter/json_test.go b/cli/reporter/json_test.go new file mode 100644 index 00000000..dd9b3d2d --- /dev/null +++ b/cli/reporter/json_test.go @@ -0,0 +1,72 @@ +package reporter + +import ( + "bytes" + "context" + "encoding/json" + "os" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.mondoo.com/cnquery/v10/cli/printer" + "go.mondoo.com/cnquery/v10/cli/theme/colors" + "go.mondoo.com/cnquery/v10/shared" + "go.mondoo.com/cnspec/v10/policy" +) + +func TestJsonOutput(t *testing.T) { + reportCollectionRaw, err := os.ReadFile("./testdata/report-ubuntu.json") + require.NoError(t, err) + + yr := &policy.ReportCollection{} + err = json.Unmarshal(reportCollectionRaw, yr) + require.NoError(t, err) + + buf := bytes.Buffer{} + writer := shared.IOWriter{Writer: &buf} + + r := &Reporter{ + Format: FormatJSON, + Printer: &printer.DefaultPrinter, + Colors: &colors.DefaultColorTheme, + out: &writer, + } + + err = r.WriteReport(context.Background(), yr) + require.NoError(t, err) + valid := json.Valid(buf.Bytes()) + require.True(t, valid) + + assert.Contains(t, buf.String(), "//policy.api.mondoo.app/queries/mondoo-linux-security-permissions-on-etcgshadow-are-configured\":{\"score\":100,\"status\":\"pass\"}") + assert.Contains(t, buf.String(), "\"errors\":{}") +} + +func TestJsonOutputOnlyErrors(t *testing.T) { + reportCollectionRaw, err := os.ReadFile("./testdata/report-k8s.json") + require.NoError(t, err) + + yr := &policy.ReportCollection{} + err = json.Unmarshal(reportCollectionRaw, yr) + require.NoError(t, err) + + buf := bytes.Buffer{} + writer := shared.IOWriter{Writer: &buf} + + r := &Reporter{ + Format: FormatJSON, + Printer: &printer.DefaultPrinter, + Colors: &colors.DefaultColorTheme, + out: &writer, + } + + err = r.WriteReport(context.Background(), yr) + require.NoError(t, err) + valid := json.Valid(buf.Bytes()) + require.True(t, valid) + + assert.NotContains(t, buf.String(), "{\"score\":100,\"status\":\"pass\"}") + assert.NotContains(t, buf.String(), "\"errors\":{}\"") + + assert.Contains(t, buf.String(), "\"data\":{},\"scores\":{},\"errors\":{\"//policy") +} diff --git a/cli/reporter/print.go b/cli/reporter/print.go index a157664c..d7474fe1 100644 --- a/cli/reporter/print.go +++ b/cli/reporter/print.go @@ -17,28 +17,28 @@ import ( type Format byte const ( - Compact Format = iota + 1 - Summary - Full - Report - YAML - JSON - JUnit - CSV + FormatCompact Format = iota + 1 + FormatSummary + FormatFull + FormatReport + FormatYAML + FormatJSON + FormatJUnit + FormatCSV ) // Formats that are supported by the reporter var Formats = map[string]Format{ - "compact": Compact, - "summary": Summary, - "full": Full, - "": Compact, - "report": Report, - "yaml": YAML, - "yml": YAML, - "json": JSON, - "junit": JUnit, - "csv": CSV, + "compact": FormatCompact, + "summary": FormatSummary, + "full": FormatFull, + "": FormatCompact, + "report": FormatReport, + "yaml": FormatYAML, + "yml": FormatYAML, + "json": FormatJSON, + "junit": FormatJUnit, + "csv": FormatCSV, } func AllFormats() string { From 91f06363636f52287bbefe3c92e8dd9223998dae Mon Sep 17 00:00:00 2001 From: Christoph Hartmann Date: Thu, 4 Apr 2024 00:09:11 +0200 Subject: [PATCH 2/3] =?UTF-8?q?=E2=AD=90=EF=B8=8F=20use=20proto=20reporter?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Makefile | 5 +- apps/cnspec/cmd/vuln.go | 17 +- cli/reporter/cli_reporter.go | 4 +- cli/reporter/cnspec_report.pb.go | 371 +++++++++++++++++++++++++++++++ cli/reporter/cnspec_report.proto | 26 +++ cli/reporter/json.go | 4 +- cli/reporter/json_test.go | 3 + cli/reporter/junit.go | 4 +- cli/reporter/junit_test.go | 11 +- cli/reporter/output_handler.go | 2 +- cli/reporter/print.go | 2 - cli/reporter/proto.go | 234 +++++++++++++++++++ cli/reporter/proto_test.go | 46 ++++ cli/reporter/reporter.go | 6 + cli/reporter/reporter.pb.go | 279 ----------------------- cli/reporter/reporter.proto | 22 -- 16 files changed, 712 insertions(+), 324 deletions(-) create mode 100644 cli/reporter/cnspec_report.pb.go create mode 100644 cli/reporter/cnspec_report.proto create mode 100644 cli/reporter/proto.go create mode 100644 cli/reporter/proto_test.go create mode 100644 cli/reporter/reporter.go delete mode 100644 cli/reporter/reporter.pb.go delete mode 100644 cli/reporter/reporter.proto diff --git a/Makefile b/Makefile index 29e51e38..b7152dbd 100644 --- a/Makefile +++ b/Makefile @@ -66,7 +66,7 @@ prep/tools: # 🌙 cnspec # -cnspec/generate: clean/proto cli/generate policy/generate +cnspec/generate: clean/proto cli/generate policy/generate reporter/generate .PHONY: cli cli/generate: @@ -78,6 +78,9 @@ policy/generate: go generate ./policy/scan go generate ./internal/bundle/yacit +reporter/generate: + go generate ./cli/reporter + # 🏗 Binary # .PHONY: cnspec/build diff --git a/apps/cnspec/cmd/vuln.go b/apps/cnspec/cmd/vuln.go index 354ef8b1..06c8c3f9 100644 --- a/apps/cnspec/cmd/vuln.go +++ b/apps/cnspec/cmd/vuln.go @@ -4,7 +4,8 @@ package cmd import ( - "bytes" + "strings" + "github.com/rs/zerolog/log" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -13,10 +14,8 @@ import ( "go.mondoo.com/cnquery/v10/providers-sdk/v1/plugin" "go.mondoo.com/cnquery/v10/providers-sdk/v1/upstream/mvd" "go.mondoo.com/cnquery/v10/sbom" - "go.mondoo.com/cnquery/v10/shared" "go.mondoo.com/cnspec/v10/cli/reporter" "go.mondoo.com/cnspec/v10/policy" - "strings" ) func init() { @@ -62,17 +61,17 @@ var vulnCmdRun = func(cmd *cobra.Command, runtime *providers.Runtime, cliRes *pl report, err := RunScan(conf) if err != nil { - log.Fatal().Err(err).Msg("error happened during package analysis") + log.Fatal().Err(err).Msg("failed to run scan") } - buf := bytes.Buffer{} - w := shared.IOWriter{Writer: &buf} - err = reporter.ReportCollectionToJSON(report, &w) + cnspecReport, err := reporter.ConvertToProto(report) if err == nil { - logger.DebugDumpJSON("mondoo-sbom-report", buf.Bytes()) + log.Debug().Msg("converted report to proto") + data, _ := cnspecReport.ToJSON() + logger.DebugDumpJSON("mondoo-sbom-report", data) } - boms, err := sbom.NewBom(buf.Bytes()) + boms, err := sbom.NewBom(cnspecReport.ToCnqueryReport()) if err != nil { log.Fatal().Err(err).Msg("failed to parse sbom data") } diff --git a/cli/reporter/cli_reporter.go b/cli/reporter/cli_reporter.go index 44066f34..6204da67 100644 --- a/cli/reporter/cli_reporter.go +++ b/cli/reporter/cli_reporter.go @@ -152,10 +152,10 @@ func (r *Reporter) WriteReport(ctx context.Context, data *policy.ReportCollectio case FormatJSON: writer := shared.IOWriter{Writer: r.out} - return ReportCollectionToJSON(data, &writer) + return ConvertToJSON(data, &writer) case FormatJUnit: writer := shared.IOWriter{Writer: r.out} - return ReportCollectionToJunit(data, &writer) + return ConvertToJunit(data, &writer) // case FormatCSV: // res, err = data.ToCsv() default: diff --git a/cli/reporter/cnspec_report.pb.go b/cli/reporter/cnspec_report.pb.go new file mode 100644 index 00000000..cd9b2529 --- /dev/null +++ b/cli/reporter/cnspec_report.pb.go @@ -0,0 +1,371 @@ +// Copyright (c) Mondoo, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.33.0 +// protoc v4.25.3 +// source: cnspec_report.proto + +package reporter + +import ( + reporter "go.mondoo.com/cnquery/v10/cli/reporter" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type Report struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Assets map[string]*reporter.Asset `protobuf:"bytes,1,rep,name=assets,proto3" json:"assets,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Data map[string]*reporter.DataValues `protobuf:"bytes,2,rep,name=data,proto3" json:"data,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Errors map[string]string `protobuf:"bytes,3,rep,name=errors,proto3" json:"errors,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Scores map[string]*ScoreValues `protobuf:"bytes,4,rep,name=scores,proto3" json:"scores,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *Report) Reset() { + *x = Report{} + if protoimpl.UnsafeEnabled { + mi := &file_cnspec_report_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Report) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Report) ProtoMessage() {} + +func (x *Report) ProtoReflect() protoreflect.Message { + mi := &file_cnspec_report_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Report.ProtoReflect.Descriptor instead. +func (*Report) Descriptor() ([]byte, []int) { + return file_cnspec_report_proto_rawDescGZIP(), []int{0} +} + +func (x *Report) GetAssets() map[string]*reporter.Asset { + if x != nil { + return x.Assets + } + return nil +} + +func (x *Report) GetData() map[string]*reporter.DataValues { + if x != nil { + return x.Data + } + return nil +} + +func (x *Report) GetErrors() map[string]string { + if x != nil { + return x.Errors + } + return nil +} + +func (x *Report) GetScores() map[string]*ScoreValues { + if x != nil { + return x.Scores + } + return nil +} + +type ScoreValues struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Values map[string]*ScoreValue `protobuf:"bytes,1,rep,name=values,proto3" json:"values,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *ScoreValues) Reset() { + *x = ScoreValues{} + if protoimpl.UnsafeEnabled { + mi := &file_cnspec_report_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ScoreValues) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ScoreValues) ProtoMessage() {} + +func (x *ScoreValues) ProtoReflect() protoreflect.Message { + mi := &file_cnspec_report_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ScoreValues.ProtoReflect.Descriptor instead. +func (*ScoreValues) Descriptor() ([]byte, []int) { + return file_cnspec_report_proto_rawDescGZIP(), []int{1} +} + +func (x *ScoreValues) GetValues() map[string]*ScoreValue { + if x != nil { + return x.Values + } + return nil +} + +type ScoreValue struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Score uint32 `protobuf:"varint,1,opt,name=score,proto3" json:"score,omitempty"` + Status string `protobuf:"bytes,2,opt,name=status,proto3" json:"status,omitempty"` +} + +func (x *ScoreValue) Reset() { + *x = ScoreValue{} + if protoimpl.UnsafeEnabled { + mi := &file_cnspec_report_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ScoreValue) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ScoreValue) ProtoMessage() {} + +func (x *ScoreValue) ProtoReflect() protoreflect.Message { + mi := &file_cnspec_report_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ScoreValue.ProtoReflect.Descriptor instead. +func (*ScoreValue) Descriptor() ([]byte, []int) { + return file_cnspec_report_proto_rawDescGZIP(), []int{2} +} + +func (x *ScoreValue) GetScore() uint32 { + if x != nil { + return x.Score + } + return 0 +} + +func (x *ScoreValue) GetStatus() string { + if x != nil { + return x.Status + } + return "" +} + +var File_cnspec_report_proto protoreflect.FileDescriptor + +var file_cnspec_report_proto_rawDesc = []byte{ + 0x0a, 0x13, 0x63, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x5f, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x17, 0x6d, 0x6f, 0x6e, 0x64, 0x6f, 0x6f, 0x2e, 0x72, 0x65, + 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x63, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x2e, 0x76, 0x31, 0x1a, 0x21, + 0x63, 0x6c, 0x69, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x72, 0x2f, 0x63, 0x6e, 0x71, + 0x75, 0x65, 0x72, 0x79, 0x5f, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x22, 0xed, 0x04, 0x0a, 0x06, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x43, 0x0a, 0x06, + 0x61, 0x73, 0x73, 0x65, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x6d, + 0x6f, 0x6e, 0x64, 0x6f, 0x6f, 0x2e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x63, 0x6e, 0x73, + 0x70, 0x65, 0x63, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x41, 0x73, + 0x73, 0x65, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x61, 0x73, 0x73, 0x65, 0x74, + 0x73, 0x12, 0x3d, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x29, 0x2e, 0x6d, 0x6f, 0x6e, 0x64, 0x6f, 0x6f, 0x2e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, + 0x63, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, + 0x2e, 0x44, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, + 0x12, 0x43, 0x0a, 0x06, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x2b, 0x2e, 0x6d, 0x6f, 0x6e, 0x64, 0x6f, 0x6f, 0x2e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, + 0x2e, 0x63, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x72, + 0x74, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x65, + 0x72, 0x72, 0x6f, 0x72, 0x73, 0x12, 0x43, 0x0a, 0x06, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x73, 0x18, + 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x6d, 0x6f, 0x6e, 0x64, 0x6f, 0x6f, 0x2e, 0x72, + 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x63, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x2e, 0x76, 0x31, 0x2e, + 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x73, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x52, 0x06, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x73, 0x1a, 0x5a, 0x0a, 0x0b, 0x41, 0x73, + 0x73, 0x65, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x35, 0x0a, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6d, 0x6f, 0x6e, + 0x64, 0x6f, 0x6f, 0x2e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x63, 0x6e, 0x71, 0x75, 0x65, + 0x72, 0x79, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x73, 0x73, 0x65, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x5d, 0x0a, 0x09, 0x44, 0x61, 0x74, 0x61, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x3a, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x6d, 0x6f, 0x6e, 0x64, 0x6f, 0x6f, 0x2e, 0x72, 0x65, + 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x63, 0x6e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x2e, + 0x44, 0x61, 0x74, 0x61, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x39, 0x0a, 0x0b, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, + 0x1a, 0x5f, 0x0a, 0x0b, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, + 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, + 0x79, 0x12, 0x3a, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x24, 0x2e, 0x6d, 0x6f, 0x6e, 0x64, 0x6f, 0x6f, 0x2e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, + 0x2e, 0x63, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x63, 0x6f, 0x72, 0x65, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, + 0x01, 0x22, 0xb7, 0x01, 0x0a, 0x0b, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, + 0x73, 0x12, 0x48, 0x0a, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x30, 0x2e, 0x6d, 0x6f, 0x6e, 0x64, 0x6f, 0x6f, 0x2e, 0x72, 0x65, 0x70, 0x6f, 0x72, + 0x74, 0x2e, 0x63, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x63, 0x6f, 0x72, + 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x52, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x1a, 0x5e, 0x0a, 0x0b, 0x56, + 0x61, 0x6c, 0x75, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, + 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x39, 0x0a, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x6d, 0x6f, + 0x6e, 0x64, 0x6f, 0x6f, 0x2e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x63, 0x6e, 0x73, 0x70, + 0x65, 0x63, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, + 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x3a, 0x0a, 0x0a, 0x53, + 0x63, 0x6f, 0x72, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x63, 0x6f, + 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x12, + 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x42, 0x27, 0x5a, 0x25, 0x67, 0x6f, 0x2e, 0x6d, 0x6f, + 0x6e, 0x64, 0x6f, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x2f, + 0x76, 0x31, 0x30, 0x2f, 0x63, 0x6c, 0x69, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x72, + 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_cnspec_report_proto_rawDescOnce sync.Once + file_cnspec_report_proto_rawDescData = file_cnspec_report_proto_rawDesc +) + +func file_cnspec_report_proto_rawDescGZIP() []byte { + file_cnspec_report_proto_rawDescOnce.Do(func() { + file_cnspec_report_proto_rawDescData = protoimpl.X.CompressGZIP(file_cnspec_report_proto_rawDescData) + }) + return file_cnspec_report_proto_rawDescData +} + +var file_cnspec_report_proto_msgTypes = make([]protoimpl.MessageInfo, 8) +var file_cnspec_report_proto_goTypes = []interface{}{ + (*Report)(nil), // 0: mondoo.report.cnspec.v1.Report + (*ScoreValues)(nil), // 1: mondoo.report.cnspec.v1.ScoreValues + (*ScoreValue)(nil), // 2: mondoo.report.cnspec.v1.ScoreValue + nil, // 3: mondoo.report.cnspec.v1.Report.AssetsEntry + nil, // 4: mondoo.report.cnspec.v1.Report.DataEntry + nil, // 5: mondoo.report.cnspec.v1.Report.ErrorsEntry + nil, // 6: mondoo.report.cnspec.v1.Report.ScoresEntry + nil, // 7: mondoo.report.cnspec.v1.ScoreValues.ValuesEntry + (*reporter.Asset)(nil), // 8: mondoo.report.cnquery.v1.Asset + (*reporter.DataValues)(nil), // 9: mondoo.report.cnquery.v1.DataValues +} +var file_cnspec_report_proto_depIdxs = []int32{ + 3, // 0: mondoo.report.cnspec.v1.Report.assets:type_name -> mondoo.report.cnspec.v1.Report.AssetsEntry + 4, // 1: mondoo.report.cnspec.v1.Report.data:type_name -> mondoo.report.cnspec.v1.Report.DataEntry + 5, // 2: mondoo.report.cnspec.v1.Report.errors:type_name -> mondoo.report.cnspec.v1.Report.ErrorsEntry + 6, // 3: mondoo.report.cnspec.v1.Report.scores:type_name -> mondoo.report.cnspec.v1.Report.ScoresEntry + 7, // 4: mondoo.report.cnspec.v1.ScoreValues.values:type_name -> mondoo.report.cnspec.v1.ScoreValues.ValuesEntry + 8, // 5: mondoo.report.cnspec.v1.Report.AssetsEntry.value:type_name -> mondoo.report.cnquery.v1.Asset + 9, // 6: mondoo.report.cnspec.v1.Report.DataEntry.value:type_name -> mondoo.report.cnquery.v1.DataValues + 1, // 7: mondoo.report.cnspec.v1.Report.ScoresEntry.value:type_name -> mondoo.report.cnspec.v1.ScoreValues + 2, // 8: mondoo.report.cnspec.v1.ScoreValues.ValuesEntry.value:type_name -> mondoo.report.cnspec.v1.ScoreValue + 9, // [9:9] is the sub-list for method output_type + 9, // [9:9] is the sub-list for method input_type + 9, // [9:9] is the sub-list for extension type_name + 9, // [9:9] is the sub-list for extension extendee + 0, // [0:9] is the sub-list for field type_name +} + +func init() { file_cnspec_report_proto_init() } +func file_cnspec_report_proto_init() { + if File_cnspec_report_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_cnspec_report_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Report); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_cnspec_report_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ScoreValues); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_cnspec_report_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ScoreValue); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_cnspec_report_proto_rawDesc, + NumEnums: 0, + NumMessages: 8, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_cnspec_report_proto_goTypes, + DependencyIndexes: file_cnspec_report_proto_depIdxs, + MessageInfos: file_cnspec_report_proto_msgTypes, + }.Build() + File_cnspec_report_proto = out.File + file_cnspec_report_proto_rawDesc = nil + file_cnspec_report_proto_goTypes = nil + file_cnspec_report_proto_depIdxs = nil +} diff --git a/cli/reporter/cnspec_report.proto b/cli/reporter/cnspec_report.proto new file mode 100644 index 00000000..fa929728 --- /dev/null +++ b/cli/reporter/cnspec_report.proto @@ -0,0 +1,26 @@ +// Copyright (c) Mondoo, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +syntax = "proto3"; + +package mondoo.report.cnspec.v1; + +option go_package = "go.mondoo.com/cnspec/v10/cli/reporter"; + +import "cli/reporter/cnquery_report.proto"; + +message Report { + map assets = 1; + map data = 2; + map errors = 3; + map scores = 4; +} + +message ScoreValues { + map values = 1; +} + +message ScoreValue { + uint32 score = 1; + string status = 2; +} \ No newline at end of file diff --git a/cli/reporter/json.go b/cli/reporter/json.go index d1d195e2..15f43392 100644 --- a/cli/reporter/json.go +++ b/cli/reporter/json.go @@ -59,7 +59,7 @@ func prepareAssetsForPrinting(assets map[string]*inventory.Asset) map[string]*as return printableAssets } -func ReportCollectionToJSON(data *policy.ReportCollection, out shared.OutputHelper) error { +func ConvertToJSON(data *policy.ReportCollection, out shared.OutputHelper) error { if data == nil { return nil } @@ -121,7 +121,7 @@ func ReportCollectionToJSON(data *policy.ReportCollection, out shared.OutputHelp out.WriteString(pre2 + llx.PrettyPrintString(mrn) + ":") pre2 = "," - err := cr.BundleResultsToJSON(query.Code, results, out) + err := cr.CodeBundleToJSON(query.Code, results, out) if err != nil { return err } diff --git a/cli/reporter/json_test.go b/cli/reporter/json_test.go index dd9b3d2d..e9ac4537 100644 --- a/cli/reporter/json_test.go +++ b/cli/reporter/json_test.go @@ -1,3 +1,6 @@ +// Copyright (c) Mondoo, Inc. +// SPDX-License-Identifier: BUSL-1.1 + package reporter import ( diff --git a/cli/reporter/junit.go b/cli/reporter/junit.go index 3dbc9af9..d43b036c 100644 --- a/cli/reporter/junit.go +++ b/cli/reporter/junit.go @@ -17,8 +17,8 @@ import ( "go.mondoo.com/cnspec/v10/policy" ) -// ReportCollectionToJunit maps the ReportCollection to Junit. Each asset becomes its own Suite -func ReportCollectionToJunit(r *policy.ReportCollection, out shared.OutputHelper) error { +// ConvertToJunit maps the ReportCollection to Junit. Each asset becomes its own Suite +func ConvertToJunit(r *policy.ReportCollection, out shared.OutputHelper) error { noXMLHeader := false suites := junit.Testsuites{} diff --git a/cli/reporter/junit_test.go b/cli/reporter/junit_test.go index 6bd9ca48..57b0fad8 100644 --- a/cli/reporter/junit_test.go +++ b/cli/reporter/junit_test.go @@ -14,8 +14,8 @@ import ( "testing" ) -func TestJunitConverter(t *testing.T) { - yr := &policy.ReportCollection{ +func sampleReportCollection() *policy.ReportCollection { + return &policy.ReportCollection{ Assets: map[string]*inventory.Asset{ "//assets.api.mondoo.app/spaces/dazzling-golick-767384/assets/2DRZ1cCWFyTYCArycAXHwvn1oU2": { Name: "X1", @@ -88,10 +88,13 @@ func TestJunitConverter(t *testing.T) { }, }, } +} +func TestJunitConverter(t *testing.T) { + yr := sampleReportCollection() buf := bytes.Buffer{} writer := shared.IOWriter{Writer: &buf} - err := ReportCollectionToJunit(yr, &writer) + err := ConvertToJunit(yr, &writer) require.NoError(t, err) junitReport := buf.String() @@ -106,7 +109,7 @@ func TestJunitNilReport(t *testing.T) { buf := bytes.Buffer{} writer := shared.IOWriter{Writer: &buf} - err := ReportCollectionToJunit(yr, &writer) + err := ConvertToJunit(yr, &writer) require.NoError(t, err) assert.Equal(t, "\n\n", buf.String()) diff --git a/cli/reporter/output_handler.go b/cli/reporter/output_handler.go index 0dfba80f..d8712314 100644 --- a/cli/reporter/output_handler.go +++ b/cli/reporter/output_handler.go @@ -87,7 +87,7 @@ func reportToYaml(report *policy.ReportCollection) ([]byte, error) { func reportToJson(report *policy.ReportCollection) ([]byte, error) { raw := bytes.Buffer{} writer := shared.IOWriter{Writer: &raw} - err := ReportCollectionToJSON(report, &writer) + err := ConvertToJSON(report, &writer) if err != nil { return nil, err } diff --git a/cli/reporter/print.go b/cli/reporter/print.go index d7474fe1..507f8651 100644 --- a/cli/reporter/print.go +++ b/cli/reporter/print.go @@ -12,8 +12,6 @@ import ( "go.mondoo.com/cnspec/v10/policy" ) -//go:generate protoc --proto_path=../../:. --go_out=. --go_opt=paths=source_relative reporter.proto - type Format byte const ( diff --git a/cli/reporter/proto.go b/cli/reporter/proto.go new file mode 100644 index 00000000..c619d680 --- /dev/null +++ b/cli/reporter/proto.go @@ -0,0 +1,234 @@ +// Copyright (c) Mondoo, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package reporter + +import ( + "bytes" + "encoding/json" + "errors" + "strings" + + cr "go.mondoo.com/cnquery/v10/cli/reporter" + "go.mondoo.com/cnquery/v10/shared" + "go.mondoo.com/cnspec/v10/policy" + "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/types/known/structpb" +) + +func ConvertToProto(data *policy.ReportCollection) (*Report, error) { + protoReport := &Report{ + Assets: map[string]*cr.Asset{}, + Data: map[string]*cr.DataValues{}, + Errors: map[string]string{}, + Scores: map[string]*ScoreValues{}, + } + + if data == nil { + return protoReport, nil + } + + var qid2mrn map[string]string + aggregateQueries := []string{} + if data.Bundle != nil { + qid2mrn = make(map[string]string, len(data.Bundle.Queries)) + for i := range data.Bundle.Queries { + query := data.Bundle.Queries[i] + if query.CodeId == "" { + aggregateQueries = append(aggregateQueries, query.Mrn) + } else { + qid2mrn[query.CodeId] = query.Mrn + } + } + } else { + qid2mrn = make(map[string]string, 0) + } + + // fill in assets + for assetMrn, a := range data.Assets { + var platformName string + if a.Platform != nil { + platformName = a.Platform.Name + } + pAsset := &cr.Asset{ + Mrn: a.Mrn, + Name: a.Name, + PlatformName: platformName, + } + protoReport.Assets[assetMrn] = pAsset + } + + // convert the data points to json + for id, report := range data.Reports { + assetMrn := prettyPrintString(id) + + resolved, ok := data.ResolvedPolicies[id] + if !ok { + return nil, errors.New("cannot find resolved pack for " + id + " in report") + } + + results := report.RawResults() + if resolved.ExecutionJob == nil { + continue + } + for qid, query := range resolved.ExecutionJob.Queries { + mrn := qid2mrn[qid] + + // policies and other stuff + if mrn == "" { + continue + } + // checks + if _, ok := report.Scores[qid]; ok { + continue + } + + buf := &bytes.Buffer{} + w := shared.IOWriter{Writer: buf} + err := cr.CodeBundleToJSON(query.Code, results, &w) + if err != nil { + return nil, err + } + + var v *structpb.Value + var jsonStruct map[string]interface{} + err = json.Unmarshal([]byte(buf.Bytes()), &jsonStruct) + if err == nil { + v, err = structpb.NewValue(jsonStruct) + if err != nil { + return nil, err + } + } else { + v, err = structpb.NewValue(buf.String()) + if err != nil { + return nil, err + } + } + + if protoReport.Data[assetMrn] == nil { + protoReport.Data[assetMrn] = &cr.DataValues{ + Values: map[string]*cr.DataValue{}, + } + } + + protoReport.Data[assetMrn].Values[mrn] = &cr.DataValue{ + Content: v, + } + } + } + + // convert scores + for mrn, report := range data.Reports { + if protoReport.Scores[mrn] == nil { + protoReport.Scores[mrn] = &ScoreValues{ + Values: map[string]*ScoreValue{}, + } + } + + score := gatherScoreValue(report.Scores[mrn]) + if score != nil { + protoReport.Scores[mrn].Values[mrn] = score + } + + resolved, ok := data.ResolvedPolicies[mrn] + if !ok { + return nil, errors.New("cannot find resolved pack for " + mrn + " in report") + } + + for qid := range resolved.ExecutionJob.Queries { + qmrn := qid2mrn[qid] + // policies and other stuff + if qmrn == "" { + continue + } + + score := gatherScoreValue(report.Scores[qid]) + if score != nil { + protoReport.Scores[mrn].Values[qmrn] = score + } + } + + for _, qmrn := range aggregateQueries { + score := gatherScoreValue(report.Scores[qmrn]) + if score != nil { + protoReport.Scores[mrn].Values[qmrn] = score + } + } + } + + for id, errStatus := range data.Errors { + assetMrn := prettyPrintString(id) + errorMsg := errStatus + protoReport.Errors[assetMrn] = errorMsg + } + + return protoReport, nil +} + +func (r *Report) ToJSON() ([]byte, error) { + return protojson.Marshal(r) +} + +func (r *Report) ToCnqueryReport() *cr.Report { + report := &cr.Report{ + Assets: map[string]*cr.Asset{}, + Data: map[string]*cr.DataValues{}, + Errors: map[string]string{}, + } + + for id, asset := range r.Assets { + report.Assets[id] = &cr.Asset{ + Mrn: asset.Mrn, + Name: asset.Name, + } + } + + for id, data := range r.Data { + report.Data[id] = &cr.DataValues{ + Values: map[string]*cr.DataValue{}, + } + for mid, value := range data.Values { + report.Data[id].Values[mid] = &cr.DataValue{ + Content: value.Content, + } + } + } + + for id, err := range r.Errors { + report.Errors[id] = err + } + + return report +} + +func JsonValue(v *structpb.Value) ([]byte, error) { + return protojson.Marshal(v) +} + +// similar to llx.PrettyPrintString but no double quotes around the string +func prettyPrintString(s string) string { + res := s + res = strings.ReplaceAll(res, "\\n", "\n") + res = strings.ReplaceAll(res, "\\t", "\t") + return res +} + +func gatherScoreValue(score *policy.Score) *ScoreValue { + if score == nil { + return nil + } + + status := score.TypeLabel() + if score.Type == policy.ScoreType_Result { + if score.Value == 100 { + status = "pass" + } else { + status = "fail" + } + } + + return &ScoreValue{ + Score: score.Value, + Status: status, + } +} diff --git a/cli/reporter/proto_test.go b/cli/reporter/proto_test.go new file mode 100644 index 00000000..8be657bf --- /dev/null +++ b/cli/reporter/proto_test.go @@ -0,0 +1,46 @@ +// Copyright (c) Mondoo, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package reporter + +import ( + "encoding/json" + "os" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.mondoo.com/cnspec/v10/policy" +) + +func TestProtoConversion(t *testing.T) { + t.Run("test policy report conversion", func(t *testing.T) { + reportCollectionRaw, err := os.ReadFile("./testdata/report-ubuntu.json") + require.NoError(t, err) + + yr := &policy.ReportCollection{} + err = json.Unmarshal(reportCollectionRaw, yr) + require.NoError(t, err) + + report, err := ConvertToProto(yr) + require.NoError(t, err) + + assert.Equal(t, 1, len(report.Assets)) + + assetMrn := "//assets.api.mondoo.app/spaces/dazzling-golick-767384/assets/2DRZ1cCWFyTYCArycAXHwvn1oU2" + asset := report.Assets[assetMrn] + assert.Equal(t, "X1", asset.Name) + assert.Equal(t, "ubuntu", asset.PlatformName) + + assert.Equal(t, 1, len(report.Scores)) + assert.Equal(t, 0, len(report.Errors)) + assert.Equal(t, 1, len(report.Data)) + + assert.Equal(t, 108, len(report.Scores[assetMrn].Values)) + + score := report.Scores[assetMrn].Values["//policy.api.mondoo.app/queries/mondoo-linux-security-permissions-on-etcgshadow-are-configured"] + assert.Equal(t, 100, int(score.Score)) + assert.Equal(t, "pass", score.Status) + }) + +} diff --git a/cli/reporter/reporter.go b/cli/reporter/reporter.go new file mode 100644 index 00000000..8161f1bb --- /dev/null +++ b/cli/reporter/reporter.go @@ -0,0 +1,6 @@ +// Copyright (c) Mondoo, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package reporter + +//go:generate protoc --proto_path=../:../../cnquery:. --go_out=. --go_opt=paths=source_relative cnspec_report.proto diff --git a/cli/reporter/reporter.pb.go b/cli/reporter/reporter.pb.go deleted file mode 100644 index 7b2d6dcb..00000000 --- a/cli/reporter/reporter.pb.go +++ /dev/null @@ -1,279 +0,0 @@ -// Copyright (c) Mondoo, Inc. -// SPDX-License-Identifier: BUSL-1.1 - -// Code generated by protoc-gen-go. DO NOT EDIT. -// versions: -// protoc-gen-go v1.32.0 -// protoc v4.25.1 -// source: reporter.proto - -package reporter - -import ( - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" - reflect "reflect" - sync "sync" -) - -const ( - // Verify that this generated code is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) - // Verify that runtime/protoimpl is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) -) - -type Result struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Pass bool `protobuf:"varint,1,opt,name=pass,proto3" json:"pass,omitempty"` - Title string `protobuf:"bytes,2,opt,name=title,proto3" json:"title,omitempty"` - Description string `protobuf:"bytes,3,opt,name=description,proto3" json:"description,omitempty"` - Error *ResultError `protobuf:"bytes,4,opt,name=error,proto3" json:"error,omitempty"` - Diagnostics []byte `protobuf:"bytes,5,opt,name=diagnostics,proto3" json:"diagnostics,omitempty"` // yaml encoded -} - -func (x *Result) Reset() { - *x = Result{} - if protoimpl.UnsafeEnabled { - mi := &file_reporter_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *Result) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Result) ProtoMessage() {} - -func (x *Result) ProtoReflect() protoreflect.Message { - mi := &file_reporter_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use Result.ProtoReflect.Descriptor instead. -func (*Result) Descriptor() ([]byte, []int) { - return file_reporter_proto_rawDescGZIP(), []int{0} -} - -func (x *Result) GetPass() bool { - if x != nil { - return x.Pass - } - return false -} - -func (x *Result) GetTitle() string { - if x != nil { - return x.Title - } - return "" -} - -func (x *Result) GetDescription() string { - if x != nil { - return x.Description - } - return "" -} - -func (x *Result) GetError() *ResultError { - if x != nil { - return x.Error - } - return nil -} - -func (x *Result) GetDiagnostics() []byte { - if x != nil { - return x.Diagnostics - } - return nil -} - -type ResultError struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` - At string `protobuf:"bytes,2,opt,name=at,proto3" json:"at,omitempty"` - Got string `protobuf:"bytes,3,opt,name=got,proto3" json:"got,omitempty"` - Expected string `protobuf:"bytes,4,opt,name=expected,proto3" json:"expected,omitempty"` -} - -func (x *ResultError) Reset() { - *x = ResultError{} - if protoimpl.UnsafeEnabled { - mi := &file_reporter_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ResultError) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ResultError) ProtoMessage() {} - -func (x *ResultError) ProtoReflect() protoreflect.Message { - mi := &file_reporter_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ResultError.ProtoReflect.Descriptor instead. -func (*ResultError) Descriptor() ([]byte, []int) { - return file_reporter_proto_rawDescGZIP(), []int{1} -} - -func (x *ResultError) GetMessage() string { - if x != nil { - return x.Message - } - return "" -} - -func (x *ResultError) GetAt() string { - if x != nil { - return x.At - } - return "" -} - -func (x *ResultError) GetGot() string { - if x != nil { - return x.Got - } - return "" -} - -func (x *ResultError) GetExpected() string { - if x != nil { - return x.Expected - } - return "" -} - -var File_reporter_proto protoreflect.FileDescriptor - -var file_reporter_proto_rawDesc = []byte{ - 0x0a, 0x0e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x12, 0x12, 0x63, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x2e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x65, - 0x72, 0x2e, 0x76, 0x31, 0x22, 0xad, 0x01, 0x0a, 0x06, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, - 0x12, 0x0a, 0x04, 0x70, 0x61, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x70, - 0x61, 0x73, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, - 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x35, 0x0a, 0x05, 0x65, - 0x72, 0x72, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x63, 0x6e, 0x73, - 0x70, 0x65, 0x63, 0x2e, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, - 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, - 0x6f, 0x72, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, - 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x64, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, - 0x74, 0x69, 0x63, 0x73, 0x22, 0x65, 0x0a, 0x0b, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x45, 0x72, - 0x72, 0x6f, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x0e, 0x0a, - 0x02, 0x61, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x61, 0x74, 0x12, 0x10, 0x0a, - 0x03, 0x67, 0x6f, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x67, 0x6f, 0x74, 0x12, - 0x1a, 0x0a, 0x08, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x08, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x42, 0x27, 0x5a, 0x25, 0x67, - 0x6f, 0x2e, 0x6d, 0x6f, 0x6e, 0x64, 0x6f, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6e, 0x73, - 0x70, 0x65, 0x63, 0x2f, 0x76, 0x31, 0x30, 0x2f, 0x63, 0x6c, 0x69, 0x2f, 0x72, 0x65, 0x70, 0x6f, - 0x72, 0x74, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} - -var ( - file_reporter_proto_rawDescOnce sync.Once - file_reporter_proto_rawDescData = file_reporter_proto_rawDesc -) - -func file_reporter_proto_rawDescGZIP() []byte { - file_reporter_proto_rawDescOnce.Do(func() { - file_reporter_proto_rawDescData = protoimpl.X.CompressGZIP(file_reporter_proto_rawDescData) - }) - return file_reporter_proto_rawDescData -} - -var file_reporter_proto_msgTypes = make([]protoimpl.MessageInfo, 2) -var file_reporter_proto_goTypes = []interface{}{ - (*Result)(nil), // 0: cnspec.reporter.v1.Result - (*ResultError)(nil), // 1: cnspec.reporter.v1.ResultError -} -var file_reporter_proto_depIdxs = []int32{ - 1, // 0: cnspec.reporter.v1.Result.error:type_name -> cnspec.reporter.v1.ResultError - 1, // [1:1] is the sub-list for method output_type - 1, // [1:1] is the sub-list for method input_type - 1, // [1:1] is the sub-list for extension type_name - 1, // [1:1] is the sub-list for extension extendee - 0, // [0:1] is the sub-list for field type_name -} - -func init() { file_reporter_proto_init() } -func file_reporter_proto_init() { - if File_reporter_proto != nil { - return - } - if !protoimpl.UnsafeEnabled { - file_reporter_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Result); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_reporter_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ResultError); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } - type x struct{} - out := protoimpl.TypeBuilder{ - File: protoimpl.DescBuilder{ - GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_reporter_proto_rawDesc, - NumEnums: 0, - NumMessages: 2, - NumExtensions: 0, - NumServices: 0, - }, - GoTypes: file_reporter_proto_goTypes, - DependencyIndexes: file_reporter_proto_depIdxs, - MessageInfos: file_reporter_proto_msgTypes, - }.Build() - File_reporter_proto = out.File - file_reporter_proto_rawDesc = nil - file_reporter_proto_goTypes = nil - file_reporter_proto_depIdxs = nil -} diff --git a/cli/reporter/reporter.proto b/cli/reporter/reporter.proto deleted file mode 100644 index b5085199..00000000 --- a/cli/reporter/reporter.proto +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) Mondoo, Inc. -// SPDX-License-Identifier: BUSL-1.1 - -syntax = "proto3"; - -package cnspec.reporter.v1; -option go_package = "go.mondoo.com/cnspec/v10/cli/reporter"; - -message Result { - bool pass = 1; - string title = 2; - string description = 3; - ResultError error = 4; - bytes diagnostics = 5; // yaml encoded -} - -message ResultError { - string message = 1; - string at = 2; - string got = 3; - string expected = 4; -} From 541148f2282c4a5e8bf50c5259b6c8ebb63efd5c Mon Sep 17 00:00:00 2001 From: Christoph Hartmann Date: Thu, 4 Apr 2024 13:24:29 +0200 Subject: [PATCH 3/3] =?UTF-8?q?=F0=9F=A7=B9=20update=20go=20mod?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 3dbed246..bf06a9b8 100644 --- a/go.mod +++ b/go.mod @@ -34,7 +34,7 @@ require ( github.com/spf13/pflag v1.0.6-0.20201009195203-85dd5c8bc61c github.com/spf13/viper v1.18.2 github.com/stretchr/testify v1.9.0 - go.mondoo.com/cnquery/v10 v10.10.0 + go.mondoo.com/cnquery/v10 v10.10.1-0.20240404112111-403df5b5663f go.mondoo.com/mondoo-go v0.0.0-20240312054001-2ab23a39b500 go.mondoo.com/ranger-rpc v0.6.0 go.opentelemetry.io/otel v1.24.0 diff --git a/go.sum b/go.sum index 8c70cd21..c8ac959d 100644 --- a/go.sum +++ b/go.sum @@ -1186,8 +1186,8 @@ go-simpler.org/sloglint v0.5.0/go.mod h1:EUknX5s8iXqf18KQxKnaBHUPVriiPnOrPjjJcsa go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/v2 v2.305.1/go.mod h1:pMEacxZW7o8pg4CrFE7pquyCJJzZvkvdD2RibOCCCGs= -go.mondoo.com/cnquery/v10 v10.10.0 h1:uEZeIc/s87u31yBqH9EQvG+KrpV3VemyjdJOv1VNwpY= -go.mondoo.com/cnquery/v10 v10.10.0/go.mod h1:gSC6NiZaa2zIM9gn7Kwtt5GsSWXrlbCISIZcZhdtRss= +go.mondoo.com/cnquery/v10 v10.10.1-0.20240404112111-403df5b5663f h1:cfRJZemrwMY9G/dN7JJIttrn7LDP4d2wloznAXE3JOY= +go.mondoo.com/cnquery/v10 v10.10.1-0.20240404112111-403df5b5663f/go.mod h1:gSC6NiZaa2zIM9gn7Kwtt5GsSWXrlbCISIZcZhdtRss= go.mondoo.com/mondoo-go v0.0.0-20240312054001-2ab23a39b500 h1:HjtfupqfqKnDaK+XUXZC/3JyIwK09C3TFNggwReuDlY= go.mondoo.com/mondoo-go v0.0.0-20240312054001-2ab23a39b500/go.mod h1:pFmkGNtz+oa1iE/0Ssjo5KCTQ2VFeZgyIaD8c7nqcoc= go.mondoo.com/ranger-rpc v0.6.0 h1:u8FY0NGhR1B/LZk9+DdmqksrWc007argv+nMGJGa3OA=