Skip to content

Commit

Permalink
feat: improve report summary (#513)
Browse files Browse the repository at this point in the history
* feat: improve report summary

* chore: pr feedback
  • Loading branch information
gotbadger authored Feb 8, 2023
1 parent 2f360bb commit 8293485
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 49 deletions.
27 changes: 13 additions & 14 deletions pkg/report/output/output.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,17 @@ func ReportSummary(report types.Report, output *zerolog.Event, config settings.C
return
}

summaryResults, err := getSummaryReportOutput(report, config)
dataflow, err := getDataflow(report, config, true)
if err != nil {
return
}

summaryResults, err := summary.GetOutput(dataflow, config)
if err != nil {
return
}

outputToFile := config.Report.Output != ""
severityForFailure := config.Report.Severity
reportStr, reportPassed := summary.BuildReportString(config.Rules, summaryResults, severityForFailure, outputToFile)
reportStr, reportPassed := summary.BuildReportString(config, summaryResults, lineOfCodeOutput, dataflow)

output.Msg(reportStr.String())

Expand Down Expand Up @@ -108,13 +111,18 @@ func ReportYAML(report types.Report, output *zerolog.Event, config settings.Conf
}

func getReportOutput(report types.Report, config settings.Config) (any, error) {

switch config.Report.Report {
case flag.ReportDetectors:
return detectors.GetOutput(report, config)
case flag.ReportDataFlow:
return getDataflow(report, config, false)
case flag.ReportSummary:
return getSummaryReportOutput(report, config)
dataflow, err := getDataflow(report, config, true)
if err != nil {
return nil, err
}
return summary.GetOutput(dataflow, config)
case flag.ReportPrivacy:
return getPrivacyReportOutput(report, config)
case flag.ReportStats:
Expand Down Expand Up @@ -148,15 +156,6 @@ func getPrivacyReportOutput(report types.Report, config settings.Config) (*priva
return privacy.GetOutput(dataflow, config)
}

func getSummaryReportOutput(report types.Report, config settings.Config) (map[string][]summary.Result, error) {
dataflow, err := getDataflow(report, config, true)
if err != nil {
return nil, err
}

return summary.GetOutput(dataflow, config)
}

func getDataflow(report types.Report, config settings.Config, isInternal bool) (*dataflow.DataFlow, error) {
reportedDetections, err := detectors.GetOutput(report, config)
if err != nil {
Expand Down
50 changes: 28 additions & 22 deletions pkg/report/output/stats/stats.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,35 +112,21 @@ func getDataGroupNames(config settings.Config, dataTypes []DataType) []string {
return maputil.SortedStringKeys(dataGroups)
}

func GetPlaceholderOutput(inputgocloc *gocloc.Result, inputDataflow *dataflow.DataFlow, config settings.Config) (outputStr *strings.Builder, err error) {
outputStr = &strings.Builder{}
statistics, err := GetOutput(inputgocloc, inputDataflow, config)
func AnythingFoundFor(statistics *Stats) bool {
return statistics.NumberOfDataTypes != 0 ||
statistics.NumberOfDatabases != 0 ||
statistics.NumberOfExternalAPIs != 0 ||
statistics.NumberOfInternalAPIs != 0
}

func WriteStatsToString(outputStr *strings.Builder, statistics *Stats) {
totalDataTypeOccurrences := 0
for _, dataType := range statistics.DataTypes {
totalDataTypeOccurrences += dataType.Occurrences
}

supportURL := "https://curio.sh/explanations/reports/"
outputStr.WriteString(fmt.Sprintf(`
The policy report is not yet available for your stack. Learn more at %s`,
supportURL))

anythingFound :=
statistics.NumberOfDataTypes != 0 ||
statistics.NumberOfDatabases != 0 ||
statistics.NumberOfExternalAPIs != 0 ||
statistics.NumberOfInternalAPIs != 0
if anythingFound {
outputStr.WriteString(`
Though this doesn’t mean the curious bear comes empty-handed, it found:
`)
}

if statistics.NumberOfDataTypes != 0 {
outputStr.WriteString(fmt.Sprintf(`
- %d unique data type(s), representing %d occurrences, including %s.`,
outputStr.WriteString(fmt.Sprintf(`- %d unique data type(s), representing %d occurrences, including %s.`,
statistics.NumberOfDataTypes,
totalDataTypeOccurrences,
strings.Join(statistics.DataGroups, ", ")))
Expand Down Expand Up @@ -172,6 +158,26 @@ Though this doesn’t mean the curious bear comes empty-handed, it found:
- %d internal URL(s).`,
statistics.NumberOfInternalAPIs))
}
}

func GetPlaceholderOutput(inputgocloc *gocloc.Result, inputDataflow *dataflow.DataFlow, config settings.Config) (outputStr *strings.Builder, err error) {
outputStr = &strings.Builder{}
statistics, err := GetOutput(inputgocloc, inputDataflow, config)

supportURL := "https://curio.sh/explanations/reports/"
outputStr.WriteString(fmt.Sprintf(`
The policy report is not yet available for your stack. Learn more at %s`,
supportURL))

if AnythingFoundFor(statistics) {
outputStr.WriteString(`
Though this doesn’t mean the curious bear comes empty-handed, it found:
`)
}

WriteStatsToString(outputStr, statistics)

suggestedCommand := color.New(color.Italic).Sprintf("curio scan %s --report dataflow", config.Target)
outputStr.WriteString(fmt.Sprintf(`
Expand Down
61 changes: 48 additions & 13 deletions pkg/report/output/summary/summary.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@ import (
"github.com/bearer/curio/pkg/util/output"
"github.com/bearer/curio/pkg/util/rego"
"github.com/fatih/color"
"github.com/hhatto/gocloc"
"golang.org/x/exp/maps"
"golang.org/x/exp/slices"

"github.com/bearer/curio/pkg/report/output/dataflow"
stats "github.com/bearer/curio/pkg/report/output/stats"
)

var underline = color.New(color.Underline).SprintFunc()
Expand Down Expand Up @@ -135,8 +137,12 @@ func GetOutput(dataflow *dataflow.DataFlow, config settings.Config) (map[string]
return result, nil
}

func BuildReportString(rules map[string]*settings.Rule, results map[string][]Result, severityForFailure map[string]bool, withoutColor bool) (*strings.Builder, bool) {
func BuildReportString(config settings.Config, results map[string][]Result, lineOfCodeOutput *gocloc.Result, dataflow *dataflow.DataFlow) (*strings.Builder, bool) {
rules := config.Rules
withoutColor := config.Report.Output != ""
severityForFailure := config.Report.Severity
reportStr := &strings.Builder{}

reportStr.WriteString("\n\nSummary Report\n")
reportStr.WriteString("\n=====================================")

Expand Down Expand Up @@ -170,7 +176,18 @@ func BuildReportString(rules map[string]*settings.Rule, results map[string][]Res
}
}

writeSummaryToString(reportStr, results, len(rules), failures, severityForFailure)
if reportPassed {
reportStr.WriteString("\nNeed to add your own custom rule? Check out the guide: https://curio.sh/guides/custom-rule\n")
}

noFailureSummary := checkAndWriteFailureSummaryToString(reportStr, results, len(rules), failures, severityForFailure)

if noFailureSummary {
writeSuccessToString(len(rules), reportStr)
writeStatsToString(reportStr, config, lineOfCodeOutput, dataflow)
}

reportStr.WriteString("\nNeed help or want to discuss the output? Join the Community https://discord.gg/eaHZBJUXRF\n")

color.NoColor = initialColorSetting

Expand Down Expand Up @@ -198,6 +215,23 @@ func FindHighestSeverity(groups []string, severity map[string]string) string {
return severity["default"]
}

func writeStatsToString(
reportStr *strings.Builder,
config settings.Config,
lineOfCodeOutput *gocloc.Result,
dataflow *dataflow.DataFlow,
) {
statistics, err := stats.GetOutput(lineOfCodeOutput, dataflow, config)
if err != nil {
return
}
if stats.AnythingFoundFor(statistics) {
reportStr.WriteString("\nCurio found:\n")
stats.WriteStatsToString(reportStr, statistics)
reportStr.WriteString("\n")
}
}

func writeRuleListToString(
reportStr *strings.Builder,
rules map[string]*settings.Rule) {
Expand All @@ -216,19 +250,22 @@ func writeRuleListToString(
reportStr.WriteString(strings.Join(ruleList, ""))
}

func writeSummaryToString(
func writeSuccessToString(policyCount int, reportStr *strings.Builder) {
reportStr.WriteString("\n\n")
reportStr.WriteString(color.HiGreenString("SUCCESS\n\n"))
reportStr.WriteString(fmt.Sprint(policyCount) + " checks were run and no failures were detected. Great job! 👏\n")
}

func checkAndWriteFailureSummaryToString(
reportStr *strings.Builder,
policyResults map[string][]Result,
policyCount int, policyFailures map[string]map[string]bool,
severityForFailure map[string]bool,
) {
) bool {
reportStr.WriteString("\n=====================================")

if len(policyResults) == 0 {
reportStr.WriteString("\n\n")
reportStr.WriteString(color.HiGreenString("SUCCESS\n\n"))
reportStr.WriteString(fmt.Sprint(policyCount) + " checks were run and no failures were detected.\n\n")
return
return true
}

// give summary including counts
Expand All @@ -246,11 +283,7 @@ func writeSummaryToString(
}

if failureCount == 0 && warningCount == 0 {
// no failures and no warnings : success
reportStr.WriteString("\n\n")
reportStr.WriteString(color.HiGreenString("SUCCESS\n\n"))
reportStr.WriteString(fmt.Sprint(policyCount) + " checks were run and no failures were detected.\n\n")
return
return true
}

reportStr.WriteString("\n\n")
Expand Down Expand Up @@ -281,6 +314,8 @@ func writeSummaryToString(
}

reportStr.WriteString("\n")

return false
}

func writeFailureToString(reportStr *strings.Builder, result Result, policySeverity string) {
Expand Down

0 comments on commit 8293485

Please sign in to comment.