diff --git a/cli/reporter/cli_reporter.go b/cli/reporter/cli_reporter.go index 1fae1008..8eed32b0 100644 --- a/cli/reporter/cli_reporter.go +++ b/cli/reporter/cli_reporter.go @@ -14,6 +14,7 @@ import ( "go.mondoo.com/cnquery/v11" "go.mondoo.com/cnquery/v11/cli/printer" "go.mondoo.com/cnquery/v11/cli/theme/colors" + "go.mondoo.com/cnquery/v11/logger" "go.mondoo.com/cnquery/v11/mqlc" "go.mondoo.com/cnquery/v11/providers" "go.mondoo.com/cnquery/v11/providers-sdk/v1/resources" @@ -108,6 +109,8 @@ func (r *Reporter) WithOutput(out io.Writer) *Reporter { } func (r *Reporter) WriteReport(ctx context.Context, data *policy.ReportCollection) error { + // write data to file for debugging + logger.DebugDumpJSON("report-collection", data) features := cnquery.GetFeatures(ctx) switch r.Conf.format { case FormatCompact, FormatSummary, FormatFull: diff --git a/cli/reporter/json.go b/cli/reporter/json.go index d80f9f31..a65f05e4 100644 --- a/cli/reporter/json.go +++ b/cli/reporter/json.go @@ -105,6 +105,11 @@ func ConvertToJSON(data *policy.ReportCollection, out iox.OutputHelper) error { return errors.New("cannot find resolved pack for " + id + " in report") } + reportingJobByQrId := map[string]*policy.ReportingJob{} + for _, job := range resolved.CollectorJob.ReportingJobs { + reportingJobByQrId[job.QrId] = job + } + results := report.RawResults() pre2 := "" for qid, query := range resolved.ExecutionJob.Queries { @@ -114,8 +119,10 @@ func ConvertToJSON(data *policy.ReportCollection, out iox.OutputHelper) error { continue } // checks - if _, ok := report.Scores[qid]; ok { - continue + if rj, ok := reportingJobByQrId[mrn]; ok { + if !(rj.Type == policy.ReportingJob_DATA_QUERY || rj.Type == policy.ReportingJob_CHECK_AND_DATA_QUERY) { + continue + } } out.WriteString(pre2 + llx.PrettyPrintString(mrn) + ":") diff --git a/cli/reporter/json_test.go b/cli/reporter/json_test.go index 05c99735..9f4faff0 100644 --- a/cli/reporter/json_test.go +++ b/cli/reporter/json_test.go @@ -7,6 +7,7 @@ import ( "bytes" "context" "encoding/json" + "fmt" "os" "testing" @@ -19,7 +20,23 @@ import ( ) func TestJsonOutput(t *testing.T) { - reportCollectionRaw, err := os.ReadFile("./testdata/report-ubuntu.json") + // You can reproduce the report by running + // DEBUG=1 cnspec scan local -f bundle.mql.yaml + // where + // bundle.mql.yaml contains + // policies: + // - uid: custom-test-policy-1 + // name: Custom Test Policy 1 + // groups: + // - filters: | + // return true + // checks: + // - uid: custom-query-passing-1 + // title: Failing Query + // mql: | + // true == true + + reportCollectionRaw, err := os.ReadFile("./testdata/simple-report.json") require.NoError(t, err) yr := &policy.ReportCollection{} @@ -41,9 +58,10 @@ func TestJsonOutput(t *testing.T) { err = r.WriteReport(context.Background(), yr) require.NoError(t, err) valid := json.Valid(buf.Bytes()) + fmt.Println(buf.String()) 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(), "//local.cnspec.io/run/local-execution/queries/custom-query-passing-1\":{\"score\":100,\"status\":\"pass\"}") assert.Contains(t, buf.String(), "\"errors\":{}") } diff --git a/cli/reporter/proto.go b/cli/reporter/proto.go index 7dbb2fa2..26e133f9 100644 --- a/cli/reporter/proto.go +++ b/cli/reporter/proto.go @@ -69,6 +69,11 @@ func ConvertToProto(data *policy.ReportCollection) (*Report, error) { return nil, errors.New("cannot find resolved pack for " + id + " in report") } + reportingJobByQrId := map[string]*policy.ReportingJob{} + for _, job := range resolved.CollectorJob.ReportingJobs { + reportingJobByQrId[job.QrId] = job + } + results := report.RawResults() if resolved.ExecutionJob == nil { continue @@ -81,8 +86,10 @@ func ConvertToProto(data *policy.ReportCollection) (*Report, error) { continue } // checks - if _, ok := report.Scores[qid]; ok { - continue + if rj, ok := reportingJobByQrId[mrn]; ok { + if !(rj.Type == policy.ReportingJob_DATA_QUERY || rj.Type == policy.ReportingJob_CHECK_AND_DATA_QUERY) { + continue + } } buf := &bytes.Buffer{} diff --git a/cli/reporter/testdata/simple-report.json b/cli/reporter/testdata/simple-report.json new file mode 100644 index 00000000..411efc3e --- /dev/null +++ b/cli/reporter/testdata/simple-report.json @@ -0,0 +1,335 @@ +{ + "assets": { + "//policy.api.mondoo.com/assets/2rRJKGpXib47ho8tWVyJegTXogt": { + "mrn": "//policy.api.mondoo.com/assets/2rRJKGpXib47ho8tWVyJegTXogt", + "name": "planetexpress", + "platform_ids": [ + "//platformid.api.mondoo.app/hostname/planetexpress" + ], + "platform": { + "name": "arch", + "arch": "x86_64", + "title": "Arch Linux", + "family": [ + "arch", + "linux", + "unix", + "os" + ], + "build": "rolling", + "version": "unknown", + "kind": "baremetal", + "technology_url_segments": [ + "os", + "linux", + "arch", + "unknown" + ], + "labels": { + "distro-id": "arch" + } + }, + "connections": [ + { + "id": 1, + "type": "local", + "options": { + "device-names": "" + }, + "discover": { + "targets": [ + "auto" + ] + }, + "capabilities": [ + "run-command", + "file" + ] + } + ], + "id_detector": [ + "hostname", + "cloud-detect" + ], + "kind_string": "baremetal" + } + }, + "bundle": { + "policies": [ + { + "mrn": "//local.cnspec.io/run/local-execution/policies/custom-test-policy-1", + "name": "Custom Test Policy 1", + "groups": [ + { + "checks": [ + { + "mql": "true == true\n", + "code_id": "sq7szyztUV4=", + "checksum": "9eg+/Yss0F4=", + "mrn": "//local.cnspec.io/run/local-execution/queries/custom-query-passing-1", + "type": "\u0004", + "title": "Failing Query" + } + ], + "filters": { + "items": { + "u3R8xyHx4gQ=": { + "mql": "return true\n", + "code_id": "u3R8xyHx4gQ=", + "checksum": "3zCtrbny2vY=", + "mrn": "//local.cnspec.io/run/local-execution/policies/custom-test-policy-1/filter/u3R8xyHx4gQ=", + "type": "\u0004" + } + } + } + } + ], + "scoring_system": "average", + "local_content_checksum": "CXa3ikhV9qY=", + "graph_content_checksum": "ZDuNv9oWhkU=", + "local_execution_checksum": "jSmx49S5w1Q=", + "graph_execution_checksum": "kgSMzsTRe1g=", + "computed_filters": { + "items": { + "u3R8xyHx4gQ=": { + "mql": "return true\n", + "code_id": "u3R8xyHx4gQ=", + "checksum": "3zCtrbny2vY=", + "mrn": "//local.cnspec.io/run/local-execution/policies/custom-test-policy-1/filter/u3R8xyHx4gQ=", + "type": "\u0004" + } + } + } + } + ], + "queries": [ + { + "mql": "true == true\n", + "code_id": "sq7szyztUV4=", + "checksum": "9eg+/Yss0F4=", + "mrn": "//local.cnspec.io/run/local-execution/queries/custom-query-passing-1", + "type": "\u0004", + "title": "Failing Query" + } + ] + }, + "reports": { + "//policy.api.mondoo.com/assets/2rRJKGpXib47ho8tWVyJegTXogt": { + "scoring_mrn": "//policy.api.mondoo.com/assets/2rRJKGpXib47ho8tWVyJegTXogt", + "entity_mrn": "//policy.api.mondoo.com/assets/2rRJKGpXib47ho8tWVyJegTXogt", + "score": { + "risk_score": 100, + "qr_id": "//policy.api.mondoo.com/assets/2rRJKGpXib47ho8tWVyJegTXogt", + "type": 2, + "value": 100, + "weight": 1, + "score_completion": 100, + "data_total": 1, + "data_completion": 100, + "value_modified_time": 1736515888 + }, + "scores": { + "//local.cnspec.io/run/local-execution/policies/custom-test-policy-1": { + "risk_score": 100, + "qr_id": "//local.cnspec.io/run/local-execution/policies/custom-test-policy-1", + "type": 2, + "value": 100, + "weight": 1, + "score_completion": 100, + "data_total": 1, + "data_completion": 100, + "value_modified_time": 1736515888 + }, + "//local.cnspec.io/run/local-execution/queries/custom-query-passing-1": { + "risk_score": 100, + "qr_id": "//local.cnspec.io/run/local-execution/queries/custom-query-passing-1", + "type": 2, + "value": 100, + "weight": 1, + "score_completion": 100, + "data_total": 1, + "data_completion": 100, + "value_modified_time": 1736515888 + }, + "//policy.api.mondoo.com/assets/2rRJKGpXib47ho8tWVyJegTXogt": { + "risk_score": 100, + "qr_id": "//policy.api.mondoo.com/assets/2rRJKGpXib47ho8tWVyJegTXogt", + "type": 2, + "value": 100, + "weight": 1, + "score_completion": 100, + "data_total": 1, + "data_completion": 100, + "value_modified_time": 1736515888 + }, + "sq7szyztUV4=": { + "risk_score": 100, + "qr_id": "sq7szyztUV4=", + "type": 2, + "value": 100, + "weight": 1, + "score_completion": 100, + "data_total": 1, + "data_completion": 100, + "value_modified_time": 1736515888 + } + }, + "data": { + "aFlB5/lPPmzZxj3I3C/YlXHYMRyCWge+J/3R7FXwY2/TvGydNb4eK2zc7yaNcU3TaI6RsSra27PLKs3PRcBiRg==": { + "data": { + "type": "\u0004", + "value": "AQ==" + }, + "code_id": "aFlB5/lPPmzZxj3I3C/YlXHYMRyCWge+J/3R7FXwY2/TvGydNb4eK2zc7yaNcU3TaI6RsSra27PLKs3PRcBiRg==" + } + }, + "risks": {}, + "resolved_policy_version": "v2" + } + }, + "resolved_policies": { + "//policy.api.mondoo.com/assets/2rRJKGpXib47ho8tWVyJegTXogt": { + "execution_job": { + "checksum": "TvjA5u1fz1w=", + "queries": { + "sq7szyztUV4=": { + "query": "true == true\n", + "checksum": "9eg+/Yss0F4=", + "datapoints": [ + "aFlB5/lPPmzZxj3I3C/YlXHYMRyCWge+J/3R7FXwY2/TvGydNb4eK2zc7yaNcU3TaI6RsSra27PLKs3PRcBiRg==" + ], + "code": { + "code_v2": { + "id": "sq7szyztUV4=", + "blocks": [ + { + "chunks": [ + { + "primitive": { + "type": "\u0004", + "value": "AQ==" + } + }, + { + "call": 1, + "id": "==\u0004", + "function": { + "type": "\u0004", + "args": [ + { + "type": "\u0004", + "value": "AQ==" + } + ], + "binding": 4294967297 + } + } + ], + "entrypoints": [ + 4294967298 + ] + } + ], + "checksums": { + "4294967297": "13VXYfnMnc74H8XVgiMbH6ZSHxTGQxkhJfUkIiYOBCfUDxHAIJWopMcsea7hXkBTFpbM9lCDnbDBev1z+uagBw==", + "4294967298": "aFlB5/lPPmzZxj3I3C/YlXHYMRyCWge+J/3R7FXwY2/TvGydNb4eK2zc7yaNcU3TaI6RsSra27PLKs3PRcBiRg==" + } + }, + "source": "true == true\n", + "labels": { + "labels": { + "aFlB5/lPPmzZxj3I3C/YlXHYMRyCWge+J/3R7FXwY2/TvGydNb4eK2zc7yaNcU3TaI6RsSra27PLKs3PRcBiRg==": " == true" + } + }, + "version": "unstable" + } + } + } + }, + "collector_job": { + "checksum": "hvAT1wlkX/g=", + "reporting_jobs": { + "7Ok2O2cuVPY=": { + "checksum": "B8wT76Dnj7w=", + "qr_id": "sq7szyztUV4=", + "uuid": "7Ok2O2cuVPY=", + "notify": [ + "cZUCeltDivI=" + ], + "datapoints": { + "aFlB5/lPPmzZxj3I3C/YlXHYMRyCWge+J/3R7FXwY2/TvGydNb4eK2zc7yaNcU3TaI6RsSra27PLKs3PRcBiRg==": true + }, + "type": 8 + }, + "AYe2BJnKXPY=": { + "checksum": "Klkmoo1RlGs=", + "qr_id": "root", + "uuid": "AYe2BJnKXPY=", + "child_jobs": { + "TLuy3aWdTc4=": null + }, + "type": 4 + }, + "TLuy3aWdTc4=": { + "checksum": "fIbaDBWoZWk=", + "qr_id": "//local.cnspec.io/run/local-execution/policies/custom-test-policy-1", + "uuid": "TLuy3aWdTc4=", + "notify": [ + "AYe2BJnKXPY=" + ], + "scoring_system": "average", + "child_jobs": { + "cZUCeltDivI=": null + }, + "type": 4, + "mrns": [ + "//local.cnspec.io/run/local-execution/policies/custom-test-policy-1" + ] + }, + "cZUCeltDivI=": { + "checksum": "qYgJOe+YMjk=", + "qr_id": "//local.cnspec.io/run/local-execution/queries/custom-query-passing-1", + "uuid": "cZUCeltDivI=", + "notify": [ + "TLuy3aWdTc4=" + ], + "child_jobs": { + "7Ok2O2cuVPY=": null + }, + "type": 1, + "mrns": [ + "//local.cnspec.io/run/local-execution/queries/custom-query-passing-1" + ] + } + }, + "reporting_queries": { + "sq7szyztUV4=": { + "items": [ + "7Ok2O2cuVPY=" + ] + } + }, + "datapoints": { + "aFlB5/lPPmzZxj3I3C/YlXHYMRyCWge+J/3R7FXwY2/TvGydNb4eK2zc7yaNcU3TaI6RsSra27PLKs3PRcBiRg==": { + "type": "\u0004", + "notify": [ + "7Ok2O2cuVPY=" + ] + } + } + }, + "filters": [ + { + "mql": "return true\n", + "code_id": "u3R8xyHx4gQ=", + "checksum": "pWBVTavsHhc=", + "mrn": "//policy.api.mondoo.com/assets/2rRJKGpXib47ho8tWVyJegTXogt/assetfilter/u3R8xyHx4gQ=", + "type": "\u0004" + } + ], + "graph_execution_checksum": "ZIY5OCjaZws=", + "filters_checksum": "p3jyRsb1cgQ=", + "reporting_job_uuid": "AYe2BJnKXPY=" + } + } +} \ No newline at end of file