mirror of
https://github.com/securego/gosec.git
synced 2024-12-24 11:35:52 +00:00
Add CWE rule mappings (#405)
* added mappings * added cwe to template * link in function to template * moved mappings and added test cases * wording * cleanup
This commit is contained in:
parent
28c1128b73
commit
53be8dd864
6 changed files with 235 additions and 4 deletions
41
issue.go
41
issue.go
|
@ -34,10 +34,50 @@ const (
|
|||
High
|
||||
)
|
||||
|
||||
// Cwe id and url
|
||||
type Cwe struct {
|
||||
ID string
|
||||
URL string
|
||||
}
|
||||
|
||||
// GetCwe creates a cwe object for a given RuleID
|
||||
func GetCwe(id string) Cwe {
|
||||
return Cwe{ID: id, URL: fmt.Sprintf("https://cwe.mitre.org/data/definitions/%s.html", id)}
|
||||
}
|
||||
|
||||
// IssueToCWE maps gosec rules to CWEs
|
||||
var IssueToCWE = map[string]Cwe{
|
||||
"G101": GetCwe("798"),
|
||||
"G102": GetCwe("200"),
|
||||
"G103": GetCwe("242"),
|
||||
"G104": GetCwe("703"),
|
||||
"G106": GetCwe("322"),
|
||||
"G107": GetCwe("88"),
|
||||
"G201": GetCwe("89"),
|
||||
"G202": GetCwe("89"),
|
||||
"G203": GetCwe("79"),
|
||||
"G204": GetCwe("78"),
|
||||
"G301": GetCwe("276"),
|
||||
"G302": GetCwe("276"),
|
||||
"G303": GetCwe("377"),
|
||||
"G304": GetCwe("22"),
|
||||
"G305": GetCwe("22"),
|
||||
"G401": GetCwe("326"),
|
||||
"G402": GetCwe("295"),
|
||||
"G403": GetCwe("310"),
|
||||
"G404": GetCwe("338"),
|
||||
"G501": GetCwe("327"),
|
||||
"G502": GetCwe("327"),
|
||||
"G503": GetCwe("327"),
|
||||
"G504": GetCwe("327"),
|
||||
"G505": GetCwe("327"),
|
||||
}
|
||||
|
||||
// Issue is returned by a gosec rule if it discovers an issue with the scanned code.
|
||||
type Issue struct {
|
||||
Severity Score `json:"severity"` // issue severity (how problematic it is)
|
||||
Confidence Score `json:"confidence"` // issue confidence (how sure we are we found it)
|
||||
Cwe Cwe `json:"cwe"` // Cwe associated with RuleID
|
||||
RuleID string `json:"rule_id"` // Human readable explanation
|
||||
What string `json:"details"` // Human readable explanation
|
||||
File string `json:"file"` // File name we found it in
|
||||
|
@ -121,5 +161,6 @@ func NewIssue(ctx *Context, node ast.Node, ruleID, desc string, severity Score,
|
|||
Confidence: confidence,
|
||||
Severity: severity,
|
||||
Code: code,
|
||||
Cwe: IssueToCWE[ruleID],
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ var _ = Describe("Issue", func() {
|
|||
Expect(issue).ShouldNot(BeNil())
|
||||
Expect(issue.Code).Should(MatchRegexp(`"bar"`))
|
||||
Expect(issue.Line).Should(Equal("2"))
|
||||
|
||||
Expect(issue.Cwe.ID).Should(Equal(""))
|
||||
})
|
||||
|
||||
It("should return an error if specific context is not able to be obtained", func() {
|
||||
|
|
|
@ -18,6 +18,7 @@ import (
|
|||
"encoding/csv"
|
||||
"encoding/json"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
htmlTemplate "html/template"
|
||||
"io"
|
||||
"strconv"
|
||||
|
@ -56,7 +57,7 @@ Golang errors in file: [{{ $filePath }}]:
|
|||
{{end}}
|
||||
{{end}}
|
||||
{{ range $index, $issue := .Issues }}
|
||||
[{{ $issue.File }}:{{ $issue.Line }}] - {{ $issue.RuleID }}: {{ $issue.What }} (Confidence: {{ $issue.Confidence}}, Severity: {{ $issue.Severity }})
|
||||
[{{ $issue.File }}:{{ $issue.Line }}] - {{ $issue.RuleID }} (CWE-{{ $issue.Cwe.ID }}): {{ $issue.What }} (Confidence: {{ $issue.Confidence}}, Severity: {{ $issue.Severity }})
|
||||
> {{ $issue.Code }}
|
||||
|
||||
{{ end }}
|
||||
|
@ -126,6 +127,7 @@ func convertToSonarIssues(rootPaths []string, data *reportInfo) (*sonarIssues, e
|
|||
sonarFilePath = strings.Replace(issue.File, rootPath+"/", "", 1)
|
||||
}
|
||||
}
|
||||
|
||||
if sonarFilePath == "" {
|
||||
continue
|
||||
}
|
||||
|
@ -154,6 +156,7 @@ func convertToSonarIssues(rootPaths []string, data *reportInfo) (*sonarIssues, e
|
|||
Type: "VULNERABILITY",
|
||||
Severity: getSonarSeverity(issue.Severity.String()),
|
||||
EffortMinutes: SonarqubeEffortMinutes,
|
||||
Cwe: issue.Cwe,
|
||||
}
|
||||
si.SonarIssues = append(si.SonarIssues, s)
|
||||
}
|
||||
|
@ -190,6 +193,7 @@ func reportCSV(w io.Writer, data *reportInfo) error {
|
|||
issue.Severity.String(),
|
||||
issue.Confidence.String(),
|
||||
issue.Code,
|
||||
fmt.Sprintf("CWE-%s", issue.Cwe.ID),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -1,12 +1,48 @@
|
|||
package output
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
"github.com/securego/gosec"
|
||||
"gopkg.in/yaml.v2"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func createIssue(ruleID string, cwe gosec.Cwe) gosec.Issue {
|
||||
return gosec.Issue{
|
||||
File: "/home/src/project/test.go",
|
||||
Line: "1",
|
||||
RuleID: ruleID,
|
||||
What: "test",
|
||||
Confidence: gosec.High,
|
||||
Severity: gosec.High,
|
||||
Code: "testcode",
|
||||
Cwe: cwe,
|
||||
}
|
||||
}
|
||||
|
||||
func createReportInfo(rule string, cwe gosec.Cwe) reportInfo {
|
||||
issue := createIssue(rule, cwe)
|
||||
metrics := gosec.Metrics{}
|
||||
return reportInfo{
|
||||
Errors: map[string][]gosec.Error{},
|
||||
Issues: []*gosec.Issue{
|
||||
&issue,
|
||||
},
|
||||
Stats: &metrics,
|
||||
}
|
||||
}
|
||||
|
||||
func stripString(str string) string {
|
||||
ret := strings.Replace(str, "\n", "", -1)
|
||||
ret = strings.Replace(ret, " ", "", -1)
|
||||
ret = strings.Replace(ret, "\t", "", -1)
|
||||
return ret
|
||||
}
|
||||
|
||||
var _ = Describe("Formatter", func() {
|
||||
BeforeEach(func() {
|
||||
})
|
||||
|
@ -210,4 +246,150 @@ var _ = Describe("Formatter", func() {
|
|||
Expect(*issues).To(Equal(*want))
|
||||
})
|
||||
})
|
||||
Context("When using different report formats", func() {
|
||||
|
||||
grules := []string{"G101", "G102", "G103", "G104", "G106",
|
||||
"G107", "G201", "G202", "G203", "G204", "G301",
|
||||
"G302", "G303", "G304", "G305", "G401", "G402",
|
||||
"G403", "G404", "G501", "G502", "G503", "G504", "G505"}
|
||||
|
||||
It("csv formatted report should contain the CWE mapping", func() {
|
||||
for _, rule := range grules {
|
||||
cwe := gosec.IssueToCWE[rule]
|
||||
issue := createIssue(rule, cwe)
|
||||
error := map[string][]gosec.Error{}
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
CreateReport(buf, "csv", []string{}, []*gosec.Issue{&issue}, &gosec.Metrics{}, error)
|
||||
pattern := "/home/src/project/test.go,1,test,HIGH,HIGH,testcode,CWE-%s\n"
|
||||
expect := fmt.Sprintf(pattern, cwe.ID)
|
||||
Expect(string(buf.Bytes())).To(Equal(expect))
|
||||
}
|
||||
})
|
||||
It("xml formatted report should contain the CWE mapping", func() {
|
||||
for _, rule := range grules {
|
||||
cwe := gosec.IssueToCWE[rule]
|
||||
issue := createIssue(rule, cwe)
|
||||
error := map[string][]gosec.Error{}
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
CreateReport(buf, "xml", []string{}, []*gosec.Issue{&issue}, &gosec.Metrics{NumFiles: 0, NumLines: 0, NumNosec: 0, NumFound: 0}, error)
|
||||
pattern := "Results:\n\n\n[/home/src/project/test.go:1] - %s (CWE-%s): test (Confidence: HIGH, Severity: HIGH)\n > testcode\n\n\nSummary:\n Files: 0\n Lines: 0\n Nosec: 0\n Issues: 0\n\n"
|
||||
expect := fmt.Sprintf(pattern, rule, cwe.ID)
|
||||
Expect(string(buf.Bytes())).To(Equal(expect))
|
||||
}
|
||||
})
|
||||
It("json formatted report should contain the CWE mapping", func() {
|
||||
for _, rule := range grules {
|
||||
cwe := gosec.IssueToCWE[rule]
|
||||
issue := createIssue(rule, cwe)
|
||||
error := map[string][]gosec.Error{}
|
||||
|
||||
data := createReportInfo(rule, cwe)
|
||||
|
||||
expect := new(bytes.Buffer)
|
||||
enc := json.NewEncoder(expect)
|
||||
enc.Encode(data)
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
CreateReport(buf, "json", []string{}, []*gosec.Issue{&issue}, &gosec.Metrics{}, error)
|
||||
result := stripString(buf.String())
|
||||
expectation := stripString(expect.String())
|
||||
Expect(result).To(Equal(expectation))
|
||||
}
|
||||
})
|
||||
It("html formatted report should contain the CWE mapping", func() {
|
||||
for _, rule := range grules {
|
||||
cwe := gosec.IssueToCWE[rule]
|
||||
issue := createIssue(rule, cwe)
|
||||
error := map[string][]gosec.Error{}
|
||||
|
||||
data := createReportInfo(rule, cwe)
|
||||
|
||||
expect := new(bytes.Buffer)
|
||||
enc := json.NewEncoder(expect)
|
||||
enc.Encode(data)
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
CreateReport(buf, "html", []string{}, []*gosec.Issue{&issue}, &gosec.Metrics{}, error)
|
||||
result := stripString(buf.String())
|
||||
expectation := stripString(expect.String())
|
||||
Expect(result).To(ContainSubstring(expectation))
|
||||
}
|
||||
})
|
||||
It("yaml formatted report should contain the CWE mapping", func() {
|
||||
for _, rule := range grules {
|
||||
cwe := gosec.IssueToCWE[rule]
|
||||
issue := createIssue(rule, cwe)
|
||||
error := map[string][]gosec.Error{}
|
||||
|
||||
data := createReportInfo(rule, cwe)
|
||||
|
||||
expect := new(bytes.Buffer)
|
||||
enc := yaml.NewEncoder(expect)
|
||||
enc.Encode(data)
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
CreateReport(buf, "yaml", []string{}, []*gosec.Issue{&issue}, &gosec.Metrics{}, error)
|
||||
result := stripString(buf.String())
|
||||
expectation := stripString(expect.String())
|
||||
Expect(result).To(ContainSubstring(expectation))
|
||||
}
|
||||
})
|
||||
It("junit-xml formatted report should contain the CWE mapping", func() {
|
||||
for _, rule := range grules {
|
||||
cwe := gosec.IssueToCWE[rule]
|
||||
issue := createIssue(rule, cwe)
|
||||
error := map[string][]gosec.Error{}
|
||||
|
||||
data := createReportInfo(rule, cwe)
|
||||
|
||||
expect := new(bytes.Buffer)
|
||||
enc := yaml.NewEncoder(expect)
|
||||
enc.Encode(data)
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
CreateReport(buf, "junit-xml", []string{}, []*gosec.Issue{&issue}, &gosec.Metrics{}, error)
|
||||
expectation := stripString(fmt.Sprintf("[/home/src/project/test.go:1] - test (Confidence: 2, Severity: 2, CWE: %s)", cwe.ID))
|
||||
result := stripString(buf.String())
|
||||
Expect(result).To(ContainSubstring(expectation))
|
||||
}
|
||||
})
|
||||
It("text formatted report should contain the CWE mapping", func() {
|
||||
for _, rule := range grules {
|
||||
cwe := gosec.IssueToCWE[rule]
|
||||
issue := createIssue(rule, cwe)
|
||||
error := map[string][]gosec.Error{}
|
||||
|
||||
data := createReportInfo(rule, cwe)
|
||||
|
||||
expect := new(bytes.Buffer)
|
||||
enc := yaml.NewEncoder(expect)
|
||||
enc.Encode(data)
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
CreateReport(buf, "text", []string{}, []*gosec.Issue{&issue}, &gosec.Metrics{}, error)
|
||||
expectation := stripString(fmt.Sprintf("[/home/src/project/test.go:1] - %s (CWE-%s): test (Confidence: HIGH, Severity: HIGH)", rule, cwe.ID))
|
||||
result := stripString(buf.String())
|
||||
Expect(result).To(ContainSubstring(expectation))
|
||||
}
|
||||
})
|
||||
It("sonarqube formatted report should contain the CWE mapping", func() {
|
||||
for _, rule := range grules {
|
||||
cwe := gosec.IssueToCWE[rule]
|
||||
issue := createIssue(rule, cwe)
|
||||
error := map[string][]gosec.Error{}
|
||||
buf := new(bytes.Buffer)
|
||||
CreateReport(buf, "sonarqube", []string{"/home/src/project"}, []*gosec.Issue{&issue}, &gosec.Metrics{}, error)
|
||||
result := stripString(buf.String())
|
||||
|
||||
expect := new(bytes.Buffer)
|
||||
enc := json.NewEncoder(expect)
|
||||
enc.Encode(cwe)
|
||||
|
||||
expectation := stripString(expect.String())
|
||||
Expect(result).To(ContainSubstring(expectation))
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -36,7 +36,8 @@ func generatePlaintext(issue *gosec.Issue) string {
|
|||
return "Results:\n" +
|
||||
"[" + issue.File + ":" + issue.Line + "] - " +
|
||||
issue.What + " (Confidence: " + strconv.Itoa(int(issue.Confidence)) +
|
||||
", Severity: " + strconv.Itoa(int(issue.Severity)) + ")\n" + "> " + htmlLib.EscapeString(issue.Code)
|
||||
", Severity: " + strconv.Itoa(int(issue.Severity)) +
|
||||
", CWE: " + issue.Cwe.ID + ")\n" + "> " + htmlLib.EscapeString(issue.Code)
|
||||
}
|
||||
|
||||
func groupDataByRules(data *reportInfo) map[string][]*gosec.Issue {
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package output
|
||||
|
||||
import "github.com/securego/gosec"
|
||||
|
||||
type textRange struct {
|
||||
StartLine int `json:"startLine"`
|
||||
EndLine int `json:"endLine"`
|
||||
|
@ -15,6 +17,7 @@ type location struct {
|
|||
type sonarIssue struct {
|
||||
EngineID string `json:"engineId"`
|
||||
RuleID string `json:"ruleId"`
|
||||
Cwe gosec.Cwe `json:"cwe"`
|
||||
PrimaryLocation location `json:"primaryLocation"`
|
||||
Type string `json:"type"`
|
||||
Severity string `json:"severity"`
|
||||
|
|
Loading…
Reference in a new issue