mirror of
https://github.com/securego/gosec.git
synced 2024-12-25 03:55:54 +00:00
Add possibility to list waived (nosec) marked issues but not count them as such
This commit is contained in:
parent
5a131be2ec
commit
ba23b5e49a
8 changed files with 76 additions and 18 deletions
26
analyzer.go
26
analyzer.go
|
@ -82,6 +82,7 @@ type Analyzer struct {
|
|||
errors map[string][]Error // keys are file paths; values are the golang errors in those files
|
||||
tests bool
|
||||
excludeGenerated bool
|
||||
showIgnored bool
|
||||
}
|
||||
|
||||
// NewAnalyzer builds a new analyzer.
|
||||
|
@ -90,11 +91,16 @@ func NewAnalyzer(conf Config, tests bool, excludeGenerated bool, logger *log.Log
|
|||
if enabled, err := conf.IsGlobalEnabled(Nosec); err == nil {
|
||||
ignoreNoSec = enabled
|
||||
}
|
||||
showIgnored := false
|
||||
if enabled, err := conf.IsGlobalEnabled(ShowIgnored); err == nil {
|
||||
showIgnored = enabled
|
||||
}
|
||||
if logger == nil {
|
||||
logger = log.New(os.Stderr, "[gosec]", log.LstdFlags)
|
||||
}
|
||||
return &Analyzer{
|
||||
ignoreNosec: ignoreNoSec,
|
||||
showIgnored: showIgnored,
|
||||
ruleset: make(RuleSet),
|
||||
context: &Context{},
|
||||
config: conf,
|
||||
|
@ -179,7 +185,7 @@ func (gosec *Analyzer) load(pkgPath string, conf *packages.Config) ([]*packages.
|
|||
}
|
||||
|
||||
if gosec.tests {
|
||||
testsFiles := []string{}
|
||||
testsFiles := make([]string, 0)
|
||||
testsFiles = append(testsFiles, basePackage.TestGoFiles...)
|
||||
testsFiles = append(testsFiles, basePackage.XTestGoFiles...)
|
||||
for _, filename := range testsFiles {
|
||||
|
@ -279,7 +285,7 @@ func (gosec *Analyzer) AppendError(file string, err error) {
|
|||
if r.MatchString(err.Error()) {
|
||||
return
|
||||
}
|
||||
errors := []Error{}
|
||||
errors := make([]Error, 0)
|
||||
if ferrs, ok := gosec.errors[file]; ok {
|
||||
errors = ferrs
|
||||
}
|
||||
|
@ -364,9 +370,8 @@ func (gosec *Analyzer) Visit(n ast.Node) ast.Visitor {
|
|||
gosec.context.Imports.TrackImport(n)
|
||||
|
||||
for _, rule := range gosec.ruleset.RegisteredFor(n) {
|
||||
if _, ok := ignores[rule.ID()]; ok {
|
||||
continue
|
||||
}
|
||||
_, ignored := ignores[rule.ID()]
|
||||
|
||||
issue, err := rule.Match(n, gosec.context)
|
||||
if err != nil {
|
||||
file, line := GetLocation(n, gosec.context)
|
||||
|
@ -374,8 +379,15 @@ func (gosec *Analyzer) Visit(n ast.Node) ast.Visitor {
|
|||
gosec.logger.Printf("Rule error: %v => %s (%s:%d)\n", reflect.TypeOf(rule), err, file, line)
|
||||
}
|
||||
if issue != nil {
|
||||
gosec.issues = append(gosec.issues, issue)
|
||||
gosec.stats.NumFound++
|
||||
if gosec.showIgnored {
|
||||
issue.NoSec = ignored
|
||||
}
|
||||
if !ignored || !gosec.showIgnored {
|
||||
gosec.stats.NumFound++
|
||||
}
|
||||
if !ignored || gosec.showIgnored || gosec.ignoreNosec {
|
||||
gosec.issues = append(gosec.issues, issue)
|
||||
}
|
||||
}
|
||||
}
|
||||
return gosec
|
||||
|
|
|
@ -261,6 +261,32 @@ var _ = Describe("Analyzer", func() {
|
|||
Expect(nosecIssues).Should(HaveLen(sample.Errors))
|
||||
})
|
||||
|
||||
XIt("should be possible to overwrite nosec comments, and report issues but the should not be counted", func() {
|
||||
// Rule for MD5 weak crypto usage
|
||||
sample := testutils.SampleCodeG401[0]
|
||||
source := sample.Code[0]
|
||||
|
||||
// overwrite nosec option
|
||||
nosecIgnoreConfig := gosec.NewConfig()
|
||||
nosecIgnoreConfig.SetGlobal(gosec.Nosec, "true")
|
||||
nosecIgnoreConfig.SetGlobal(gosec.ShowIgnored, "true")
|
||||
customAnalyzer := gosec.NewAnalyzer(nosecIgnoreConfig, tests, false, logger)
|
||||
customAnalyzer.LoadRules(rules.Generate(rules.NewRuleFilter(false, "G401")).Builders())
|
||||
|
||||
nosecPackage := testutils.NewTestPackage()
|
||||
defer nosecPackage.Close()
|
||||
nosecSource := strings.Replace(source, "h := md5.New()", "h := md5.New() // #nosec", 1)
|
||||
nosecPackage.AddFile("md5.go", nosecSource)
|
||||
err := nosecPackage.Build()
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
err = customAnalyzer.Process(buildTags, nosecPackage.Path)
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
nosecIssues, metrics, _ := customAnalyzer.Report()
|
||||
Expect(nosecIssues).Should(HaveLen(sample.Errors))
|
||||
Expect(metrics.NumFound).Should(Equal(0))
|
||||
Expect(metrics.NumNosec).Should(Equal(1))
|
||||
})
|
||||
|
||||
It("should be possible to use an alternative nosec tag", func() {
|
||||
// Rule for MD5 weak crypto usage
|
||||
sample := testutils.SampleCodeG401[0]
|
||||
|
|
|
@ -72,6 +72,9 @@ var (
|
|||
// #nosec flag
|
||||
flagIgnoreNoSec = flag.Bool("nosec", false, "Ignores #nosec comments when set")
|
||||
|
||||
// show ignored
|
||||
flagShowIgnored = flag.Bool("show-ignored", false, "If enabled, ignored issues are printed")
|
||||
|
||||
// format output
|
||||
flagFormat = flag.String("fmt", "text", "Set output format. Valid options are: json, yaml, csv, junit-xml, html, sonarqube, golint, sarif or text")
|
||||
|
||||
|
@ -173,6 +176,9 @@ func loadConfig(configFile string) (gosec.Config, error) {
|
|||
if *flagIgnoreNoSec {
|
||||
config.SetGlobal(gosec.Nosec, "true")
|
||||
}
|
||||
if *flagShowIgnored {
|
||||
config.SetGlobal(gosec.ShowIgnored, "true")
|
||||
}
|
||||
if *flagAlternativeNoSec != "" {
|
||||
config.SetGlobal(gosec.NoSecAlternative, *flagAlternativeNoSec)
|
||||
}
|
||||
|
@ -200,7 +206,7 @@ func loadRules(include, exclude string) rules.RuleList {
|
|||
}
|
||||
|
||||
func getRootPaths(paths []string) []string {
|
||||
rootPaths := []string{}
|
||||
rootPaths := make([]string, 0)
|
||||
for _, path := range paths {
|
||||
rootPath, err := gosec.RootPath(path)
|
||||
if err != nil {
|
||||
|
@ -255,14 +261,18 @@ func convertToScore(severity string) (gosec.Score, error) {
|
|||
}
|
||||
}
|
||||
|
||||
func filterIssues(issues []*gosec.Issue, severity gosec.Score, confidence gosec.Score) []*gosec.Issue {
|
||||
result := []*gosec.Issue{}
|
||||
func filterIssues(issues []*gosec.Issue, severity gosec.Score, confidence gosec.Score) ([]*gosec.Issue, int) {
|
||||
result := make([]*gosec.Issue, 0)
|
||||
trueIssues := 0
|
||||
for _, issue := range issues {
|
||||
if issue.Severity >= severity && issue.Confidence >= confidence {
|
||||
result = append(result, issue)
|
||||
if !issue.NoSec || !*flagShowIgnored {
|
||||
trueIssues++
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
return result, trueIssues
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
@ -372,9 +382,10 @@ func main() {
|
|||
}
|
||||
|
||||
// Filter the issues by severity and confidence
|
||||
issues = filterIssues(issues, failSeverity, failConfidence)
|
||||
if metrics.NumFound != len(issues) {
|
||||
metrics.NumFound = len(issues)
|
||||
var trueIssues int
|
||||
issues, trueIssues = filterIssues(issues, failSeverity, failConfidence)
|
||||
if metrics.NumFound != trueIssues {
|
||||
metrics.NumFound = trueIssues
|
||||
}
|
||||
|
||||
// Exit quietly if nothing was found
|
||||
|
@ -390,7 +401,7 @@ func main() {
|
|||
if *flagOutput == "" || *flagStdOut {
|
||||
fileFormat := getPrintedFormat(*flagFormat, *flagVerbose)
|
||||
if err := printReport(fileFormat, *flagColor, rootPaths, reportInfo); err != nil {
|
||||
logger.Fatal((err))
|
||||
logger.Fatal(err)
|
||||
}
|
||||
}
|
||||
if *flagOutput != "" {
|
||||
|
|
|
@ -20,6 +20,8 @@ type GlobalOption string
|
|||
const (
|
||||
// Nosec global option for #nosec directive
|
||||
Nosec GlobalOption = "nosec"
|
||||
// ShowIgnored defines whether nosec issues are counted as finding or not
|
||||
ShowIgnored GlobalOption = "show-ignored"
|
||||
// Audit global option which indicates that gosec runs in audit mode
|
||||
Audit GlobalOption = "audit"
|
||||
// NoSecAlternative global option alternative for #nosec directive
|
||||
|
|
1
issue.go
1
issue.go
|
@ -97,6 +97,7 @@ type Issue struct {
|
|||
Code string `json:"code"` // Impacted code line
|
||||
Line string `json:"line"` // Line number in file
|
||||
Col string `json:"column"` // Column number in line
|
||||
NoSec bool `json:"nosec"` // true if the issue is nosec
|
||||
}
|
||||
|
||||
// FileLocation point out the file path and line number in file
|
||||
|
|
|
@ -62,6 +62,8 @@ const templateContent = `
|
|||
level += " is-warning";
|
||||
} else if (this.props.level === "LOW") {
|
||||
level += " is-info";
|
||||
} else if (this.props.level === "WAIVED") {
|
||||
level += " is-success";
|
||||
}
|
||||
level +=" is-rounded";
|
||||
return (
|
||||
|
@ -96,6 +98,7 @@ const templateContent = `
|
|||
</div>
|
||||
<div className="column is-one-quarter">
|
||||
<div className="field is-grouped is-grouped-multiline">
|
||||
{this.props.data.nosec && <IssueTag label="NoSec" level="WAIVED"/>}
|
||||
<IssueTag label="Severity" level={ this.props.data.severity }/>
|
||||
<IssueTag label="Confidence" level={ this.props.data.confidence }/>
|
||||
</div>
|
||||
|
|
|
@ -8,7 +8,7 @@ Golang errors in file: [{{ $filePath }}]:
|
|||
{{end}}
|
||||
{{end}}
|
||||
{{ range $index, $issue := .Issues }}
|
||||
[{{ highlight $issue.FileLocation $issue.Severity }}] - {{ $issue.RuleID }} ({{ $issue.Cwe.SprintID }}): {{ $issue.What }} (Confidence: {{ $issue.Confidence}}, Severity: {{ $issue.Severity }})
|
||||
[{{ highlight $issue.FileLocation $issue.Severity $issue.NoSec }}] - {{ $issue.RuleID }}{{ if $issue.NoSec }} ({{- success "NoSec" -}}){{ end }} ({{ $issue.Cwe.SprintID }}): {{ $issue.What }} (Confidence: {{ $issue.Confidence}}, Severity: {{ $issue.Severity }})
|
||||
{{ printCode $issue }}
|
||||
|
||||
{{ end }}
|
||||
|
|
|
@ -45,7 +45,7 @@ func plainTextFuncMap(enableColor bool) template.FuncMap {
|
|||
|
||||
// by default those functions return the given content untouched
|
||||
return template.FuncMap{
|
||||
"highlight": func(t string, s gosec.Score) string {
|
||||
"highlight": func(t string, s gosec.Score, ignored bool) string {
|
||||
return t
|
||||
},
|
||||
"danger": fmt.Sprint,
|
||||
|
@ -56,7 +56,10 @@ func plainTextFuncMap(enableColor bool) template.FuncMap {
|
|||
}
|
||||
|
||||
// highlight returns content t colored based on Score
|
||||
func highlight(t string, s gosec.Score) string {
|
||||
func highlight(t string, s gosec.Score, ignored bool) string {
|
||||
if ignored {
|
||||
return defaultTheme.Sprint(t)
|
||||
}
|
||||
switch s {
|
||||
case gosec.High:
|
||||
return errorTheme.Sprint(t)
|
||||
|
|
Loading…
Reference in a new issue