From 977b62f6448ba2f1dcb629a860f51ee2684c5652 Mon Sep 17 00:00:00 2001 From: elsapet Date: Mon, 28 Nov 2022 10:50:46 +0200 Subject: [PATCH] feat(policies): include code excerpt in policy breach display (#164) * feat: include code excerpt in policy breach display * feat: tidy up output * fix: omit empty parents --- go.mod | 2 +- go.sum | 7 +- .../TestReportFlags-report-policies | 5 +- pkg/commands/artifact/run.go | 4 +- .../settings/policies/logger_leaks.rego | 10 ++- pkg/commands/process/settings/settings.go | 1 + .../output/dataflow/datatypes/datatypes.go | 7 +- .../detectiondecoder/schema_classification.go | 33 ++++----- pkg/report/output/dataflow/risks/risks.go | 15 ++++- pkg/report/output/dataflow/types/risks.go | 3 + pkg/report/output/output.go | 67 ++++++++++++++----- pkg/report/output/policies/policies.go | 25 +++++-- 12 files changed, 130 insertions(+), 49 deletions(-) diff --git a/go.mod b/go.mod index 3a9db7f49..e49d5fa90 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,6 @@ module github.com/bearer/curio go 1.18 require ( - github.com/TwiN/go-color v1.4.0 github.com/bradleyjkemp/cupaloy v2.3.0+incompatible github.com/gertd/go-pluralize v0.2.1 github.com/ghodss/yaml v1.0.0 @@ -69,6 +68,7 @@ require ( ) require ( + github.com/fatih/color v1.13.0 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/onsi/ginkgo v1.16.5 // indirect github.com/onsi/gomega v1.24.1 // indirect diff --git a/go.sum b/go.sum index 4d1e89c5a..fe42af404 100644 --- a/go.sum +++ b/go.sum @@ -46,8 +46,6 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/OneOfOne/xxhash v1.2.8 h1:31czK/TI9sNkxIKfaUfGlU47BAxQ0ztGgd9vPyqimf8= github.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= -github.com/TwiN/go-color v1.4.0 h1:fNbOwOrvup5oj934UragnW0B1WKaAkkB85q19Y7h4ng= -github.com/TwiN/go-color v1.4.0/go.mod h1:0QTVEPlu+AoCyTrho7bXbVkrCkVpdQr7YF7PYWEtSxM= github.com/agnivade/levenshtein v1.1.1 h1:QY8M92nrzkmr798gCo3kmMyqXFzdQVpxLlGPRBij0P8= github.com/agnivade/levenshtein v1.1.1/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo= github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q= @@ -85,6 +83,8 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/semgroup v1.2.0 h1:h/OLXwEM+3NNyAdZEpMiH1OzfplU09i2qXPVThGZvyg= github.com/fatih/semgroup v1.2.0/go.mod h1:1KAD4iIYfXjE4U13B48VM4z9QUwV5Tt8O4rS879kgm8= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= @@ -219,8 +219,10 @@ github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69 github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= @@ -472,6 +474,7 @@ golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/integration/flags/.snapshots/TestReportFlags-report-policies b/integration/flags/.snapshots/TestReportFlags-report-policies index 57c6cefb3..5bb3524e8 100644 --- a/integration/flags/.snapshots/TestReportFlags-report-policies +++ b/integration/flags/.snapshots/TestReportFlags-report-policies @@ -1,8 +1,11 @@ critical: - policy_name: Logger leaking policy_description: Logger leaks detected - filename: users.rb + line_number: 1 + filename: testdata/policiesusers.rb category_group: Personal data + parent_line_number: 1 + parent_content: logger.info(user.address) -- diff --git a/pkg/commands/artifact/run.go b/pkg/commands/artifact/run.go index b351f03a1..485a7c159 100644 --- a/pkg/commands/artifact/run.go +++ b/pkg/commands/artifact/run.go @@ -113,6 +113,8 @@ func Run(ctx context.Context, opts flag.Options, targetKind TargetKind) (err err }() scanSettings, err := settings.FromOptions(opts) + scanSettings.Target = opts.Target + if err != nil { return err } @@ -147,7 +149,7 @@ func (r *runner) Report(config settings.Config, report types.Report) error { } if config.Report.Report == flag.ReportPolicies && config.Report.Format == "" { - // for polict report, default report format is NOT JSON + // for policy report, default report format is NOT JSON err := reportoutput.ReportPolicies(report, logger, config) if err != nil { return fmt.Errorf("error generating report %w", err) diff --git a/pkg/commands/process/settings/policies/logger_leaks.rego b/pkg/commands/process/settings/policies/logger_leaks.rego index c9a019b26..5fb57b4e5 100644 --- a/pkg/commands/process/settings/policies/logger_leaks.rego +++ b/pkg/commands/process/settings/policies/logger_leaks.rego @@ -18,7 +18,10 @@ high[item] { location = data_type.locations[_] item := { "category_group": category.group_name, - "filename": location.filename + "filename": location.filename, + "line_number": location.line_number, + "parent_line_number": data_type.parent.line_number, + "parent_content": data_type.parent.content } } @@ -35,6 +38,9 @@ critical[item] { location = data_type.locations[_] item := { "category_group": category.group_name, - "filename": location.filename + "filename": location.filename, + "line_number": location.line_number, + "parent_line_number": data_type.parent.line_number, + "parent_content": data_type.parent.content } } diff --git a/pkg/commands/process/settings/settings.go b/pkg/commands/process/settings/settings.go index 1404de609..d65f2902b 100644 --- a/pkg/commands/process/settings/settings.go +++ b/pkg/commands/process/settings/settings.go @@ -18,6 +18,7 @@ type Config struct { Report flag.ReportOptions `json:"report" yaml:"report"` CustomDetector map[string]Rule `json:"custom_detector" yaml:"custom_detector"` Policies map[string]*Policy `json:"policies" yaml:"policies"` + Target string `json:"target" yaml:"target"` } type PolicyLevel string diff --git a/pkg/report/output/dataflow/datatypes/datatypes.go b/pkg/report/output/dataflow/datatypes/datatypes.go index 2eb01f218..5b0abded9 100644 --- a/pkg/report/output/dataflow/datatypes/datatypes.go +++ b/pkg/report/output/dataflow/datatypes/datatypes.go @@ -46,7 +46,12 @@ func New(isInternal bool) *Holder { } func (holder *Holder) AddSchema(detection detections.Detection, extras *extraFields) error { - classification, err := detectiondecoder.GetSchemaClassification(detection) + schema, err := detectiondecoder.GetSchema(detection) + if err != nil { + return err + } + + classification, err := detectiondecoder.GetSchemaClassification(schema, detection) if err != nil { return err } diff --git a/pkg/report/output/dataflow/detectiondecoder/schema_classification.go b/pkg/report/output/dataflow/detectiondecoder/schema_classification.go index 255140064..2457acab3 100644 --- a/pkg/report/output/dataflow/detectiondecoder/schema_classification.go +++ b/pkg/report/output/dataflow/detectiondecoder/schema_classification.go @@ -11,30 +11,33 @@ import ( "github.com/bearer/curio/pkg/report/schema" ) -func GetSchemaClassification(detection detections.Detection) (schemaclassification.Classification, error) { - // decode schema - var value schema.Schema +func GetSchemaClassification(schema schema.Schema, detection detections.Detection) (schemaclassification.Classification, error) { + // decode classification + var classification schemaclassification.Classification buf := bytes.NewBuffer(nil) - err := json.NewEncoder(buf).Encode(detection.Value) + err := json.NewEncoder(buf).Encode(schema.Classification) if err != nil { - return schemaclassification.Classification{}, fmt.Errorf("expect detection to have value of type schema %#v", detection.Value) + return schemaclassification.Classification{}, fmt.Errorf("expecting classification got %#v", schema.Classification) } - err = json.NewDecoder(buf).Decode(&value) + err = json.NewDecoder(buf).Decode(&classification) if err != nil { - return schemaclassification.Classification{}, fmt.Errorf("expect detection to have value of type schema %#v", detection.Value) + return schemaclassification.Classification{}, fmt.Errorf("expecting classification got %#v", schema.Classification) } - // decode classification - var classification schemaclassification.Classification - buf = bytes.NewBuffer(nil) - err = json.NewEncoder(buf).Encode(value.Classification) + return classification, nil +} + +func GetSchema(detection detections.Detection) (schema.Schema, error) { + var value schema.Schema + buf := bytes.NewBuffer(nil) + err := json.NewEncoder(buf).Encode(detection.Value) if err != nil { - return schemaclassification.Classification{}, fmt.Errorf("expecting classification got %#v", value.Classification) + return schema.Schema{}, fmt.Errorf("expect detection to have value of type schema %#v", detection.Value) } - err = json.NewDecoder(buf).Decode(&classification) + err = json.NewDecoder(buf).Decode(&value) if err != nil { - return schemaclassification.Classification{}, fmt.Errorf("expecting classification got %#v", value.Classification) + return schema.Schema{}, fmt.Errorf("expect detection to have value of type schema %#v", detection.Value) } - return classification, nil + return value, nil } diff --git a/pkg/report/output/dataflow/risks/risks.go b/pkg/report/output/dataflow/risks/risks.go index 33a813329..3bf87f130 100644 --- a/pkg/report/output/dataflow/risks/risks.go +++ b/pkg/report/output/dataflow/risks/risks.go @@ -5,6 +5,7 @@ import ( "github.com/bearer/curio/pkg/commands/process/settings" "github.com/bearer/curio/pkg/report/output/dataflow/detectiondecoder" "github.com/bearer/curio/pkg/report/output/dataflow/types" + "github.com/bearer/curio/pkg/report/schema" "github.com/bearer/curio/pkg/report/detections" "github.com/bearer/curio/pkg/util/classify" @@ -25,6 +26,7 @@ type datatypeHolder struct { name string uuid string categoryUUID string + parent *schema.Parent files map[string]*fileHolder // group files by filename } type fileHolder struct { @@ -41,20 +43,25 @@ func New(config settings.Config, isInternal bool) *Holder { } func (holder *Holder) AddSchema(detection detections.Detection) error { - classification, err := detectiondecoder.GetSchemaClassification(detection) + schema, err := detectiondecoder.GetSchema(detection) + if err != nil { + return err + } + + classification, err := detectiondecoder.GetSchemaClassification(schema, detection) if err != nil { return err } if classification.Decision.State == classify.Valid { - holder.addDatatype(string(detection.DetectorType), classification.DataType, detection.Source.Filename, *detection.Source.LineNumber) + holder.addDatatype(string(detection.DetectorType), classification.DataType, detection.Source.Filename, *detection.Source.LineNumber, schema.Parent) } return nil } // addDatatype adds detector to hash list and at the same time blocks duplicates -func (holder *Holder) addDatatype(ruleName string, datatype *db.DataType, fileName string, lineNumber int) { +func (holder *Holder) addDatatype(ruleName string, datatype *db.DataType, fileName string, lineNumber int, parent *schema.Parent) { // create detector entry if it doesn't exist if _, exists := holder.detectors[ruleName]; !exists { holder.detectors[ruleName] = detectorHolder{ @@ -71,6 +78,7 @@ func (holder *Holder) addDatatype(ruleName string, datatype *db.DataType, fileNa name: datatype.Name, uuid: datatype.UUID, categoryUUID: datatype.CategoryUUID, + parent: parent, files: make(map[string]*fileHolder), } } else { @@ -118,6 +126,7 @@ func (holder *Holder) ToDataFlow() []types.RiskDetector { Name: datatype.name, UUID: datatype.uuid, CategoryUUID: datatype.categoryUUID, + Parent: datatype.parent, Stored: stored, Locations: make([]types.RiskLocation, 0), } diff --git a/pkg/report/output/dataflow/types/risks.go b/pkg/report/output/dataflow/types/risks.go index 0e0d4ef1f..6a36283c6 100644 --- a/pkg/report/output/dataflow/types/risks.go +++ b/pkg/report/output/dataflow/types/risks.go @@ -1,5 +1,7 @@ package types +import "github.com/bearer/curio/pkg/report/schema" + type RiskDetector struct { DetectorID string `json:"detector_id" yaml:"detector_id"` DataTypes []RiskDatatype `json:"data_types" yaml:"data_types"` @@ -11,6 +13,7 @@ type RiskDatatype struct { CategoryUUID string `json:"category_uuid,omitempty" yaml:"category_uuid,omitempty"` Stored bool `json:"stored" yaml:"stored"` Locations []RiskLocation `json:"locations" yaml:"locations"` + Parent *schema.Parent `json:"parent,omitempty" yaml:"parent,omitempty"` } type RiskLocation struct { diff --git a/pkg/report/output/output.go b/pkg/report/output/output.go index 0c07974f6..ae629c7d5 100644 --- a/pkg/report/output/output.go +++ b/pkg/report/output/output.go @@ -6,7 +6,6 @@ import ( "fmt" "strings" - "github.com/TwiN/go-color" "github.com/bearer/curio/pkg/commands/process/settings" "github.com/bearer/curio/pkg/flag" "github.com/bearer/curio/pkg/report/output/dataflow" @@ -15,13 +14,20 @@ import ( "github.com/bearer/curio/pkg/report/output/policies" "github.com/bearer/curio/pkg/report/output/stats" "github.com/bearer/curio/pkg/types" - + "github.com/fatih/color" "gopkg.in/yaml.v3" "github.com/rs/zerolog" ) var ErrUndefinedFormat = errors.New("undefined output format") +var underline = color.New(color.Underline).SprintFunc() +var severityColorFns = map[string]func(x ...interface{}) string{ + settings.LevelCritical: color.New(color.FgRed).SprintFunc(), + settings.LevelHigh: color.New(color.FgHiRed).SprintFunc(), + settings.LevelMedium: color.New(color.FgYellow).SprintFunc(), + settings.LevelLow: color.New(color.FgBlue).SprintFunc(), +} func ReportPolicies(report types.Report, output *zerolog.Event, config settings.Config) error { outputPolicies, err := getPolicyReportOutput(report, config) @@ -33,19 +39,19 @@ func ReportPolicies(report types.Report, output *zerolog.Event, config settings. outputStr.WriteString("===============================") for _, policyBreach := range outputPolicies[settings.LevelCritical] { - writePolicyBreachToOutput(outputStr, policyBreach, settings.LevelCritical, color.Red) + writePolicyBreachToOutput(outputStr, policyBreach, settings.LevelCritical) } for _, policyBreach := range outputPolicies[settings.LevelHigh] { - writePolicyBreachToOutput(outputStr, policyBreach, settings.LevelHigh, color.Yellow) + writePolicyBreachToOutput(outputStr, policyBreach, settings.LevelHigh) } for _, policyBreach := range outputPolicies[settings.LevelMedium] { - writePolicyBreachToOutput(outputStr, policyBreach, settings.LevelMedium, color.Cyan) + writePolicyBreachToOutput(outputStr, policyBreach, settings.LevelMedium) } for _, policyBreach := range outputPolicies[settings.LevelLow] { - writePolicyBreachToOutput(outputStr, policyBreach, settings.LevelLow, color.Blue) + writePolicyBreachToOutput(outputStr, policyBreach, settings.LevelLow) } output.Msg(outputStr.String()) @@ -134,18 +140,6 @@ func getPolicyReportOutput(report types.Report, config settings.Config) (map[str return policies.GetOutput(dataflow, config) } -func writePolicyBreachToOutput(outputStr *strings.Builder, policyBreach policies.PolicyResult, policySeverity string, displayColor string) { - outputStr.WriteString("\n") - outputStr.WriteString("\n") - outputStr.WriteString(color.With(displayColor, strings.ToUpper(policySeverity)) + ": ") - outputStr.WriteString(policyBreach.PolicyName + ", policy breached with " + policyBreach.CategoryGroup + "\n") - outputStr.WriteString(policyBreach.PolicyDescription + "\n") - outputStr.WriteString("Filename: " + policyBreach.Filename) - outputStr.WriteString("\n") - outputStr.WriteString("\n") - outputStr.WriteString("===============================") -} - func getDataflow(report types.Report, config settings.Config, isInternal bool) (*dataflow.DataFlow, error) { reportedDetections, err := detectors.GetOutput(report) if err != nil { @@ -154,3 +148,40 @@ func getDataflow(report types.Report, config settings.Config, isInternal bool) ( return dataflow.GetOutput(reportedDetections, config, isInternal) } + +func writePolicyBreachToOutput(outputStr *strings.Builder, policyBreach policies.PolicyResult, policySeverity string) { + outputStr.WriteString("\n\n") + outputStr.WriteString(formatSeverity(policySeverity)) + outputStr.WriteString(policyBreach.PolicyName + " policy breach with " + policyBreach.CategoryGroup + "\n") + outputStr.WriteString(color.HiBlackString(policyBreach.PolicyDescription + "\n")) + outputStr.WriteString("\n") + outputStr.WriteString(color.HiBlueString("File: " + underline(policyBreach.Filename+":"+fmt.Sprint(policyBreach.LineNumber)) + "\n")) + outputStr.WriteString("\n") + outputStr.WriteString(highlightCodeExtract(policyBreach.LineNumber, policyBreach.ParentLineNumber, policyBreach.ParentContent)) + outputStr.WriteString("\n\n") + outputStr.WriteString("=====================================") +} + +func formatSeverity(policySeverity string) string { + severityColorFn, ok := severityColorFns[policySeverity] + if !ok { + return strings.ToUpper(policySeverity) + } + return severityColorFn(strings.ToUpper(policySeverity + ": ")) +} + +func highlightCodeExtract(lineNumber int, extractStartLineNumber int, extract string) string { + result := "" + targetIndex := lineNumber - extractStartLineNumber + for index, line := range strings.Split(extract, "\n") { + if index == targetIndex { + result += color.MagentaString(" " + fmt.Sprint(extractStartLineNumber+index) + " ") + result += color.MagentaString(line) + "\n" + } else { + result += " " + fmt.Sprint(extractStartLineNumber+index) + " " + result += line + "\n" + } + } + + return result +} diff --git a/pkg/report/output/policies/policies.go b/pkg/report/output/policies/policies.go index 252285d56..86695c2b8 100644 --- a/pkg/report/output/policies/policies.go +++ b/pkg/report/output/policies/policies.go @@ -17,17 +17,21 @@ type PolicyInput struct { } type PolicyOutput struct { - LineNumber string `json:"line_number,omitempty" yaml:"line_number,omitempty"` - Filename string `json:"filename,omitempty" yaml:"filename,omitempty"` - CategoryGroup string `json:"category_group,omitempty" yaml:"category_group,omitempty"` + ParentLineNumber int `json:"parent_line_number,omitempty" yaml:"parent_line_number,omitempty"` + ParentContent string `json:"parent_content,omitempty" yaml:"parent_content,omitempty"` + LineNumber int `json:"line_number,omitempty" yaml:"line_number,omitempty"` + Filename string `json:"filename,omitempty" yaml:"filename,omitempty"` + CategoryGroup string `json:"category_group,omitempty" yaml:"category_group,omitempty"` } type PolicyResult struct { PolicyName string `json:"policy_name" yaml:"policy_name"` PolicyDescription string `json:"policy_description" yaml:"policy_description"` - LineNumber string `json:"line_number,omitempty" yaml:"line_number,omitempty"` + LineNumber int `json:"line_number,omitempty" yaml:"line_number,omitempty"` Filename string `json:"filename,omitempty" yaml:"filename,omitempty"` CategoryGroup string `json:"category_group,omitempty" yaml:"category_group,omitempty"` + ParentLineNumber int `json:"parent_line_number,omitempty" yaml:"parent_line_number,omitempty"` + ParentContent string `json:"parent_content,omitempty" yaml:"parent_content,omitempty"` } func GetOutput(dataflow *dataflow.DataFlow, config settings.Config) (map[string][]PolicyResult, error) { @@ -69,8 +73,11 @@ func GetOutput(dataflow *dataflow.DataFlow, config settings.Config) (map[string] policyResult := PolicyResult{ PolicyName: policy.Name, PolicyDescription: policy.Description, - Filename: policyOutput.Filename, + Filename: getFullFilename(config.Target, policyOutput.Filename), + LineNumber: policyOutput.LineNumber, CategoryGroup: policyOutput.CategoryGroup, + ParentLineNumber: policyOutput.ParentLineNumber, + ParentContent: policyOutput.ParentContent, } result[severity] = append(result[severity], policyResult) @@ -81,3 +88,11 @@ func GetOutput(dataflow *dataflow.DataFlow, config settings.Config) (map[string] return result, nil } + +func getFullFilename(path string, filename string) string { + if filename == "." { + return path + } + + return path + filename +}