Add golint format to output format (#428)

Signed-off-by: Hiroki Suezawa <suezawa@gmail.com>
This commit is contained in:
Hiroki Suezawa 2020-01-03 18:56:21 +09:00 committed by Cosmin Cojocar
parent 57c3788fe5
commit 79fbf3af8d
6 changed files with 54 additions and 2 deletions

View file

@ -210,7 +210,7 @@ gosec -tag debug,ignore ./...
### Output formats ### Output formats
gosec currently supports text, json, yaml, csv, sonarqube and JUnit XML output formats. By default gosec currently supports text, json, yaml, csv, sonarqube, JUnit XML and golint output formats. By default
results will be reported to stdout, but can also be written to an output results will be reported to stdout, but can also be written to an output
file. The output format is controlled by the '-fmt' flag, and the output file is controlled by the '-out' flag as follows: file. The output format is controlled by the '-fmt' flag, and the output file is controlled by the '-out' flag as follows:

View file

@ -73,7 +73,7 @@ var (
flagIgnoreNoSec = flag.Bool("nosec", false, "Ignores #nosec comments when set") flagIgnoreNoSec = flag.Bool("nosec", false, "Ignores #nosec comments when set")
// format output // format output
flagFormat = flag.String("fmt", "text", "Set output format. Valid options are: json, yaml, csv, junit-xml, html, sonarqube, or text") flagFormat = flag.String("fmt", "text", "Set output format. Valid options are: json, yaml, csv, junit-xml, html, sonarqube, golint or text")
// #nosec alternative tag // #nosec alternative tag
flagAlternativeNoSec = flag.String("nosec-tag", "", "Set an alternative string for #nosec. Some examples: #dontanalyze, #falsepositive") flagAlternativeNoSec = flag.String("nosec-tag", "", "Set an alternative string for #nosec. Some examples: #dontanalyze, #falsepositive")

View file

@ -83,6 +83,7 @@ type Issue struct {
File string `json:"file"` // File name we found it in File string `json:"file"` // File name we found it in
Code string `json:"code"` // Impacted code line Code string `json:"code"` // Impacted code line
Line string `json:"line"` // Line number in file Line string `json:"line"` // Line number in file
Col string `json:"column"` // Column number in line
} }
// MetaData is embedded in all gosec rules. The Severity, Confidence and What message // MetaData is embedded in all gosec rules. The Severity, Confidence and What message
@ -142,6 +143,8 @@ func NewIssue(ctx *Context, node ast.Node, ruleID, desc string, severity Score,
line = fmt.Sprintf("%d-%d", start, end) line = fmt.Sprintf("%d-%d", start, end)
} }
col := strconv.Itoa(fobj.Position(node.Pos()).Column)
// #nosec // #nosec
if file, err := os.Open(fobj.Name()); err == nil { if file, err := os.Open(fobj.Name()); err == nil {
defer file.Close() defer file.Close()
@ -156,6 +159,7 @@ func NewIssue(ctx *Context, node ast.Node, ruleID, desc string, severity Score,
return &Issue{ return &Issue{
File: name, File: name,
Line: line, Line: line,
Col: col,
RuleID: ruleID, RuleID: ruleID,
What: desc, What: desc,
Confidence: confidence, Confidence: confidence,

View file

@ -41,6 +41,7 @@ var _ = Describe("Issue", func() {
Expect(issue).ShouldNot(BeNil()) Expect(issue).ShouldNot(BeNil())
Expect(issue.Code).Should(MatchRegexp(`"bar"`)) Expect(issue.Code).Should(MatchRegexp(`"bar"`))
Expect(issue.Line).Should(Equal("2")) Expect(issue.Line).Should(Equal("2"))
Expect(issue.Col).Should(Equal("16"))
Expect(issue.Cwe.ID).Should(Equal("")) Expect(issue.Cwe.ID).Should(Equal(""))
}) })
@ -84,6 +85,7 @@ var _ = Describe("Issue", func() {
Expect(issue).ShouldNot(BeNil()) Expect(issue).ShouldNot(BeNil())
Expect(issue.File).Should(MatchRegexp("foo.go")) Expect(issue.File).Should(MatchRegexp("foo.go"))
Expect(issue.Line).Should(MatchRegexp("3-4")) Expect(issue.Line).Should(MatchRegexp("3-4"))
Expect(issue.Col).Should(Equal("21"))
}) })
It("should maintain the provided severity score", func() { It("should maintain the provided severity score", func() {

View file

@ -99,6 +99,8 @@ func CreateReport(w io.Writer, format string, rootPaths []string, issues []*gose
err = reportFromPlaintextTemplate(w, text, data) err = reportFromPlaintextTemplate(w, text, data)
case "sonarqube": case "sonarqube":
err = reportSonarqube(rootPaths, w, data) err = reportSonarqube(rootPaths, w, data)
case "golint":
err = reportGolint(w, data)
default: default:
err = reportFromPlaintextTemplate(w, text, data) err = reportFromPlaintextTemplate(w, text, data)
} }
@ -202,6 +204,36 @@ func reportCSV(w io.Writer, data *reportInfo) error {
return nil return nil
} }
func reportGolint(w io.Writer, data *reportInfo) error {
// Output Sample:
// /tmp/main.go:11:14: [CWE-310] RSA keys should be at least 2048 bits (Rule:G403, Severity:MEDIUM, Confidence:HIGH)
for _, issue := range data.Issues {
what := issue.What
if issue.Cwe.ID != "" {
what = fmt.Sprintf("[CWE-%s] %s", issue.Cwe.ID, issue.What)
}
// issue.Line uses "start-end" format for multiple line detection.
lines := strings.Split(issue.Line, "-")
start := lines[0]
_, err := fmt.Fprintf(w, "%s:%s:%s: %s (Rule:%s, Severity:%s, Confidence:%s)\n",
issue.File,
start,
issue.Col,
what,
issue.RuleID,
issue.Severity.String(),
issue.Confidence.String(),
)
if err != nil {
return err
}
}
return nil
}
func reportJUnitXML(w io.Writer, data *reportInfo) error { func reportJUnitXML(w io.Writer, data *reportInfo) error {
groupedData := groupDataByRules(data) groupedData := groupDataByRules(data)
junitXMLStruct := createJUnitXMLStruct(groupedData) junitXMLStruct := createJUnitXMLStruct(groupedData)

View file

@ -15,6 +15,7 @@ func createIssue(ruleID string, cwe gosec.Cwe) gosec.Issue {
return gosec.Issue{ return gosec.Issue{
File: "/home/src/project/test.go", File: "/home/src/project/test.go",
Line: "1", Line: "1",
Col: "1",
RuleID: ruleID, RuleID: ruleID,
What: "test", What: "test",
Confidence: gosec.High, Confidence: gosec.High,
@ -391,5 +392,18 @@ var _ = Describe("Formatter", func() {
Expect(result).To(ContainSubstring(expectation)) Expect(result).To(ContainSubstring(expectation))
} }
}) })
It("golint 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, "golint", []string{}, []*gosec.Issue{&issue}, &gosec.Metrics{}, error)
pattern := "/home/src/project/test.go:1:1: [CWE-%s] test (Rule:%s, Severity:HIGH, Confidence:HIGH)\n"
expect := fmt.Sprintf(pattern, cwe.ID, rule)
Expect(string(buf.Bytes())).To(Equal(expect))
}
})
}) })
}) })