Skip to content

Commit

Permalink
feat: add severity computation details (#1195)
Browse files Browse the repository at this point in the history
* feat: add severity computation details

* ci: update tests

* fix: update tests and always include bool

* fixup: update severity default to avoid empty values

* feat: add severity weighting to saas

* fix: clean up stale snapshots

* feat: rename to SeverityMeta and add raw fields

---------

Co-authored-by: elsapet <elizabeth@bearer.sh>
  • Loading branch information
cfabianski and elsapet authored Aug 30, 2023
1 parent f13e708 commit d723dbb
Show file tree
Hide file tree
Showing 10 changed files with 163 additions and 38 deletions.
10 changes: 10 additions & 0 deletions pkg/commands/process/settings/settings.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import (
"github.com/bearer/bearer/pkg/util/ignore"
"github.com/bearer/bearer/pkg/util/output"
"github.com/bearer/bearer/pkg/util/rego"

globaltypes "github.com/bearer/bearer/pkg/types"
)

var (
Expand Down Expand Up @@ -253,6 +255,14 @@ func (rule *Rule) PolicyType() bool {
return rule.Type == "risk"
}

func (rule *Rule) GetSeverity() string {
if rule.Severity == "" {
return globaltypes.LevelLow
}

return rule.Severity
}

func (rule *Rule) Language() string {
if rule.Languages == nil {
return "secret"
Expand Down
6 changes: 3 additions & 3 deletions pkg/report/output/privacy/privacy.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ func AddReportData(reportData *outputtypes.ReportData, config settings.Config) e
}

for _, ruleOutputFailure := range ruleOutput["local_rule_failure"] {
ruleSeverity := security.CalculateSeverity(ruleOutputFailure.CategoryGroups, rule.Severity, true)
ruleSeverity := security.CalculateSeverity(ruleOutputFailure.CategoryGroups, rule.GetSeverity(), true)

key := buildKey(ruleOutputFailure.DataSubject, ruleOutputFailure.DataType)
subjectRuleFailure, ok := subjectRuleFailures[key]
Expand All @@ -193,7 +193,7 @@ func AddReportData(reportData *outputtypes.ReportData, config settings.Config) e
}

// count severity
switch ruleSeverity {
switch ruleSeverity.DisplaySeverity {
case globaltypes.LevelCritical:
subjectRuleFailure.CriticalRiskFindingCount += 1
case globaltypes.LevelHigh:
Expand Down Expand Up @@ -233,7 +233,7 @@ func AddReportData(reportData *outputtypes.ReportData, config settings.Config) e
}

// count severity
switch ruleSeverity {
switch ruleSeverity.DisplaySeverity {
case globaltypes.LevelCritical:
thirdPartyDataSubject.CriticalRiskFindingCount += 1
case globaltypes.LevelHigh:
Expand Down
7 changes: 6 additions & 1 deletion pkg/report/output/saas/saas.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,12 @@ func GetReport(reportData *types.ReportData, config settings.Config, ensureMeta
saasFindingsBySeverity := make(map[string][]saas.SaasFinding)
for _, severity := range maps.Keys(reportData.FindingsBySeverity) {
for _, finding := range reportData.FindingsBySeverity[severity] {
saasFindingsBySeverity[severity] = append(saasFindingsBySeverity[severity], saas.SaasFinding{Finding: finding})
saasFindingsBySeverity[severity] = append(
saasFindingsBySeverity[severity],
saas.SaasFinding{
Finding: finding,
SeverityMeta: finding.SeverityMeta,
})
}
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/report/output/saas/types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,5 @@ type BearerReport struct {

type SaasFinding struct {
securitytypes.Finding
// add any extra data to send to SaaS
SeverityMeta securitytypes.SeverityMeta `json:"severity_meta" yaml:"severity_meta"`
}
27 changes: 25 additions & 2 deletions pkg/report/output/security/.snapshots/TestAddReportData
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,19 @@
CodeExtract: (string) "",
RawCodeExtract: ([]file.Line) {
},
SomeExtraField: (string) ""
SeverityMeta: (types.SeverityMeta) {
RuleSeverity: (string) (len=3) "low",
SensitiveDataCategories: ([]string) (len=3) {
(string) (len=3) "PII",
(string) (len=13) "Personal Data",
(string) (len=25) "Personal Data (Sensitive)"
},
HasLocalDataTypes: (*bool)(true),
SensitiveDataCategoryWeighting: (int) 3,
RuleSeverityWeighting: (int) 2,
FinalWeighting: (int) 8,
DisplaySeverity: (string) (len=8) "critical"
}
}
},
(string) (len=4) "high": ([]types.Finding) (len=1) {
Expand Down Expand Up @@ -103,7 +115,18 @@
CodeExtract: (string) "",
RawCodeExtract: ([]file.Line) {
},
SomeExtraField: (string) ""
SeverityMeta: (types.SeverityMeta) {
RuleSeverity: (string) (len=6) "medium",
SensitiveDataCategories: ([]string) (len=2) {
(string) (len=3) "PII",
(string) (len=13) "Personal Data"
},
HasLocalDataTypes: (*bool)(false),
SensitiveDataCategoryWeighting: (int) 2,
RuleSeverityWeighting: (int) 3,
FinalWeighting: (int) 5,
DisplaySeverity: (string) (len=4) "high"
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,19 @@
CodeExtract: (string) "",
RawCodeExtract: ([]file.Line) {
},
SomeExtraField: (string) ""
SeverityMeta: (types.SeverityMeta) {
RuleSeverity: (string) (len=3) "low",
SensitiveDataCategories: ([]string) (len=3) {
(string) (len=3) "PII",
(string) (len=13) "Personal Data",
(string) (len=25) "Personal Data (Sensitive)"
},
HasLocalDataTypes: (*bool)(true),
SensitiveDataCategoryWeighting: (int) 3,
RuleSeverityWeighting: (int) 2,
FinalWeighting: (int) 8,
DisplaySeverity: (string) (len=8) "critical"
}
}
}
}
59 changes: 53 additions & 6 deletions pkg/report/output/security/.snapshots/TestCalculateSeverity
Original file line number Diff line number Diff line change
@@ -1,7 +1,54 @@
([]string) (len=5) {
(string) (len=8) "critical",
(string) (len=4) "high",
(string) (len=6) "medium",
(string) (len=7) "warning",
(string) (len=7) "warning"
([]types.SeverityMeta) (len=5) {
(types.SeverityMeta) {
RuleSeverity: (string) (len=3) "low",
SensitiveDataCategories: ([]string) (len=2) {
(string) (len=3) "PHI",
(string) (len=13) "Personal Data"
},
HasLocalDataTypes: (*bool)(true),
SensitiveDataCategoryWeighting: (int) 3,
RuleSeverityWeighting: (int) 2,
FinalWeighting: (int) 8,
DisplaySeverity: (string) (len=8) "critical"
},
(types.SeverityMeta) {
RuleSeverity: (string) (len=3) "low",
SensitiveDataCategories: ([]string) (len=1) {
(string) (len=25) "Personal Data (Sensitive)"
},
HasLocalDataTypes: (*bool)(false),
SensitiveDataCategoryWeighting: (int) 3,
RuleSeverityWeighting: (int) 2,
FinalWeighting: (int) 5,
DisplaySeverity: (string) (len=4) "high"
},
(types.SeverityMeta) {
RuleSeverity: (string) (len=3) "low",
SensitiveDataCategories: ([]string) (len=1) {
(string) (len=13) "Personal Data"
},
HasLocalDataTypes: (*bool)(false),
SensitiveDataCategoryWeighting: (int) 2,
RuleSeverityWeighting: (int) 2,
FinalWeighting: (int) 4,
DisplaySeverity: (string) (len=6) "medium"
},
(types.SeverityMeta) {
RuleSeverity: (string) (len=7) "warning",
SensitiveDataCategories: ([]string) <nil>,
HasLocalDataTypes: (*bool)(<nil>),
SensitiveDataCategoryWeighting: (int) 0,
RuleSeverityWeighting: (int) 0,
FinalWeighting: (int) 0,
DisplaySeverity: (string) (len=7) "warning"
},
(types.SeverityMeta) {
RuleSeverity: (string) (len=7) "warning",
SensitiveDataCategories: ([]string) <nil>,
HasLocalDataTypes: (*bool)(<nil>),
SensitiveDataCategoryWeighting: (int) 0,
RuleSeverityWeighting: (int) 0,
FinalWeighting: (int) 0,
DisplaySeverity: (string) (len=7) "warning"
}
}
33 changes: 25 additions & 8 deletions pkg/report/output/security/security.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,9 +228,11 @@ func evaluateRules(
OldFingerprint: oldFingerprint,
}

severity := CalculateSeverity(finding.CategoryGroups, rule.Severity, output.IsLocal != nil && *output.IsLocal)
severityWeighting := CalculateSeverity(finding.CategoryGroups, rule.GetSeverity(), output.IsLocal != nil && *output.IsLocal)
severity := severityWeighting.DisplaySeverity

if config.Report.Severity[severity] {
finding.SeverityMeta = severityWeighting
outputFindings[severity] = append(outputFindings[severity], finding)
}
}
Expand Down Expand Up @@ -389,9 +391,12 @@ func BuildReportString(reportData *outputtypes.ReportData, config settings.Confi
return reportStr
}

func CalculateSeverity(groups []string, severity string, hasLocalDataTypes bool) string {
func CalculateSeverity(groups []string, severity string, hasLocalDataTypes bool) types.SeverityMeta {
if severity == globaltypes.LevelWarning {
return globaltypes.LevelWarning
return types.SeverityMeta{
RuleSeverity: severity,
DisplaySeverity: globaltypes.LevelWarning,
}
}

// highest sensitive data category
Expand Down Expand Up @@ -423,16 +428,28 @@ func CalculateSeverity(groups []string, severity string, hasLocalDataTypes bool)
triggerWeighting = 2
}

switch finalWeighting := ruleSeverityWeighting + (sensitiveDataCategoryWeighting * triggerWeighting); {
var displaySeverity string
finalWeighting := ruleSeverityWeighting + (sensitiveDataCategoryWeighting * triggerWeighting)
switch {
case finalWeighting >= 8:
return globaltypes.LevelCritical
displaySeverity = globaltypes.LevelCritical
case finalWeighting >= 5:
return globaltypes.LevelHigh
displaySeverity = globaltypes.LevelHigh
case finalWeighting >= 3:
return globaltypes.LevelMedium
displaySeverity = globaltypes.LevelMedium
default:
displaySeverity = globaltypes.LevelLow
}

return globaltypes.LevelLow
return types.SeverityMeta{
RuleSeverity: severity,
SensitiveDataCategories: groups,
HasLocalDataTypes: &hasLocalDataTypes,
RuleSeverityWeighting: ruleSeverityWeighting,
SensitiveDataCategoryWeighting: sensitiveDataCategoryWeighting,
FinalWeighting: finalWeighting,
DisplaySeverity: displaySeverity,
}
}

func writeStatsToString(
Expand Down
3 changes: 2 additions & 1 deletion pkg/report/output/security/security_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (

dataflowtypes "github.com/bearer/bearer/pkg/report/output/dataflow/types"
"github.com/bearer/bearer/pkg/report/output/security"
securitytypes "github.com/bearer/bearer/pkg/report/output/security/types"
"github.com/bearer/bearer/pkg/report/output/types"
outputtypes "github.com/bearer/bearer/pkg/report/output/types"
)
Expand Down Expand Up @@ -161,7 +162,7 @@ func TestAddReportDataWithSeverity(t *testing.T) {
}

func TestCalculateSeverity(t *testing.T) {
res := []string{
res := []securitytypes.SeverityMeta{
security.CalculateSeverity([]string{"PHI", "Personal Data"}, "low", true),
security.CalculateSeverity([]string{"Personal Data (Sensitive)"}, "low", false),
security.CalculateSeverity([]string{"Personal Data"}, "low", false),
Expand Down
40 changes: 25 additions & 15 deletions pkg/report/output/security/types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,21 @@ import (

type Finding struct {
*Rule
LineNumber int `json:"line_number,omitempty" yaml:"line_number,omitempty"`
FullFilename string `json:"full_filename,omitempty" yaml:"full_filename,omitempty"`
Filename string `json:"filename,omitempty" yaml:"filename,omitempty"`
DataType *DataType `json:"data_type,omitempty" yaml:"data_type,omitempty"`
CategoryGroups []string `json:"category_groups,omitempty" yaml:"category_groups,omitempty"`
Source Source `json:"source,omitempty" yaml:"source,omitempty"`
Sink Sink `json:"sink,omitempty" yaml:"sink,omitempty"`
ParentLineNumber int `json:"parent_line_number,omitempty" yaml:"parent_line_number,omitempty"`
ParentContent string `json:"snippet,omitempty" yaml:"snippet,omitempty"`
Fingerprint string `json:"fingerprint,omitempty" yaml:"fingerprint,omitempty"`
OldFingerprint string `json:"old_fingerprint,omitempty" yaml:"old_fingerprint,omitempty"`
DetailedContext string `json:"detailed_context,omitempty" yaml:"detailed_context,omitempty"`
CodeExtract string `json:"code_extract,omitempty" yaml:"code_extract,omitempty"`
RawCodeExtract []file.Line `json:"-" yaml:"-"`
SomeExtraField string `json:"-" yaml:"-"`
LineNumber int `json:"line_number,omitempty" yaml:"line_number,omitempty"`
FullFilename string `json:"full_filename,omitempty" yaml:"full_filename,omitempty"`
Filename string `json:"filename,omitempty" yaml:"filename,omitempty"`
DataType *DataType `json:"data_type,omitempty" yaml:"data_type,omitempty"`
CategoryGroups []string `json:"category_groups,omitempty" yaml:"category_groups,omitempty"`
Source Source `json:"source,omitempty" yaml:"source,omitempty"`
Sink Sink `json:"sink,omitempty" yaml:"sink,omitempty"`
ParentLineNumber int `json:"parent_line_number,omitempty" yaml:"parent_line_number,omitempty"`
ParentContent string `json:"snippet,omitempty" yaml:"snippet,omitempty"`
Fingerprint string `json:"fingerprint,omitempty" yaml:"fingerprint,omitempty"`
OldFingerprint string `json:"old_fingerprint,omitempty" yaml:"old_fingerprint,omitempty"`
DetailedContext string `json:"detailed_context,omitempty" yaml:"detailed_context,omitempty"`
CodeExtract string `json:"code_extract,omitempty" yaml:"code_extract,omitempty"`
RawCodeExtract []file.Line `json:"-" yaml:"-"`
SeverityMeta SeverityMeta `json:"-" yaml:"-"`
}

type DataType struct {
Expand Down Expand Up @@ -60,6 +60,16 @@ type Sink struct {
Content string `json:"content" yaml:"content"`
}

type SeverityMeta struct {
RuleSeverity string `json:"rule_severity" yaml:"rule_severity"`
SensitiveDataCategories []string `json:"sensitive_data_categories" yaml:"sensitive_data_categories"`
HasLocalDataTypes *bool `json:"local_data_types,omitempty" yaml:"local_data_types,omitempty"`
SensitiveDataCategoryWeighting int `json:"sensitive_data_category_weighting,omitempty" yaml:"sensitive_data_category_weighting,omitempty"`
RuleSeverityWeighting int `json:"rule_severity_weighting,omitempty" yaml:"rule_severity_weighting,omitempty"`
FinalWeighting int `json:"final_weighting,omitempty" yaml:"final_weighting,omitempty"`
DisplaySeverity string `json:"display_severity" yaml:"display_severity"`
}

func (f Finding) HighlightCodeExtract() string {
result := ""
for _, line := range f.RawCodeExtract {
Expand Down

0 comments on commit d723dbb

Please sign in to comment.