Handle gosec version in SARIF report

This commit is contained in:
Matthieu MOREL 2021-05-20 10:16:42 +02:00 committed by GitHub
parent 51f7411573
commit d040f0725f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 151 additions and 96 deletions

View file

@ -216,23 +216,23 @@ func getPrintedFormat(format string, verbose string) string {
return fileFormat return fileFormat
} }
func printReport(format string, color bool, rootPaths []string, issues []*gosec.Issue, metrics *gosec.Metrics, errors map[string][]gosec.Error) error { func printReport(format string, color bool, rootPaths []string, reportInfo *gosec.ReportInfo) error {
err := report.CreateReport(os.Stdout, format, color, rootPaths, issues, metrics, errors) err := report.CreateReport(os.Stdout, format, color, rootPaths, reportInfo)
if err != nil { if err != nil {
return err return err
} }
return nil return nil
} }
func saveReport(filename, format string, rootPaths []string, issues []*gosec.Issue, metrics *gosec.Metrics, errors map[string][]gosec.Error) error { func saveReport(filename, format string, rootPaths []string, reportInfo *gosec.ReportInfo) error {
outfile, err := os.Create(filename) outfile, err := os.Create(filename)
if err != nil { if err != nil {
return err return err
} }
defer outfile.Close() // #nosec G307 defer outfile.Close() // #nosec G307
err = report.CreateReport(outfile, format, false, rootPaths, issues, metrics, errors) err = report.CreateReport(outfile, format, false, rootPaths, reportInfo)
if err != nil { if err != nil {
return err return err
} }
@ -383,14 +383,16 @@ func main() {
// Create output report // Create output report
rootPaths := getRootPaths(flag.Args()) rootPaths := getRootPaths(flag.Args())
reportInfo := gosec.NewReportInfo(issues, metrics, errors).WithVersion(Version)
if *flagOutput == "" || *flagStdOut { if *flagOutput == "" || *flagStdOut {
var fileFormat = getPrintedFormat(*flagOutput, *flagVerbose) var fileFormat = getPrintedFormat(*flagOutput, *flagVerbose)
if err := printReport(fileFormat, *flagColor, rootPaths, issues, metrics, errors); err != nil { if err := printReport(fileFormat, *flagColor, rootPaths, reportInfo); err != nil {
logger.Fatal((err)) logger.Fatal((err))
} }
} }
if *flagOutput != "" { if *flagOutput != "" {
if err := saveReport(*flagOutput, *flagFormat, rootPaths, issues, metrics, errors); err != nil { if err := saveReport(*flagOutput, *flagFormat, rootPaths, reportInfo); err != nil {
logger.Fatal(err) logger.Fatal(err)
} }
} }

3
go.mod
View file

@ -3,13 +3,14 @@ module github.com/securego/gosec/v2
require ( require (
github.com/google/uuid v1.1.1 github.com/google/uuid v1.1.1
github.com/gookit/color v1.4.2 github.com/gookit/color v1.4.2
github.com/lib/pq v1.9.0
github.com/mozilla/tls-observatory v0.0.0-20210209181001-cf43108d6880 github.com/mozilla/tls-observatory v0.0.0-20210209181001-cf43108d6880
github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354 github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354
github.com/onsi/ginkgo v1.16.1 github.com/onsi/ginkgo v1.16.1
github.com/onsi/gomega v1.11.0 github.com/onsi/gomega v1.11.0
golang.org/x/mod v0.4.1 // indirect golang.org/x/mod v0.4.1 // indirect
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 // indirect golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 // indirect
golang.org/x/text v0.3.5 // indirect golang.org/x/text v0.3.5
golang.org/x/tools v0.1.0 golang.org/x/tools v0.1.0
gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v2 v2.4.0
) )

View file

@ -1,7 +1,7 @@
{ {
"extends": [ "extends": [
"config:semverAllMonthly", "config:semverAllMonthly",
":enableVulnerabilityAlertsWithLabel(vulnerablity)", ":enableVulnerabilityAlertsWithLabel(vulnerablity)",
":docker" ":docker"
] ]
} }

24
report.go Normal file
View file

@ -0,0 +1,24 @@
package gosec
// ReportInfo this is report information
type ReportInfo struct {
Errors map[string][]Error `json:"Golang errors"`
Issues []*Issue
Stats *Metrics
GosecVersion string
}
// NewReportInfo instantiate a ReportInfo
func NewReportInfo(issues []*Issue, metrics *Metrics, errors map[string][]Error) *ReportInfo {
return &ReportInfo{
Errors: errors,
Issues: issues,
Stats: metrics,
}
}
// WithVersion defines the version of gosec used to generate the report
func (r *ReportInfo) WithVersion(version string) *ReportInfo {
r.GosecVersion = version
return r
}

View file

@ -1,12 +0,0 @@
package core
import (
"github.com/securego/gosec/v2"
)
//ReportInfo this is report information
type ReportInfo struct {
Errors map[string][]gosec.Error `json:"Golang errors"`
Issues []*gosec.Issue
Stats *gosec.Metrics
}

View file

@ -2,12 +2,13 @@ package csv
import ( import (
"encoding/csv" "encoding/csv"
"github.com/securego/gosec/v2/report/core"
"io" "io"
"github.com/securego/gosec/v2"
) )
//WriteReport write a report in csv format to the output writer //WriteReport write a report in csv format to the output writer
func WriteReport(w io.Writer, data *core.ReportInfo) error { func WriteReport(w io.Writer, data *gosec.ReportInfo) error {
out := csv.NewWriter(w) out := csv.NewWriter(w)
defer out.Flush() defer out.Flush()
for _, issue := range data.Issues { for _, issue := range data.Issues {

View file

@ -15,8 +15,9 @@
package report package report
import ( import (
"io"
"github.com/securego/gosec/v2" "github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/report/core"
"github.com/securego/gosec/v2/report/csv" "github.com/securego/gosec/v2/report/csv"
"github.com/securego/gosec/v2/report/golint" "github.com/securego/gosec/v2/report/golint"
"github.com/securego/gosec/v2/report/html" "github.com/securego/gosec/v2/report/html"
@ -26,7 +27,6 @@ import (
"github.com/securego/gosec/v2/report/sonar" "github.com/securego/gosec/v2/report/sonar"
"github.com/securego/gosec/v2/report/text" "github.com/securego/gosec/v2/report/text"
"github.com/securego/gosec/v2/report/yaml" "github.com/securego/gosec/v2/report/yaml"
"io"
) )
// Format enumerates the output format for reported issues // Format enumerates the output format for reported issues
@ -51,12 +51,7 @@ const (
// CreateReport generates a report based for the supplied issues and metrics given // CreateReport generates a report based for the supplied issues and metrics given
// the specified format. The formats currently accepted are: json, yaml, csv, junit-xml, html, sonarqube, golint and text. // the specified format. The formats currently accepted are: json, yaml, csv, junit-xml, html, sonarqube, golint and text.
func CreateReport(w io.Writer, format string, enableColor bool, rootPaths []string, issues []*gosec.Issue, metrics *gosec.Metrics, errors map[string][]gosec.Error) error { func CreateReport(w io.Writer, format string, enableColor bool, rootPaths []string, data *gosec.ReportInfo) error {
data := &core.ReportInfo{
Errors: errors,
Issues: issues,
Stats: metrics,
}
var err error var err error
switch format { switch format {
case "json": case "json":

View file

@ -10,7 +10,6 @@ import (
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"github.com/securego/gosec/v2" "github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/cwe" "github.com/securego/gosec/v2/cwe"
"github.com/securego/gosec/v2/report/core"
"github.com/securego/gosec/v2/report/junit" "github.com/securego/gosec/v2/report/junit"
"github.com/securego/gosec/v2/report/sonar" "github.com/securego/gosec/v2/report/sonar"
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
@ -37,10 +36,10 @@ func createIssue(ruleID string, weakness *cwe.Weakness) gosec.Issue {
} }
} }
func createReportInfo(rule string, weakness *cwe.Weakness) core.ReportInfo { func createReportInfo(rule string, weakness *cwe.Weakness) gosec.ReportInfo {
issue := createIssue(rule, weakness) issue := createIssue(rule, weakness)
metrics := gosec.Metrics{} metrics := gosec.Metrics{}
return core.ReportInfo{ return gosec.ReportInfo{
Errors: map[string][]gosec.Error{}, Errors: map[string][]gosec.Error{},
Issues: []*gosec.Issue{ Issues: []*gosec.Issue{
&issue, &issue,
@ -61,7 +60,7 @@ var _ = Describe("Formatter", func() {
}) })
Context("when converting to Sonarqube issues", func() { Context("when converting to Sonarqube issues", func() {
It("it should parse the report info", func() { It("it should parse the report info", func() {
data := &core.ReportInfo{ data := &gosec.ReportInfo{
Errors: map[string][]gosec.Error{}, Errors: map[string][]gosec.Error{},
Issues: []*gosec.Issue{ Issues: []*gosec.Issue{
{ {
@ -109,7 +108,7 @@ var _ = Describe("Formatter", func() {
}) })
It("it should parse the report info with files in subfolders", func() { It("it should parse the report info with files in subfolders", func() {
data := &core.ReportInfo{ data := &gosec.ReportInfo{
Errors: map[string][]gosec.Error{}, Errors: map[string][]gosec.Error{},
Issues: []*gosec.Issue{ Issues: []*gosec.Issue{
{ {
@ -156,7 +155,7 @@ var _ = Describe("Formatter", func() {
Expect(*issues).To(Equal(*want)) Expect(*issues).To(Equal(*want))
}) })
It("it should not parse the report info for files from other projects", func() { It("it should not parse the report info for files from other projects", func() {
data := &core.ReportInfo{ data := &gosec.ReportInfo{
Errors: map[string][]gosec.Error{}, Errors: map[string][]gosec.Error{},
Issues: []*gosec.Issue{ Issues: []*gosec.Issue{
{ {
@ -188,7 +187,7 @@ var _ = Describe("Formatter", func() {
}) })
It("it should parse the report info for multiple projects projects", func() { It("it should parse the report info for multiple projects projects", func() {
data := &core.ReportInfo{ data := &gosec.ReportInfo{
Errors: map[string][]gosec.Error{}, Errors: map[string][]gosec.Error{},
Issues: []*gosec.Issue{ Issues: []*gosec.Issue{
{ {
@ -264,7 +263,7 @@ var _ = Describe("Formatter", func() {
It("preserves order of issues", func() { It("preserves order of issues", func() {
issues := []*gosec.Issue{createIssueWithFileWhat("i1", "1"), createIssueWithFileWhat("i2", "2"), createIssueWithFileWhat("i3", "1")} issues := []*gosec.Issue{createIssueWithFileWhat("i1", "1"), createIssueWithFileWhat("i2", "2"), createIssueWithFileWhat("i3", "1")}
junitReport := junit.GenerateReport(&core.ReportInfo{Issues: issues}) junitReport := junit.GenerateReport(&gosec.ReportInfo{Issues: issues})
testSuite := junitReport.Testsuites[0] testSuite := junitReport.Testsuites[0]
@ -290,7 +289,8 @@ var _ = Describe("Formatter", func() {
error := map[string][]gosec.Error{} error := map[string][]gosec.Error{}
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
err := CreateReport(buf, "csv", false, []string{}, []*gosec.Issue{&issue}, &gosec.Metrics{}, error) reportInfo := gosec.NewReportInfo([]*gosec.Issue{&issue}, &gosec.Metrics{}, error)
err := CreateReport(buf, "csv", false, []string{}, reportInfo)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
pattern := "/home/src/project/test.go,1,test,HIGH,HIGH,1: testcode,CWE-%s\n" pattern := "/home/src/project/test.go,1,test,HIGH,HIGH,1: testcode,CWE-%s\n"
expect := fmt.Sprintf(pattern, cwe.ID) expect := fmt.Sprintf(pattern, cwe.ID)
@ -304,7 +304,8 @@ var _ = Describe("Formatter", func() {
error := map[string][]gosec.Error{} error := map[string][]gosec.Error{}
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
err := CreateReport(buf, "xml", false, []string{}, []*gosec.Issue{&issue}, &gosec.Metrics{NumFiles: 0, NumLines: 0, NumNosec: 0, NumFound: 0}, error) reportInfo := gosec.NewReportInfo([]*gosec.Issue{&issue}, &gosec.Metrics{NumFiles: 0, NumLines: 0, NumNosec: 0, NumFound: 0}, error)
err := CreateReport(buf, "xml", false, []string{}, reportInfo)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
pattern := "Results:\n\n\n[/home/src/project/test.go:1] - %s (CWE-%s): test (Confidence: HIGH, Severity: HIGH)\n > 1: testcode\n\n\n\nSummary:\n Files: 0\n Lines: 0\n Nosec: 0\n Issues: 0\n\n" pattern := "Results:\n\n\n[/home/src/project/test.go:1] - %s (CWE-%s): test (Confidence: HIGH, Severity: HIGH)\n > 1: testcode\n\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 := fmt.Sprintf(pattern, rule, cwe.ID)
@ -324,7 +325,8 @@ var _ = Describe("Formatter", func() {
err := enc.Encode(data) err := enc.Encode(data)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
err = CreateReport(buf, "json", false, []string{}, []*gosec.Issue{&issue}, &gosec.Metrics{}, error) reportInfo := gosec.NewReportInfo([]*gosec.Issue{&issue}, &gosec.Metrics{}, error)
err = CreateReport(buf, "json", false, []string{}, reportInfo)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
result := stripString(buf.String()) result := stripString(buf.String())
expectation := stripString(expect.String()) expectation := stripString(expect.String())
@ -344,7 +346,8 @@ var _ = Describe("Formatter", func() {
err := enc.Encode(data) err := enc.Encode(data)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
err = CreateReport(buf, "html", false, []string{}, []*gosec.Issue{&issue}, &gosec.Metrics{}, error) reportInfo := gosec.NewReportInfo([]*gosec.Issue{&issue}, &gosec.Metrics{}, error)
err = CreateReport(buf, "html", false, []string{}, reportInfo)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
result := stripString(buf.String()) result := stripString(buf.String())
expectation := stripString(expect.String()) expectation := stripString(expect.String())
@ -364,7 +367,8 @@ var _ = Describe("Formatter", func() {
err := enc.Encode(data) err := enc.Encode(data)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
err = CreateReport(buf, "yaml", false, []string{}, []*gosec.Issue{&issue}, &gosec.Metrics{}, error) reportInfo := gosec.NewReportInfo([]*gosec.Issue{&issue}, &gosec.Metrics{}, error)
err = CreateReport(buf, "yaml", false, []string{}, reportInfo)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
result := stripString(buf.String()) result := stripString(buf.String())
expectation := stripString(expect.String()) expectation := stripString(expect.String())
@ -384,7 +388,8 @@ var _ = Describe("Formatter", func() {
err := enc.Encode(data) err := enc.Encode(data)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
err = CreateReport(buf, "junit-xml", false, []string{}, []*gosec.Issue{&issue}, &gosec.Metrics{}, error) reportInfo := gosec.NewReportInfo([]*gosec.Issue{&issue}, &gosec.Metrics{}, error)
err = CreateReport(buf, "junit-xml", false, []string{}, reportInfo)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
expectation := stripString(fmt.Sprintf("[/home/src/project/test.go:1] - test (Confidence: 2, Severity: 2, CWE: %s)", cwe.ID)) expectation := stripString(fmt.Sprintf("[/home/src/project/test.go:1] - test (Confidence: 2, Severity: 2, CWE: %s)", cwe.ID))
result := stripString(buf.String()) result := stripString(buf.String())
@ -404,7 +409,8 @@ var _ = Describe("Formatter", func() {
err := enc.Encode(data) err := enc.Encode(data)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
err = CreateReport(buf, "text", false, []string{}, []*gosec.Issue{&issue}, &gosec.Metrics{}, error) reportInfo := gosec.NewReportInfo([]*gosec.Issue{&issue}, &gosec.Metrics{}, error)
err = CreateReport(buf, "text", false, []string{}, reportInfo)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
expectation := stripString(fmt.Sprintf("[/home/src/project/test.go:1] - %s (CWE-%s): test (Confidence: HIGH, Severity: HIGH)", rule, cwe.ID)) 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()) result := stripString(buf.String())
@ -417,7 +423,8 @@ var _ = Describe("Formatter", func() {
issue := createIssue(rule, cwe) issue := createIssue(rule, cwe)
error := map[string][]gosec.Error{} error := map[string][]gosec.Error{}
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
err := CreateReport(buf, "sonarqube", false, []string{"/home/src/project"}, []*gosec.Issue{&issue}, &gosec.Metrics{}, error) reportInfo := gosec.NewReportInfo([]*gosec.Issue{&issue}, &gosec.Metrics{}, error)
err := CreateReport(buf, "sonarqube", false, []string{"/home/src/project"}, reportInfo)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
result := stripString(buf.String()) result := stripString(buf.String())
@ -438,7 +445,8 @@ var _ = Describe("Formatter", func() {
error := map[string][]gosec.Error{} error := map[string][]gosec.Error{}
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
err := CreateReport(buf, "golint", false, []string{}, []*gosec.Issue{&issue}, &gosec.Metrics{}, error) reportInfo := gosec.NewReportInfo([]*gosec.Issue{&issue}, &gosec.Metrics{}, error)
err := CreateReport(buf, "golint", false, []string{}, reportInfo)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
pattern := "/home/src/project/test.go:1:1: [CWE-%s] test (Rule:%s, Severity:HIGH, Confidence:HIGH)\n" 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 := fmt.Sprintf(pattern, cwe.ID, rule)
@ -452,7 +460,8 @@ var _ = Describe("Formatter", func() {
error := map[string][]gosec.Error{} error := map[string][]gosec.Error{}
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
err := CreateReport(buf, "sarif", false, []string{}, []*gosec.Issue{&issue}, &gosec.Metrics{}, error) reportInfo := gosec.NewReportInfo([]*gosec.Issue{&issue}, &gosec.Metrics{}, error).WithVersion("v2.7.0")
err := CreateReport(buf, "sarif", false, []string{}, reportInfo)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
result := stripString(buf.String()) result := stripString(buf.String())

View file

@ -2,13 +2,14 @@ package golint
import ( import (
"fmt" "fmt"
"github.com/securego/gosec/v2/report/core"
"io" "io"
"strings" "strings"
"github.com/securego/gosec/v2"
) )
//WriteReport write a report in golint format to the output writer //WriteReport write a report in golint format to the output writer
func WriteReport(w io.Writer, data *core.ReportInfo) error { func WriteReport(w io.Writer, data *gosec.ReportInfo) error {
// Output Sample: // Output Sample:
// /tmp/main.go:11:14: [CWE-310] RSA keys should be at least 2048 bits (Rule:G403, Severity:MEDIUM, Confidence:HIGH) // /tmp/main.go:11:14: [CWE-310] RSA keys should be at least 2048 bits (Rule:G403, Severity:MEDIUM, Confidence:HIGH)

View file

@ -1,13 +1,14 @@
package html package html
import ( import (
"github.com/securego/gosec/v2/report/core"
"html/template" "html/template"
"io" "io"
"github.com/securego/gosec/v2"
) )
//WriteReport write a report in html format to the output writer //WriteReport write a report in html format to the output writer
func WriteReport(w io.Writer, data *core.ReportInfo) error { func WriteReport(w io.Writer, data *gosec.ReportInfo) error {
t, e := template.New("gosec").Parse(templateContent) t, e := template.New("gosec").Parse(templateContent)
if e != nil { if e != nil {
return e return e

View file

@ -2,12 +2,13 @@ package json
import ( import (
"encoding/json" "encoding/json"
"github.com/securego/gosec/v2/report/core"
"io" "io"
"github.com/securego/gosec/v2"
) )
//WriteReport write a report in json format to the output writer //WriteReport write a report in json format to the output writer
func WriteReport(w io.Writer, data *core.ReportInfo) error { func WriteReport(w io.Writer, data *gosec.ReportInfo) error {
raw, err := json.MarshalIndent(data, "", "\t") raw, err := json.MarshalIndent(data, "", "\t")
if err != nil { if err != nil {
return err return err

View file

@ -5,7 +5,6 @@ import (
"strconv" "strconv"
"github.com/securego/gosec/v2" "github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/report/core"
) )
func generatePlaintext(issue *gosec.Issue) string { func generatePlaintext(issue *gosec.Issue) string {
@ -17,7 +16,7 @@ func generatePlaintext(issue *gosec.Issue) string {
} }
//GenerateReport Convert a gosec report to a JUnit Report //GenerateReport Convert a gosec report to a JUnit Report
func GenerateReport(data *core.ReportInfo) Report { func GenerateReport(data *gosec.ReportInfo) Report {
var xmlReport Report var xmlReport Report
testsuites := map[string]int{} testsuites := map[string]int{}

View file

@ -2,12 +2,13 @@ package junit
import ( import (
"encoding/xml" "encoding/xml"
"github.com/securego/gosec/v2/report/core"
"io" "io"
"github.com/securego/gosec/v2"
) )
//WriteReport write a report in JUnit format to the output writer //WriteReport write a report in JUnit format to the output writer
func WriteReport(w io.Writer, data *core.ReportInfo) error { func WriteReport(w io.Writer, data *gosec.ReportInfo) error {
junitXMLStruct := GenerateReport(data) junitXMLStruct := GenerateReport(data)
raw, err := xml.MarshalIndent(junitXMLStruct, "", "\t") raw, err := xml.MarshalIndent(junitXMLStruct, "", "\t")
if err != nil { if err != nil {

View file

@ -126,6 +126,18 @@ func NewToolComponent(name string, version string, informationURI string) *ToolC
} }
} }
//WithLanguage set Language for the current ToolComponent
func (t *ToolComponent) WithLanguage(language string) *ToolComponent {
t.Language = language
return t
}
//WithSemanticVersion set SemanticVersion for the current ToolComponent
func (t *ToolComponent) WithSemanticVersion(semanticVersion string) *ToolComponent {
t.SemanticVersion = semanticVersion
return t
}
//WithReleaseDateUtc set releaseDateUtc for the current ToolComponent //WithReleaseDateUtc set releaseDateUtc for the current ToolComponent
func (t *ToolComponent) WithReleaseDateUtc(releaseDateUtc string) *ToolComponent { func (t *ToolComponent) WithReleaseDateUtc(releaseDateUtc string) *ToolComponent {
t.ReleaseDateUtc = releaseDateUtc t.ReleaseDateUtc = releaseDateUtc

View file

@ -2,18 +2,18 @@ package sarif
import ( import (
"fmt" "fmt"
"github.com/google/uuid" "sort"
"runtime/debug"
"strconv" "strconv"
"strings" "strings"
"github.com/google/uuid"
"github.com/securego/gosec/v2" "github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/cwe" "github.com/securego/gosec/v2/cwe"
"github.com/securego/gosec/v2/report/core"
) )
//GenerateReport Convert a gosec report to a Sarif Report //GenerateReport Convert a gosec report to a Sarif Report
func GenerateReport(rootPaths []string, data *core.ReportInfo) (*Report, error) { func GenerateReport(rootPaths []string, data *gosec.ReportInfo) (*Report, error) {
type rule struct { type rule struct {
index int index int
@ -56,7 +56,10 @@ func GenerateReport(rootPaths []string, data *core.ReportInfo) (*Report, error)
results = append(results, result) results = append(results, result)
} }
tool := NewTool(buildSarifDriver(rules)) sort.SliceStable(rules, func(i, j int) bool { return rules[i].ID < rules[j].ID })
sort.SliceStable(cweTaxa, func(i, j int) bool { return cweTaxa[i].ID < cweTaxa[j].ID })
tool := NewTool(buildSarifDriver(rules, data.GosecVersion))
cweTaxonomy := buildCWETaxonomy(cweTaxa) cweTaxonomy := buildCWETaxonomy(cweTaxa)
@ -108,6 +111,7 @@ func buildCWETaxonomy(taxa []*ReportingDescriptor) *ToolComponent {
WithOrganization(cwe.Organization). WithOrganization(cwe.Organization).
WithShortDescription(NewMultiformatMessageString(cwe.Description)). WithShortDescription(NewMultiformatMessageString(cwe.Description)).
WithIsComprehensive(true). WithIsComprehensive(true).
WithLanguage("en").
WithMinimumRequiredLocalizedDataSemanticVersion(cwe.Version). WithMinimumRequiredLocalizedDataSemanticVersion(cwe.Version).
WithTaxa(taxa...) WithTaxa(taxa...)
} }
@ -115,22 +119,27 @@ func buildCWETaxonomy(taxa []*ReportingDescriptor) *ToolComponent {
func parseSarifTaxon(weakness *cwe.Weakness) *ReportingDescriptor { func parseSarifTaxon(weakness *cwe.Weakness) *ReportingDescriptor {
return &ReportingDescriptor{ return &ReportingDescriptor{
ID: weakness.ID, ID: weakness.ID,
Name: weakness.Name,
GUID: uuid3(weakness.SprintID()), GUID: uuid3(weakness.SprintID()),
HelpURI: weakness.SprintURL(), HelpURI: weakness.SprintURL(),
ShortDescription: NewMultiformatMessageString(weakness.Description), FullDescription: NewMultiformatMessageString(weakness.Description),
ShortDescription: NewMultiformatMessageString(weakness.Name),
} }
} }
func buildSarifDriver(rules []*ReportingDescriptor) *ToolComponent { func parseSemanticVersion(version string) string {
buildInfo, ok := debug.ReadBuildInfo() if len(version) == 0 {
var gosecVersion string return "devel"
if ok {
gosecVersion = buildInfo.Main.Version[1:]
} else {
gosecVersion = "devel"
} }
if strings.HasPrefix(version, "v") {
return version[1:]
}
return version
}
func buildSarifDriver(rules []*ReportingDescriptor, gosecVersion string) *ToolComponent {
semanticVersion := parseSemanticVersion(gosecVersion)
return NewToolComponent("gosec", gosecVersion, "https://github.com/securego/gosec/"). return NewToolComponent("gosec", gosecVersion, "https://github.com/securego/gosec/").
WithSemanticVersion(semanticVersion).
WithSupportedTaxonomies(NewToolComponentReference(cwe.Acronym)). WithSupportedTaxonomies(NewToolComponentReference(cwe.Acronym)).
WithRules(rules...) WithRules(rules...)
} }

View file

@ -2,12 +2,13 @@ package sarif
import ( import (
"encoding/json" "encoding/json"
"github.com/securego/gosec/v2/report/core"
"io" "io"
"github.com/securego/gosec/v2"
) )
//WriteReport write a report in SARIF format to the output writer //WriteReport write a report in SARIF format to the output writer
func WriteReport(w io.Writer, data *core.ReportInfo, rootPaths []string) error { func WriteReport(w io.Writer, data *gosec.ReportInfo, rootPaths []string) error {
sr, err := GenerateReport(rootPaths, data) sr, err := GenerateReport(rootPaths, data)
if err != nil { if err != nil {
return err return err

View file

@ -1,10 +1,10 @@
package sonar package sonar
import ( import (
"github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/report/core"
"strconv" "strconv"
"strings" "strings"
"github.com/securego/gosec/v2"
) )
const ( const (
@ -13,7 +13,7 @@ const (
) )
//GenerateReport Convert a gosec report to a Sonar Report //GenerateReport Convert a gosec report to a Sonar Report
func GenerateReport(rootPaths []string, data *core.ReportInfo) (*Report, error) { func GenerateReport(rootPaths []string, data *gosec.ReportInfo) (*Report, error) {
si := &Report{Issues: []*Issue{}} si := &Report{Issues: []*Issue{}}
for _, issue := range data.Issues { for _, issue := range data.Issues {
sonarFilePath := parseFilePath(issue, rootPaths) sonarFilePath := parseFilePath(issue, rootPaths)

View file

@ -4,7 +4,6 @@ import (
. "github.com/onsi/ginkgo" . "github.com/onsi/ginkgo"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"github.com/securego/gosec/v2" "github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/report/core"
"github.com/securego/gosec/v2/report/sonar" "github.com/securego/gosec/v2/report/sonar"
) )
@ -13,7 +12,7 @@ var _ = Describe("Sonar Formatter", func() {
}) })
Context("when converting to Sonarqube issues", func() { Context("when converting to Sonarqube issues", func() {
It("it should parse the report info", func() { It("it should parse the report info", func() {
data := &core.ReportInfo{ data := &gosec.ReportInfo{
Errors: map[string][]gosec.Error{}, Errors: map[string][]gosec.Error{},
Issues: []*gosec.Issue{ Issues: []*gosec.Issue{
{ {
@ -61,7 +60,7 @@ var _ = Describe("Sonar Formatter", func() {
}) })
It("it should parse the report info with files in subfolders", func() { It("it should parse the report info with files in subfolders", func() {
data := &core.ReportInfo{ data := &gosec.ReportInfo{
Errors: map[string][]gosec.Error{}, Errors: map[string][]gosec.Error{},
Issues: []*gosec.Issue{ Issues: []*gosec.Issue{
{ {
@ -108,7 +107,7 @@ var _ = Describe("Sonar Formatter", func() {
Expect(*issues).To(Equal(*want)) Expect(*issues).To(Equal(*want))
}) })
It("it should not parse the report info for files from other projects", func() { It("it should not parse the report info for files from other projects", func() {
data := &core.ReportInfo{ data := &gosec.ReportInfo{
Errors: map[string][]gosec.Error{}, Errors: map[string][]gosec.Error{},
Issues: []*gosec.Issue{ Issues: []*gosec.Issue{
{ {
@ -140,7 +139,7 @@ var _ = Describe("Sonar Formatter", func() {
}) })
It("it should parse the report info for multiple projects projects", func() { It("it should parse the report info for multiple projects projects", func() {
data := &core.ReportInfo{ data := &gosec.ReportInfo{
Errors: map[string][]gosec.Error{}, Errors: map[string][]gosec.Error{},
Issues: []*gosec.Issue{ Issues: []*gosec.Issue{
{ {

View file

@ -2,12 +2,13 @@ package sonar
import ( import (
"encoding/json" "encoding/json"
"github.com/securego/gosec/v2/report/core"
"io" "io"
"github.com/securego/gosec/v2"
) )
//WriteReport write a report in sonar format to the output writer //WriteReport write a report in sonar format to the output writer
func WriteReport(w io.Writer, data *core.ReportInfo, rootPaths []string) error { func WriteReport(w io.Writer, data *gosec.ReportInfo, rootPaths []string) error {
si, err := GenerateReport(rootPaths, data) si, err := GenerateReport(rootPaths, data)
if err != nil { if err != nil {
return err return err

View file

@ -4,13 +4,13 @@ import (
"bufio" "bufio"
"bytes" "bytes"
"fmt" "fmt"
"github.com/gookit/color"
"github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/report/core"
"io" "io"
"strconv" "strconv"
"strings" "strings"
"text/template" "text/template"
"github.com/gookit/color"
"github.com/securego/gosec/v2"
) )
var ( var (
@ -20,7 +20,7 @@ var (
) )
//WriteReport write a (colorized) report in text format //WriteReport write a (colorized) report in text format
func WriteReport(w io.Writer, data *core.ReportInfo, enableColor bool) error { func WriteReport(w io.Writer, data *gosec.ReportInfo, enableColor bool) error {
t, e := template. t, e := template.
New("gosec"). New("gosec").
Funcs(plainTextFuncMap(enableColor)). Funcs(plainTextFuncMap(enableColor)).

View file

@ -1,13 +1,14 @@
package yaml package yaml
import ( import (
"github.com/securego/gosec/v2/report/core"
"gopkg.in/yaml.v2"
"io" "io"
"github.com/securego/gosec/v2"
"gopkg.in/yaml.v2"
) )
//WriteReport write a report in yaml format to the output writer //WriteReport write a report in yaml format to the output writer
func WriteReport(w io.Writer, data *core.ReportInfo) error { func WriteReport(w io.Writer, data *gosec.ReportInfo) error {
raw, err := yaml.Marshal(data) raw, err := yaml.Marshal(data)
if err != nil { if err != nil {
return err return err

9
tools/tools.go Normal file
View file

@ -0,0 +1,9 @@
// +build tools
package tools
// nolint
import (
_ "github.com/lib/pq"
_ "golang.org/x/text"
)