Extract the issue in its own package

This commit is contained in:
Cosmin Cojocar 2023-02-15 20:44:13 +01:00 committed by Cosmin Cojocar
parent 31e63276f1
commit de2c6a36fa
48 changed files with 439 additions and 378 deletions

View file

@ -87,4 +87,7 @@ image-push: image
docker push $(IMAGE_REPO)/$(BIN):$(GIT_TAG) docker push $(IMAGE_REPO)/$(BIN):$(GIT_TAG)
docker push $(IMAGE_REPO)/$(BIN):latest docker push $(IMAGE_REPO)/$(BIN):latest
.PHONY: test build clean release image image-push tlsconfig:
go generate ./...
.PHONY: test build clean release image image-push tlsconfig

View file

@ -32,6 +32,7 @@ import (
"sync" "sync"
"github.com/securego/gosec/v2/analyzers" "github.com/securego/gosec/v2/analyzers"
"github.com/securego/gosec/v2/issue"
"golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/buildssa" "golang.org/x/tools/go/analysis/passes/buildssa"
"golang.org/x/tools/go/packages" "golang.org/x/tools/go/packages"
@ -68,10 +69,21 @@ type Context struct {
Root *ast.File Root *ast.File
Imports *ImportTracker Imports *ImportTracker
Config Config Config Config
Ignores []map[string][]SuppressionInfo Ignores []map[string][]issue.SuppressionInfo
PassedValues map[string]interface{} PassedValues map[string]interface{}
} }
// getFileAtNodePos returns the file at the node position in the file set available in the context.
func (ctx *Context) GetFileAtNodePos(node ast.Node) *token.File {
return ctx.FileSet.File(node.Pos())
}
// NewIssue creates a new issue
func (ctx *Context) NewIssue(node ast.Node, ruleID, desc string,
severity, confidence issue.Score) *issue.Issue {
return issue.New(ctx.GetFileAtNodePos(node), node, ruleID, desc, severity, confidence)
}
// Metrics used when reporting information about a scanning run. // Metrics used when reporting information about a scanning run.
type Metrics struct { type Metrics struct {
NumFiles int `json:"files"` NumFiles int `json:"files"`
@ -88,7 +100,7 @@ type Analyzer struct {
context *Context context *Context
config Config config Config
logger *log.Logger logger *log.Logger
issues []*Issue issues []*issue.Issue
stats *Metrics stats *Metrics
errors map[string][]Error // keys are file paths; values are the golang errors in those files errors map[string][]Error // keys are file paths; values are the golang errors in those files
tests bool tests bool
@ -99,13 +111,6 @@ type Analyzer struct {
analyzerList []*analysis.Analyzer analyzerList []*analysis.Analyzer
} }
// SuppressionInfo object is to record the kind and the justification that used
// to suppress violations.
type SuppressionInfo struct {
Kind string `json:"kind"`
Justification string `json:"justification"`
}
// NewAnalyzer builds a new analyzer. // NewAnalyzer builds a new analyzer.
func NewAnalyzer(conf Config, tests bool, excludeGenerated bool, trackSuppressions bool, concurrency int, logger *log.Logger) *Analyzer { func NewAnalyzer(conf Config, tests bool, excludeGenerated bool, trackSuppressions bool, concurrency int, logger *log.Logger) *Analyzer {
ignoreNoSec := false ignoreNoSec := false
@ -126,7 +131,7 @@ func NewAnalyzer(conf Config, tests bool, excludeGenerated bool, trackSuppressio
context: &Context{}, context: &Context{},
config: conf, config: conf,
logger: logger, logger: logger,
issues: make([]*Issue, 0, 16), issues: make([]*issue.Issue, 0, 16),
stats: &Metrics{}, stats: &Metrics{},
errors: make(map[string][]Error), errors: make(map[string][]Error),
tests: tests, tests: tests,
@ -371,8 +376,8 @@ func (gosec *Analyzer) CheckAnalyzers(pkg *packages.Package) {
continue continue
} }
if result != nil { if result != nil {
if issue, ok := result.(*analyzers.Issue); ok { if aissue, ok := result.(*analyzers.Issue); ok {
gosec.updateIssues(toGosecIssue(issue), false, []SuppressionInfo{}) gosec.updateIssues(toGosecIssue(aissue), false, []issue.SuppressionInfo{})
} }
} }
} }
@ -439,7 +444,7 @@ func (gosec *Analyzer) AppendError(file string, err error) {
} }
// ignore a node (and sub-tree) if it is tagged with a nosec tag comment // ignore a node (and sub-tree) if it is tagged with a nosec tag comment
func (gosec *Analyzer) ignore(n ast.Node) map[string]SuppressionInfo { func (gosec *Analyzer) ignore(n ast.Node) map[string]issue.SuppressionInfo {
if groups, ok := gosec.context.Comments[n]; ok && !gosec.ignoreNosec { if groups, ok := gosec.context.Comments[n]; ok && !gosec.ignoreNosec {
// Checks if an alternative for #nosec is set and, if not, uses the default. // Checks if an alternative for #nosec is set and, if not, uses the default.
@ -476,13 +481,13 @@ func (gosec *Analyzer) ignore(n ast.Node) map[string]SuppressionInfo {
re := regexp.MustCompile(`(G\d{3})`) re := regexp.MustCompile(`(G\d{3})`)
matches := re.FindAllStringSubmatch(directive, -1) matches := re.FindAllStringSubmatch(directive, -1)
suppression := SuppressionInfo{ suppression := issue.SuppressionInfo{
Kind: "inSource", Kind: "inSource",
Justification: justification, Justification: justification,
} }
// Find the rule IDs to ignore. // Find the rule IDs to ignore.
ignores := make(map[string]SuppressionInfo) ignores := make(map[string]issue.SuppressionInfo)
for _, v := range matches { for _, v := range matches {
ignores[v[1]] = suppression ignores[v[1]] = suppression
} }
@ -525,7 +530,7 @@ func (gosec *Analyzer) Visit(n ast.Node) ast.Visitor {
return gosec return gosec
} }
func (gosec *Analyzer) updateIgnoredRules(n ast.Node) (map[string][]SuppressionInfo, bool) { func (gosec *Analyzer) updateIgnoredRules(n ast.Node) (map[string][]issue.SuppressionInfo, bool) {
if n == nil { if n == nil {
if len(gosec.context.Ignores) > 0 { if len(gosec.context.Ignores) > 0 {
gosec.context.Ignores = gosec.context.Ignores[1:] gosec.context.Ignores = gosec.context.Ignores[1:]
@ -536,7 +541,7 @@ func (gosec *Analyzer) updateIgnoredRules(n ast.Node) (map[string][]SuppressionI
ignoredRules := gosec.ignore(n) ignoredRules := gosec.ignore(n)
// Now create the union of exclusions. // Now create the union of exclusions.
ignores := map[string][]SuppressionInfo{} ignores := map[string][]issue.SuppressionInfo{}
if len(gosec.context.Ignores) > 0 { if len(gosec.context.Ignores) > 0 {
for k, v := range gosec.context.Ignores[0] { for k, v := range gosec.context.Ignores[0] {
ignores[k] = v ignores[k] = v
@ -548,12 +553,12 @@ func (gosec *Analyzer) updateIgnoredRules(n ast.Node) (map[string][]SuppressionI
} }
// Push the new set onto the stack. // Push the new set onto the stack.
gosec.context.Ignores = append([]map[string][]SuppressionInfo{ignores}, gosec.context.Ignores...) gosec.context.Ignores = append([]map[string][]issue.SuppressionInfo{ignores}, gosec.context.Ignores...)
return ignores, true return ignores, true
} }
func (gosec *Analyzer) updateSuppressions(id string, ignores map[string][]SuppressionInfo) ([]SuppressionInfo, bool) { func (gosec *Analyzer) updateSuppressions(id string, ignores map[string][]issue.SuppressionInfo) ([]issue.SuppressionInfo, bool) {
// Check if all rules are ignored. // Check if all rules are ignored.
generalSuppressions, generalIgnored := ignores[aliasOfAllRules] generalSuppressions, generalIgnored := ignores[aliasOfAllRules]
// Check if the specific rule is ignored // Check if the specific rule is ignored
@ -565,7 +570,7 @@ func (gosec *Analyzer) updateSuppressions(id string, ignores map[string][]Suppre
// Track external suppressions. // Track external suppressions.
if gosec.ruleset.IsRuleSuppressed(id) { if gosec.ruleset.IsRuleSuppressed(id) {
ignored = true ignored = true
suppressions = append(suppressions, SuppressionInfo{ suppressions = append(suppressions, issue.SuppressionInfo{
Kind: "external", Kind: "external",
Justification: externalSuppressionJustification, Justification: externalSuppressionJustification,
}) })
@ -573,7 +578,7 @@ func (gosec *Analyzer) updateSuppressions(id string, ignores map[string][]Suppre
return suppressions, ignored return suppressions, ignored
} }
func (gosec *Analyzer) updateIssues(issue *Issue, ignored bool, suppressions []SuppressionInfo) { func (gosec *Analyzer) updateIssues(issue *issue.Issue, ignored bool, suppressions []issue.SuppressionInfo) {
if issue != nil { if issue != nil {
if gosec.showIgnored { if gosec.showIgnored {
issue.NoSec = ignored issue.NoSec = ignored
@ -590,27 +595,27 @@ func (gosec *Analyzer) updateIssues(issue *Issue, ignored bool, suppressions []S
} }
} }
func toGosecIssue(issue *analyzers.Issue) *Issue { func toGosecIssue(aissue *analyzers.Issue) *issue.Issue {
return &Issue{ return &issue.Issue{
File: issue.File, File: aissue.File,
Line: issue.Line, Line: aissue.Line,
Col: issue.Col, Col: aissue.Col,
RuleID: issue.AnalyzerID, RuleID: aissue.AnalyzerID,
What: issue.What, What: aissue.What,
Confidence: Score(issue.Confidence), Confidence: issue.Score(aissue.Confidence),
Severity: Score(issue.Severity), Severity: issue.Score(aissue.Severity),
} }
} }
// Report returns the current issues discovered and the metrics about the scan // Report returns the current issues discovered and the metrics about the scan
func (gosec *Analyzer) Report() ([]*Issue, *Metrics, map[string][]Error) { func (gosec *Analyzer) Report() ([]*issue.Issue, *Metrics, map[string][]Error) {
return gosec.issues, gosec.stats, gosec.errors return gosec.issues, gosec.stats, gosec.errors
} }
// Reset clears state such as context, issues and metrics from the configured analyzer // Reset clears state such as context, issues and metrics from the configured analyzer
func (gosec *Analyzer) Reset() { func (gosec *Analyzer) Reset() {
gosec.context = &Context{} gosec.context = &Context{}
gosec.issues = make([]*Issue, 0, 16) gosec.issues = make([]*issue.Issue, 0, 16)
gosec.stats = &Metrics{} gosec.stats = &Metrics{}
gosec.ruleset = NewRuleSet() gosec.ruleset = NewRuleSet()
} }

View file

@ -26,6 +26,7 @@ import (
"github.com/securego/gosec/v2" "github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/cmd/vflag" "github.com/securego/gosec/v2/cmd/vflag"
"github.com/securego/gosec/v2/issue"
"github.com/securego/gosec/v2/report" "github.com/securego/gosec/v2/report"
"github.com/securego/gosec/v2/rules" "github.com/securego/gosec/v2/rules"
) )
@ -265,22 +266,22 @@ func saveReport(filename, format string, rootPaths []string, reportInfo *gosec.R
return nil return nil
} }
func convertToScore(value string) (gosec.Score, error) { func convertToScore(value string) (issue.Score, error) {
value = strings.ToLower(value) value = strings.ToLower(value)
switch value { switch value {
case "low": case "low":
return gosec.Low, nil return issue.Low, nil
case "medium": case "medium":
return gosec.Medium, nil return issue.Medium, nil
case "high": case "high":
return gosec.High, nil return issue.High, nil
default: default:
return gosec.Low, fmt.Errorf("provided value '%s' not valid. Valid options: low, medium, high", value) return issue.Low, fmt.Errorf("provided value '%s' not valid. Valid options: low, medium, high", value)
} }
} }
func filterIssues(issues []*gosec.Issue, severity gosec.Score, confidence gosec.Score) ([]*gosec.Issue, int) { func filterIssues(issues []*issue.Issue, severity issue.Score, confidence issue.Score) ([]*issue.Issue, int) {
result := make([]*gosec.Issue, 0) result := make([]*issue.Issue, 0)
trueIssues := 0 trueIssues := 0
for _, issue := range issues { for _, issue := range issues {
if issue.Severity >= severity && issue.Confidence >= confidence { if issue.Severity >= severity && issue.Confidence >= confidence {
@ -293,7 +294,7 @@ func filterIssues(issues []*gosec.Issue, severity gosec.Score, confidence gosec.
return result, trueIssues return result, trueIssues
} }
func exit(issues []*gosec.Issue, errors map[string][]gosec.Error, noFail bool) { func exit(issues []*issue.Issue, errors map[string][]gosec.Error, noFail bool) {
nsi := 0 nsi := 0
for _, issue := range issues { for _, issue := range issues {
if len(issue.Suppressions) == 0 { if len(issue.Suppressions) == 0 {

View file

@ -5,7 +5,7 @@ import (
"strconv" "strconv"
"strings" "strings"
"github.com/securego/gosec/v2" "github.com/securego/gosec/v2/issue"
) )
// handle ranges // handle ranges
@ -14,7 +14,7 @@ func extractLineNumber(s string) int {
return lineNumber return lineNumber
} }
type sortBySeverity []*gosec.Issue type sortBySeverity []*issue.Issue
func (s sortBySeverity) Len() int { return len(s) } func (s sortBySeverity) Len() int { return len(s) }
@ -34,6 +34,6 @@ func (s sortBySeverity) Less(i, j int) bool {
func (s sortBySeverity) Swap(i, j int) { s[i], s[j] = s[j], s[i] } func (s sortBySeverity) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
// sortIssues sorts the issues by severity in descending order // sortIssues sorts the issues by severity in descending order
func sortIssues(issues []*gosec.Issue) { func sortIssues(issues []*issue.Issue) {
sort.Sort(sortBySeverity(issues)) sort.Sort(sortBySeverity(issues))
} }

View file

@ -5,22 +5,22 @@ import (
. "github.com/onsi/ginkgo/v2" . "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"github.com/securego/gosec/v2" "github.com/securego/gosec/v2/issue"
) )
var defaultIssue = gosec.Issue{ var defaultIssue = issue.Issue{
File: "/home/src/project/test.go", File: "/home/src/project/test.go",
Line: "1", Line: "1",
Col: "1", Col: "1",
RuleID: "ruleID", RuleID: "ruleID",
What: "test", What: "test",
Confidence: gosec.High, Confidence: issue.High,
Severity: gosec.High, Severity: issue.High,
Code: "1: testcode", Code: "1: testcode",
Cwe: gosec.GetCweByRule("G101"), Cwe: issue.GetCweByRule("G101"),
} }
func createIssue() gosec.Issue { func createIssue() issue.Issue {
return defaultIssue return defaultIssue
} }
@ -29,8 +29,8 @@ func TestRules(t *testing.T) {
RunSpecs(t, "Sort issues Suite") RunSpecs(t, "Sort issues Suite")
} }
func firstIsGreater(less, greater *gosec.Issue) { func firstIsGreater(less, greater *issue.Issue) {
slice := []*gosec.Issue{less, greater} slice := []*issue.Issue{less, greater}
sortIssues(slice) sortIssues(slice)
@ -40,9 +40,9 @@ func firstIsGreater(less, greater *gosec.Issue) {
var _ = Describe("Sorting by Severity", func() { var _ = Describe("Sorting by Severity", func() {
It("sorts by severity", func() { It("sorts by severity", func() {
less := createIssue() less := createIssue()
less.Severity = gosec.Low less.Severity = issue.Low
greater := createIssue() greater := createIssue()
less.Severity = gosec.High less.Severity = issue.High
firstIsGreater(&less, &greater) firstIsGreater(&less, &greater)
}) })

View file

@ -9,5 +9,6 @@ import (
"go/ast" "go/ast"
"github.com/securego/gosec/v2" "github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
) )
`)) `))

View file

@ -7,7 +7,7 @@ var generatedRuleTmpl = template.Must(template.New("generated").Parse(`
// DO NOT EDIT - generated by tlsconfig tool // DO NOT EDIT - generated by tlsconfig tool
func New{{.Name}}TLSCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) { func New{{.Name}}TLSCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
return &insecureConfigTLS{ return &insecureConfigTLS{
MetaData: gosec.MetaData{ID: id}, MetaData: issue.MetaData{ID: id},
requiredType: "crypto/tls.Config", requiredType: "crypto/tls.Config",
MinVersion: {{ .MinVersion }}, MinVersion: {{ .MinVersion }},
MaxVersion: {{ .MaxVersion }}, MaxVersion: {{ .MaxVersion }},

View file

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
package gosec package issue
import ( import (
"bufio" "bufio"
@ -105,8 +105,15 @@ type Issue struct {
Suppressions []SuppressionInfo `json:"suppressions"` // Suppression info of the issue Suppressions []SuppressionInfo `json:"suppressions"` // Suppression info of the issue
} }
// SuppressionInfo object is to record the kind and the justification that used
// to suppress violations.
type SuppressionInfo struct {
Kind string `json:"kind"`
Justification string `json:"justification"`
}
// FileLocation point out the file path and line number in file // FileLocation point out the file path and line number in file
func (i Issue) FileLocation() string { func (i *Issue) FileLocation() string {
return fmt.Sprintf("%s:%s", i.File, i.Line) return fmt.Sprintf("%s:%s", i.File, i.Line)
} }
@ -171,9 +178,8 @@ func codeSnippetEndLine(node ast.Node, fobj *token.File) int64 {
return e + SnippetOffset return e + SnippetOffset
} }
// NewIssue creates a new Issue // New creates a new Issue
func NewIssue(ctx *Context, node ast.Node, ruleID, desc string, severity Score, confidence Score) *Issue { func New(fobj *token.File, node ast.Node, ruleID, desc string, severity, confidence Score) *Issue {
fobj := ctx.FileSet.File(node.Pos())
name := fobj.Name() name := fobj.Name()
start, end := fobj.Line(node.Pos()), fobj.Line(node.End()) start, end := fobj.Line(node.Pos()), fobj.Line(node.End())
line := strconv.Itoa(start) line := strconv.Itoa(start)

View file

@ -1,4 +1,4 @@
package gosec_test package issue_test
import ( import (
"go/ast" "go/ast"
@ -6,6 +6,7 @@ import (
. "github.com/onsi/ginkgo/v2" . "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"github.com/securego/gosec/v2" "github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
"github.com/securego/gosec/v2/rules" "github.com/securego/gosec/v2/rules"
"github.com/securego/gosec/v2/testutils" "github.com/securego/gosec/v2/testutils"
) )
@ -36,7 +37,8 @@ var _ = Describe("Issue", func() {
ast.Walk(v, ctx.Root) ast.Walk(v, ctx.Root)
Expect(target).ShouldNot(BeNil()) Expect(target).ShouldNot(BeNil())
issue := gosec.NewIssue(ctx, target, "TEST", "", gosec.High, gosec.High) fobj := ctx.GetFileAtNodePos(target)
issue := issue.New(fobj, target, "TEST", "", issue.High, issue.High)
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"))
@ -79,10 +81,10 @@ var _ = Describe("Issue", func() {
// Use hardcodeded rule to check assignment // Use hardcodeded rule to check assignment
cfg := gosec.NewConfig() cfg := gosec.NewConfig()
rule, _ := rules.NewHardcodedCredentials("TEST", cfg) rule, _ := rules.NewHardcodedCredentials("TEST", cfg)
issue, err := rule.Match(target, ctx) foundIssue, err := rule.Match(target, ctx)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
Expect(issue).ShouldNot(BeNil()) Expect(foundIssue).ShouldNot(BeNil())
Expect(issue.FileLocation()).Should(MatchRegexp("foo.go:5")) Expect(foundIssue.FileLocation()).Should(MatchRegexp("foo.go:5"))
}) })
It("should provide accurate line and file information", func() { It("should provide accurate line and file information", func() {

View file

@ -1,15 +1,19 @@
package gosec package gosec
import (
"github.com/securego/gosec/v2/issue"
)
// ReportInfo this is report information // ReportInfo this is report information
type ReportInfo struct { type ReportInfo struct {
Errors map[string][]Error `json:"Golang errors"` Errors map[string][]Error `json:"Golang errors"`
Issues []*Issue Issues []*issue.Issue
Stats *Metrics Stats *Metrics
GosecVersion string GosecVersion string
} }
// NewReportInfo instantiate a ReportInfo // NewReportInfo instantiate a ReportInfo
func NewReportInfo(issues []*Issue, metrics *Metrics, errors map[string][]Error) *ReportInfo { func NewReportInfo(issues []*issue.Issue, metrics *Metrics, errors map[string][]Error) *ReportInfo {
return &ReportInfo{ return &ReportInfo{
Errors: errors, Errors: errors,
Issues: issues, Issues: issues,

View file

@ -18,6 +18,7 @@ import (
"io" "io"
"github.com/securego/gosec/v2" "github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
"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"
@ -81,8 +82,8 @@ func CreateReport(w io.Writer, format string, enableColor bool, rootPaths []stri
return err return err
} }
func filterOutSuppressedIssues(issues []*gosec.Issue) []*gosec.Issue { func filterOutSuppressedIssues(issues []*issue.Issue) []*issue.Issue {
nonSuppressedIssues := []*gosec.Issue{} nonSuppressedIssues := []*issue.Issue{}
for _, issue := range issues { for _, issue := range issues {
if len(issue.Suppressions) == 0 { if len(issue.Suppressions) == 0 {
nonSuppressedIssues = append(nonSuppressedIssues, issue) nonSuppressedIssues = append(nonSuppressedIssues, issue)

View file

@ -10,39 +10,40 @@ 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/issue"
"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.v3" "gopkg.in/yaml.v3"
) )
func createIssueWithFileWhat(file, what string) *gosec.Issue { func createIssueWithFileWhat(file, what string) *issue.Issue {
issue := createIssue("i1", gosec.GetCweByRule("G101")) issue := createIssue("i1", issue.GetCweByRule("G101"))
issue.File = file issue.File = file
issue.What = what issue.What = what
return &issue return &issue
} }
func createIssue(ruleID string, weakness *cwe.Weakness) gosec.Issue { func createIssue(ruleID string, weakness *cwe.Weakness) issue.Issue {
return gosec.Issue{ return issue.Issue{
File: "/home/src/project/test.go", File: "/home/src/project/test.go",
Line: "1", Line: "1",
Col: "1", Col: "1",
RuleID: ruleID, RuleID: ruleID,
What: "test", What: "test",
Confidence: gosec.High, Confidence: issue.High,
Severity: gosec.High, Severity: issue.High,
Code: "1: testcode", Code: "1: testcode",
Cwe: weakness, Cwe: weakness,
} }
} }
func createReportInfo(rule string, weakness *cwe.Weakness) gosec.ReportInfo { func createReportInfo(rule string, weakness *cwe.Weakness) gosec.ReportInfo {
issue := createIssue(rule, weakness) newissue := createIssue(rule, weakness)
metrics := gosec.Metrics{} metrics := gosec.Metrics{}
return gosec.ReportInfo{ return gosec.ReportInfo{
Errors: map[string][]gosec.Error{}, Errors: map[string][]gosec.Error{},
Issues: []*gosec.Issue{ Issues: []*issue.Issue{
&issue, &newissue,
}, },
Stats: &metrics, Stats: &metrics,
} }
@ -62,7 +63,7 @@ var _ = Describe("Formatter", func() {
It("it should parse the report info", func() { It("it should parse the report info", func() {
data := &gosec.ReportInfo{ data := &gosec.ReportInfo{
Errors: map[string][]gosec.Error{}, Errors: map[string][]gosec.Error{},
Issues: []*gosec.Issue{ Issues: []*issue.Issue{
{ {
Severity: 2, Severity: 2,
Confidence: 0, Confidence: 0,
@ -110,7 +111,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 := &gosec.ReportInfo{ data := &gosec.ReportInfo{
Errors: map[string][]gosec.Error{}, Errors: map[string][]gosec.Error{},
Issues: []*gosec.Issue{ Issues: []*issue.Issue{
{ {
Severity: 2, Severity: 2,
Confidence: 0, Confidence: 0,
@ -157,7 +158,7 @@ var _ = Describe("Formatter", func() {
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 := &gosec.ReportInfo{ data := &gosec.ReportInfo{
Errors: map[string][]gosec.Error{}, Errors: map[string][]gosec.Error{},
Issues: []*gosec.Issue{ Issues: []*issue.Issue{
{ {
Severity: 2, Severity: 2,
Confidence: 0, Confidence: 0,
@ -189,7 +190,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 := &gosec.ReportInfo{ data := &gosec.ReportInfo{
Errors: map[string][]gosec.Error{}, Errors: map[string][]gosec.Error{},
Issues: []*gosec.Issue{ Issues: []*issue.Issue{
{ {
Severity: 2, Severity: 2,
Confidence: 0, Confidence: 0,
@ -261,7 +262,7 @@ var _ = Describe("Formatter", func() {
Context("When using junit", func() { Context("When using junit", 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 := []*issue.Issue{createIssueWithFileWhat("i1", "1"), createIssueWithFileWhat("i2", "2"), createIssueWithFileWhat("i3", "1")}
junitReport := junit.GenerateReport(&gosec.ReportInfo{Issues: issues}) junitReport := junit.GenerateReport(&gosec.ReportInfo{Issues: issues})
@ -285,12 +286,12 @@ var _ = Describe("Formatter", func() {
It("csv formatted report should contain the CWE mapping", func() { It("csv formatted report should contain the CWE mapping", func() {
for _, rule := range grules { for _, rule := range grules {
cwe := gosec.GetCweByRule(rule) cwe := issue.GetCweByRule(rule)
issue := createIssue(rule, cwe) newissue := createIssue(rule, cwe)
error := map[string][]gosec.Error{} error := map[string][]gosec.Error{}
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
reportInfo := gosec.NewReportInfo([]*gosec.Issue{&issue}, &gosec.Metrics{}, error) reportInfo := gosec.NewReportInfo([]*issue.Issue{&newissue}, &gosec.Metrics{}, error)
err := CreateReport(buf, "csv", false, []string{}, reportInfo) 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"
@ -300,12 +301,12 @@ var _ = Describe("Formatter", func() {
}) })
It("xml formatted report should contain the CWE mapping", func() { It("xml formatted report should contain the CWE mapping", func() {
for _, rule := range grules { for _, rule := range grules {
cwe := gosec.GetCweByRule(rule) cwe := issue.GetCweByRule(rule)
issue := createIssue(rule, cwe) newissue := createIssue(rule, cwe)
error := map[string][]gosec.Error{} error := map[string][]gosec.Error{}
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
reportInfo := gosec.NewReportInfo([]*gosec.Issue{&issue}, &gosec.Metrics{NumFiles: 0, NumLines: 0, NumNosec: 0, NumFound: 0}, error).WithVersion("v2.7.0") reportInfo := gosec.NewReportInfo([]*issue.Issue{&newissue}, &gosec.Metrics{NumFiles: 0, NumLines: 0, NumNosec: 0, NumFound: 0}, error).WithVersion("v2.7.0")
err := CreateReport(buf, "xml", false, []string{}, reportInfo) 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 Gosec : v2.7.0\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 Gosec : v2.7.0\n Files : 0\n Lines : 0\n Nosec : 0\n Issues : 0\n\n"
@ -315,8 +316,8 @@ var _ = Describe("Formatter", func() {
}) })
It("json formatted report should contain the CWE mapping", func() { It("json formatted report should contain the CWE mapping", func() {
for _, rule := range grules { for _, rule := range grules {
cwe := gosec.GetCweByRule(rule) cwe := issue.GetCweByRule(rule)
issue := createIssue(rule, cwe) newissue := createIssue(rule, cwe)
error := map[string][]gosec.Error{} error := map[string][]gosec.Error{}
data := createReportInfo(rule, cwe) data := createReportInfo(rule, cwe)
@ -326,7 +327,7 @@ 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)
reportInfo := gosec.NewReportInfo([]*gosec.Issue{&issue}, &gosec.Metrics{}, error) reportInfo := gosec.NewReportInfo([]*issue.Issue{&newissue}, &gosec.Metrics{}, error)
err = CreateReport(buf, "json", false, []string{}, reportInfo) err = CreateReport(buf, "json", false, []string{}, reportInfo)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
result := stripString(buf.String()) result := stripString(buf.String())
@ -336,8 +337,8 @@ var _ = Describe("Formatter", func() {
}) })
It("html formatted report should contain the CWE mapping", func() { It("html formatted report should contain the CWE mapping", func() {
for _, rule := range grules { for _, rule := range grules {
cwe := gosec.GetCweByRule(rule) cwe := issue.GetCweByRule(rule)
issue := createIssue(rule, cwe) newissue := createIssue(rule, cwe)
error := map[string][]gosec.Error{} error := map[string][]gosec.Error{}
data := createReportInfo(rule, cwe) data := createReportInfo(rule, cwe)
@ -347,7 +348,7 @@ 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)
reportInfo := gosec.NewReportInfo([]*gosec.Issue{&issue}, &gosec.Metrics{}, error) reportInfo := gosec.NewReportInfo([]*issue.Issue{&newissue}, &gosec.Metrics{}, error)
err = CreateReport(buf, "html", false, []string{}, reportInfo) err = CreateReport(buf, "html", false, []string{}, reportInfo)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
result := stripString(buf.String()) result := stripString(buf.String())
@ -357,8 +358,8 @@ var _ = Describe("Formatter", func() {
}) })
It("yaml formatted report should contain the CWE mapping", func() { It("yaml formatted report should contain the CWE mapping", func() {
for _, rule := range grules { for _, rule := range grules {
cwe := gosec.GetCweByRule(rule) cwe := issue.GetCweByRule(rule)
issue := createIssue(rule, cwe) newissue := createIssue(rule, cwe)
error := map[string][]gosec.Error{} error := map[string][]gosec.Error{}
data := createReportInfo(rule, cwe) data := createReportInfo(rule, cwe)
@ -368,7 +369,7 @@ 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)
reportInfo := gosec.NewReportInfo([]*gosec.Issue{&issue}, &gosec.Metrics{}, error) reportInfo := gosec.NewReportInfo([]*issue.Issue{&newissue}, &gosec.Metrics{}, error)
err = CreateReport(buf, "yaml", false, []string{}, reportInfo) err = CreateReport(buf, "yaml", false, []string{}, reportInfo)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
result := stripString(buf.String()) result := stripString(buf.String())
@ -378,8 +379,8 @@ var _ = Describe("Formatter", func() {
}) })
It("junit-xml formatted report should contain the CWE mapping", func() { It("junit-xml formatted report should contain the CWE mapping", func() {
for _, rule := range grules { for _, rule := range grules {
cwe := gosec.GetCweByRule(rule) cwe := issue.GetCweByRule(rule)
issue := createIssue(rule, cwe) newissue := createIssue(rule, cwe)
error := map[string][]gosec.Error{} error := map[string][]gosec.Error{}
data := createReportInfo(rule, cwe) data := createReportInfo(rule, cwe)
@ -389,7 +390,7 @@ 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)
reportInfo := gosec.NewReportInfo([]*gosec.Issue{&issue}, &gosec.Metrics{}, error) reportInfo := gosec.NewReportInfo([]*issue.Issue{&newissue}, &gosec.Metrics{}, error)
err = CreateReport(buf, "junit-xml", false, []string{}, reportInfo) 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))
@ -399,8 +400,8 @@ var _ = Describe("Formatter", func() {
}) })
It("text formatted report should contain the CWE mapping", func() { It("text formatted report should contain the CWE mapping", func() {
for _, rule := range grules { for _, rule := range grules {
cwe := gosec.GetCweByRule(rule) cwe := issue.GetCweByRule(rule)
issue := createIssue(rule, cwe) newissue := createIssue(rule, cwe)
error := map[string][]gosec.Error{} error := map[string][]gosec.Error{}
data := createReportInfo(rule, cwe) data := createReportInfo(rule, cwe)
@ -410,7 +411,7 @@ 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)
reportInfo := gosec.NewReportInfo([]*gosec.Issue{&issue}, &gosec.Metrics{}, error) reportInfo := gosec.NewReportInfo([]*issue.Issue{&newissue}, &gosec.Metrics{}, error)
err = CreateReport(buf, "text", false, []string{}, reportInfo) 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))
@ -420,11 +421,11 @@ var _ = Describe("Formatter", func() {
}) })
It("sonarqube formatted report shouldn't contain the CWE mapping", func() { It("sonarqube formatted report shouldn't contain the CWE mapping", func() {
for _, rule := range grules { for _, rule := range grules {
cwe := gosec.GetCweByRule(rule) cwe := issue.GetCweByRule(rule)
issue := createIssue(rule, cwe) newissue := createIssue(rule, cwe)
error := map[string][]gosec.Error{} error := map[string][]gosec.Error{}
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
reportInfo := gosec.NewReportInfo([]*gosec.Issue{&issue}, &gosec.Metrics{}, error) reportInfo := gosec.NewReportInfo([]*issue.Issue{&newissue}, &gosec.Metrics{}, error)
err := CreateReport(buf, "sonarqube", false, []string{"/home/src/project"}, reportInfo) err := CreateReport(buf, "sonarqube", false, []string{"/home/src/project"}, reportInfo)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
@ -441,12 +442,12 @@ var _ = Describe("Formatter", func() {
}) })
It("golint formatted report should contain the CWE mapping", func() { It("golint formatted report should contain the CWE mapping", func() {
for _, rule := range grules { for _, rule := range grules {
cwe := gosec.GetCweByRule(rule) cwe := issue.GetCweByRule(rule)
issue := createIssue(rule, cwe) newissue := createIssue(rule, cwe)
error := map[string][]gosec.Error{} error := map[string][]gosec.Error{}
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
reportInfo := gosec.NewReportInfo([]*gosec.Issue{&issue}, &gosec.Metrics{}, error) reportInfo := gosec.NewReportInfo([]*issue.Issue{&newissue}, &gosec.Metrics{}, error)
err := CreateReport(buf, "golint", false, []string{}, reportInfo) 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"
@ -456,12 +457,12 @@ var _ = Describe("Formatter", func() {
}) })
It("sarif formatted report should contain the CWE mapping", func() { It("sarif formatted report should contain the CWE mapping", func() {
for _, rule := range grules { for _, rule := range grules {
cwe := gosec.GetCweByRule(rule) cwe := issue.GetCweByRule(rule)
issue := createIssue(rule, cwe) newissue := createIssue(rule, cwe)
error := map[string][]gosec.Error{} error := map[string][]gosec.Error{}
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
reportInfo := gosec.NewReportInfo([]*gosec.Issue{&issue}, &gosec.Metrics{}, error).WithVersion("v2.7.0") reportInfo := gosec.NewReportInfo([]*issue.Issue{&newissue}, &gosec.Metrics{}, error).WithVersion("v2.7.0")
err := CreateReport(buf, "sarif", false, []string{}, reportInfo) err := CreateReport(buf, "sarif", false, []string{}, reportInfo)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
@ -490,8 +491,8 @@ var _ = Describe("Formatter", func() {
Context("When converting suppressed issues", func() { Context("When converting suppressed issues", func() {
ruleID := "G101" ruleID := "G101"
cwe := gosec.GetCweByRule(ruleID) cwe := issue.GetCweByRule(ruleID)
suppressions := []gosec.SuppressionInfo{ suppressions := []issue.SuppressionInfo{
{ {
Kind: "kind", Kind: "kind",
Justification: "justification", Justification: "justification",
@ -502,7 +503,7 @@ var _ = Describe("Formatter", func() {
It("text formatted report should contain the suppressed issues", func() { It("text formatted report should contain the suppressed issues", func() {
error := map[string][]gosec.Error{} error := map[string][]gosec.Error{}
reportInfo := gosec.NewReportInfo([]*gosec.Issue{&suppressedIssue}, &gosec.Metrics{}, error) reportInfo := gosec.NewReportInfo([]*issue.Issue{&suppressedIssue}, &gosec.Metrics{}, error)
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
err := CreateReport(buf, "text", false, []string{}, reportInfo) err := CreateReport(buf, "text", false, []string{}, reportInfo)
@ -514,7 +515,7 @@ var _ = Describe("Formatter", func() {
It("sarif formatted report should contain the suppressed issues", func() { It("sarif formatted report should contain the suppressed issues", func() {
error := map[string][]gosec.Error{} error := map[string][]gosec.Error{}
reportInfo := gosec.NewReportInfo([]*gosec.Issue{&suppressedIssue}, &gosec.Metrics{}, error) reportInfo := gosec.NewReportInfo([]*issue.Issue{&suppressedIssue}, &gosec.Metrics{}, error)
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
err := CreateReport(buf, "sarif", false, []string{}, reportInfo) err := CreateReport(buf, "sarif", false, []string{}, reportInfo)
@ -526,7 +527,7 @@ var _ = Describe("Formatter", func() {
It("json formatted report should contain the suppressed issues", func() { It("json formatted report should contain the suppressed issues", func() {
error := map[string][]gosec.Error{} error := map[string][]gosec.Error{}
reportInfo := gosec.NewReportInfo([]*gosec.Issue{&suppressedIssue}, &gosec.Metrics{}, error) reportInfo := gosec.NewReportInfo([]*issue.Issue{&suppressedIssue}, &gosec.Metrics{}, error)
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
err := CreateReport(buf, "json", false, []string{}, reportInfo) err := CreateReport(buf, "json", false, []string{}, reportInfo)

View file

@ -5,9 +5,10 @@ import (
"strconv" "strconv"
"github.com/securego/gosec/v2" "github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
) )
func generatePlaintext(issue *gosec.Issue) string { func generatePlaintext(issue *issue.Issue) string {
cweID := "CWE" cweID := "CWE"
if issue.Cwe != nil { if issue.Cwe != nil {
cweID = issue.Cwe.ID cweID = issue.Cwe.ID

View file

@ -9,6 +9,7 @@ import (
"github.com/google/uuid" "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/issue"
) )
// GenerateReport Convert a gosec report to a Sarif Report // GenerateReport Convert a gosec report to a Sarif Report
@ -72,28 +73,28 @@ func GenerateReport(rootPaths []string, data *gosec.ReportInfo) (*Report, error)
} }
// parseSarifRule return SARIF rule field struct // parseSarifRule return SARIF rule field struct
func parseSarifRule(issue *gosec.Issue) *ReportingDescriptor { func parseSarifRule(i *issue.Issue) *ReportingDescriptor {
cwe := gosec.GetCweByRule(issue.RuleID) cwe := issue.GetCweByRule(i.RuleID)
name := issue.RuleID name := i.RuleID
if cwe != nil { if cwe != nil {
name = cwe.Name name = cwe.Name
} }
return &ReportingDescriptor{ return &ReportingDescriptor{
ID: issue.RuleID, ID: i.RuleID,
Name: name, Name: name,
ShortDescription: NewMultiformatMessageString(issue.What), ShortDescription: NewMultiformatMessageString(i.What),
FullDescription: NewMultiformatMessageString(issue.What), FullDescription: NewMultiformatMessageString(i.What),
Help: NewMultiformatMessageString(fmt.Sprintf("%s\nSeverity: %s\nConfidence: %s\n", Help: NewMultiformatMessageString(fmt.Sprintf("%s\nSeverity: %s\nConfidence: %s\n",
issue.What, issue.Severity.String(), issue.Confidence.String())), i.What, i.Severity.String(), i.Confidence.String())),
Properties: &PropertyBag{ Properties: &PropertyBag{
"tags": []string{"security", issue.Severity.String()}, "tags": []string{"security", i.Severity.String()},
"precision": strings.ToLower(issue.Confidence.String()), "precision": strings.ToLower(i.Confidence.String()),
}, },
DefaultConfiguration: &ReportingConfiguration{ DefaultConfiguration: &ReportingConfiguration{
Level: getSarifLevel(issue.Severity.String()), Level: getSarifLevel(i.Severity.String()),
}, },
Relationships: []*ReportingDescriptorRelationship{ Relationships: []*ReportingDescriptorRelationship{
buildSarifReportingDescriptorRelationship(issue.Cwe), buildSarifReportingDescriptorRelationship(i.Cwe),
}, },
} }
} }
@ -157,27 +158,27 @@ func uuid3(value string) string {
} }
// parseSarifLocation return SARIF location struct // parseSarifLocation return SARIF location struct
func parseSarifLocation(issue *gosec.Issue, rootPaths []string) (*Location, error) { func parseSarifLocation(i *issue.Issue, rootPaths []string) (*Location, error) {
region, err := parseSarifRegion(issue) region, err := parseSarifRegion(i)
if err != nil { if err != nil {
return nil, err return nil, err
} }
artifactLocation := parseSarifArtifactLocation(issue, rootPaths) artifactLocation := parseSarifArtifactLocation(i, rootPaths)
return NewLocation(NewPhysicalLocation(artifactLocation, region)), nil return NewLocation(NewPhysicalLocation(artifactLocation, region)), nil
} }
func parseSarifArtifactLocation(issue *gosec.Issue, rootPaths []string) *ArtifactLocation { func parseSarifArtifactLocation(i *issue.Issue, rootPaths []string) *ArtifactLocation {
var filePath string var filePath string
for _, rootPath := range rootPaths { for _, rootPath := range rootPaths {
if strings.HasPrefix(issue.File, rootPath) { if strings.HasPrefix(i.File, rootPath) {
filePath = strings.Replace(issue.File, rootPath+"/", "", 1) filePath = strings.Replace(i.File, rootPath+"/", "", 1)
} }
} }
return NewArtifactLocation(filePath) return NewArtifactLocation(filePath)
} }
func parseSarifRegion(issue *gosec.Issue) (*Region, error) { func parseSarifRegion(i *issue.Issue) (*Region, error) {
lines := strings.Split(issue.Line, "-") lines := strings.Split(i.Line, "-")
startLine, err := strconv.Atoi(lines[0]) startLine, err := strconv.Atoi(lines[0])
if err != nil { if err != nil {
return nil, err return nil, err
@ -189,13 +190,13 @@ func parseSarifRegion(issue *gosec.Issue) (*Region, error) {
return nil, err return nil, err
} }
} }
col, err := strconv.Atoi(issue.Col) col, err := strconv.Atoi(i.Col)
if err != nil { if err != nil {
return nil, err return nil, err
} }
var code string var code string
line := startLine line := startLine
codeLines := strings.Split(issue.Code, "\n") codeLines := strings.Split(i.Code, "\n")
for _, codeLine := range codeLines { for _, codeLine := range codeLines {
lineStart := fmt.Sprintf("%d:", line) lineStart := fmt.Sprintf("%d:", line)
if strings.HasPrefix(codeLine, lineStart) { if strings.HasPrefix(codeLine, lineStart) {
@ -227,7 +228,7 @@ func getSarifLevel(s string) Level {
} }
} }
func buildSarifSuppressions(suppressions []gosec.SuppressionInfo) []*Suppression { func buildSarifSuppressions(suppressions []issue.SuppressionInfo) []*Suppression {
var sarifSuppressionList []*Suppression var sarifSuppressionList []*Suppression
for _, s := range suppressions { for _, s := range suppressions {
sarifSuppressionList = append(sarifSuppressionList, NewSuppression(s.Kind, s.Justification)) sarifSuppressionList = append(sarifSuppressionList, NewSuppression(s.Kind, s.Justification))

View file

@ -7,6 +7,7 @@ import (
. "github.com/onsi/ginkgo/v2" . "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"github.com/securego/gosec/v2" "github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
"github.com/securego/gosec/v2/report/sarif" "github.com/securego/gosec/v2/report/sarif"
) )
@ -16,7 +17,7 @@ var _ = Describe("Sarif Formatter", func() {
Context("when converting to Sarif issues", func() { Context("when converting to Sarif issues", func() {
It("sarif formatted report should contain the result", func() { It("sarif formatted report should contain the result", func() {
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
reportInfo := gosec.NewReportInfo([]*gosec.Issue{}, &gosec.Metrics{}, map[string][]gosec.Error{}).WithVersion("v2.7.0") reportInfo := gosec.NewReportInfo([]*issue.Issue{}, &gosec.Metrics{}, map[string][]gosec.Error{}).WithVersion("v2.7.0")
err := sarif.WriteReport(buf, reportInfo, []string{}) err := sarif.WriteReport(buf, reportInfo, []string{})
result := buf.String() result := buf.String()
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
@ -25,18 +26,18 @@ var _ = Describe("Sarif Formatter", func() {
It("sarif formatted report should contain the suppressed results", func() { It("sarif formatted report should contain the suppressed results", func() {
ruleID := "G101" ruleID := "G101"
cwe := gosec.GetCweByRule(ruleID) cwe := issue.GetCweByRule(ruleID)
suppressedIssue := gosec.Issue{ suppressedIssue := issue.Issue{
File: "/home/src/project/test.go", File: "/home/src/project/test.go",
Line: "1", Line: "1",
Col: "1", Col: "1",
RuleID: ruleID, RuleID: ruleID,
What: "test", What: "test",
Confidence: gosec.High, Confidence: issue.High,
Severity: gosec.High, Severity: issue.High,
Code: "1: testcode", Code: "1: testcode",
Cwe: cwe, Cwe: cwe,
Suppressions: []gosec.SuppressionInfo{ Suppressions: []issue.SuppressionInfo{
{ {
Kind: "kind", Kind: "kind",
Justification: "justification", Justification: "justification",
@ -44,7 +45,7 @@ var _ = Describe("Sarif Formatter", func() {
}, },
} }
reportInfo := gosec.NewReportInfo([]*gosec.Issue{&suppressedIssue}, &gosec.Metrics{}, map[string][]gosec.Error{}).WithVersion("v2.7.0") reportInfo := gosec.NewReportInfo([]*issue.Issue{&suppressedIssue}, &gosec.Metrics{}, map[string][]gosec.Error{}).WithVersion("v2.7.0")
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
err := sarif.WriteReport(buf, reportInfo, []string{}) err := sarif.WriteReport(buf, reportInfo, []string{})
result := buf.String() result := buf.String()
@ -58,54 +59,54 @@ var _ = Describe("Sarif Formatter", func() {
}) })
It("sarif formatted report should contain the formatted one line code snippet", func() { It("sarif formatted report should contain the formatted one line code snippet", func() {
ruleID := "G101" ruleID := "G101"
cwe := gosec.GetCweByRule(ruleID) cwe := issue.GetCweByRule(ruleID)
code := "68: \t\t}\n69: \t\tvar data = template.HTML(v.TmplFile)\n70: \t\tisTmpl := true\n" code := "68: \t\t}\n69: \t\tvar data = template.HTML(v.TmplFile)\n70: \t\tisTmpl := true\n"
expectedCode := "var data = template.HTML(v.TmplFile)" expectedCode := "var data = template.HTML(v.TmplFile)"
issue := gosec.Issue{ newissue := issue.Issue{
File: "/home/src/project/test.go", File: "/home/src/project/test.go",
Line: "69", Line: "69",
Col: "14", Col: "14",
RuleID: ruleID, RuleID: ruleID,
What: "test", What: "test",
Confidence: gosec.High, Confidence: issue.High,
Severity: gosec.High, Severity: issue.High,
Code: code, Code: code,
Cwe: cwe, Cwe: cwe,
Suppressions: []gosec.SuppressionInfo{ Suppressions: []issue.SuppressionInfo{
{ {
Kind: "kind", Kind: "kind",
Justification: "justification", Justification: "justification",
}, },
}, },
} }
reportInfo := gosec.NewReportInfo([]*gosec.Issue{&issue}, &gosec.Metrics{}, map[string][]gosec.Error{}).WithVersion("v2.7.0") reportInfo := gosec.NewReportInfo([]*issue.Issue{&newissue}, &gosec.Metrics{}, map[string][]gosec.Error{}).WithVersion("v2.7.0")
sarifReport, err := sarif.GenerateReport([]string{}, reportInfo) sarifReport, err := sarif.GenerateReport([]string{}, reportInfo)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
Expect(sarifReport.Runs[0].Results[0].Locations[0].PhysicalLocation.Region.Snippet.Text).Should(Equal(expectedCode)) Expect(sarifReport.Runs[0].Results[0].Locations[0].PhysicalLocation.Region.Snippet.Text).Should(Equal(expectedCode))
}) })
It("sarif formatted report should contain the formatted multiple line code snippet", func() { It("sarif formatted report should contain the formatted multiple line code snippet", func() {
ruleID := "G101" ruleID := "G101"
cwe := gosec.GetCweByRule(ruleID) cwe := issue.GetCweByRule(ruleID)
code := "68: }\n69: var data = template.HTML(v.TmplFile)\n70: isTmpl := true\n" code := "68: }\n69: var data = template.HTML(v.TmplFile)\n70: isTmpl := true\n"
expectedCode := "var data = template.HTML(v.TmplFile)\nisTmpl := true\n" expectedCode := "var data = template.HTML(v.TmplFile)\nisTmpl := true\n"
issue := gosec.Issue{ newissue := issue.Issue{
File: "/home/src/project/test.go", File: "/home/src/project/test.go",
Line: "69-70", Line: "69-70",
Col: "14", Col: "14",
RuleID: ruleID, RuleID: ruleID,
What: "test", What: "test",
Confidence: gosec.High, Confidence: issue.High,
Severity: gosec.High, Severity: issue.High,
Code: code, Code: code,
Cwe: cwe, Cwe: cwe,
Suppressions: []gosec.SuppressionInfo{ Suppressions: []issue.SuppressionInfo{
{ {
Kind: "kind", Kind: "kind",
Justification: "justification", Justification: "justification",
}, },
}, },
} }
reportInfo := gosec.NewReportInfo([]*gosec.Issue{&issue}, &gosec.Metrics{}, map[string][]gosec.Error{}).WithVersion("v2.7.0") reportInfo := gosec.NewReportInfo([]*issue.Issue{&newissue}, &gosec.Metrics{}, map[string][]gosec.Error{}).WithVersion("v2.7.0")
sarifReport, err := sarif.GenerateReport([]string{}, reportInfo) sarifReport, err := sarif.GenerateReport([]string{}, reportInfo)
Expect(err).ShouldNot(HaveOccurred()) Expect(err).ShouldNot(HaveOccurred())
Expect(sarifReport.Runs[0].Results[0].Locations[0].PhysicalLocation.Region.Snippet.Text).Should(Equal(expectedCode)) Expect(sarifReport.Runs[0].Results[0].Locations[0].PhysicalLocation.Region.Snippet.Text).Should(Equal(expectedCode))

View file

@ -5,6 +5,7 @@ import (
"strings" "strings"
"github.com/securego/gosec/v2" "github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
) )
const ( const (
@ -36,7 +37,7 @@ func GenerateReport(rootPaths []string, data *gosec.ReportInfo) (*Report, error)
return si, nil return si, nil
} }
func parseFilePath(issue *gosec.Issue, rootPaths []string) string { func parseFilePath(issue *issue.Issue, rootPaths []string) string {
var sonarFilePath string var sonarFilePath string
for _, rootPath := range rootPaths { for _, rootPath := range rootPaths {
if strings.HasPrefix(issue.File, rootPath) { if strings.HasPrefix(issue.File, rootPath) {
@ -46,7 +47,7 @@ func parseFilePath(issue *gosec.Issue, rootPaths []string) string {
return sonarFilePath return sonarFilePath
} }
func parseTextRange(issue *gosec.Issue) (*TextRange, error) { func parseTextRange(issue *issue.Issue) (*TextRange, error) {
lines := strings.Split(issue.Line, "-") lines := strings.Split(issue.Line, "-")
startLine, err := strconv.Atoi(lines[0]) startLine, err := strconv.Atoi(lines[0])
if err != nil { if err != nil {

View file

@ -4,6 +4,7 @@ import (
. "github.com/onsi/ginkgo/v2" . "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"github.com/securego/gosec/v2" "github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
"github.com/securego/gosec/v2/report/sonar" "github.com/securego/gosec/v2/report/sonar"
) )
@ -14,7 +15,7 @@ var _ = Describe("Sonar Formatter", func() {
It("it should parse the report info", func() { It("it should parse the report info", func() {
data := &gosec.ReportInfo{ data := &gosec.ReportInfo{
Errors: map[string][]gosec.Error{}, Errors: map[string][]gosec.Error{},
Issues: []*gosec.Issue{ Issues: []*issue.Issue{
{ {
Severity: 2, Severity: 2,
Confidence: 0, Confidence: 0,
@ -62,7 +63,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 := &gosec.ReportInfo{ data := &gosec.ReportInfo{
Errors: map[string][]gosec.Error{}, Errors: map[string][]gosec.Error{},
Issues: []*gosec.Issue{ Issues: []*issue.Issue{
{ {
Severity: 2, Severity: 2,
Confidence: 0, Confidence: 0,
@ -109,7 +110,7 @@ var _ = Describe("Sonar Formatter", func() {
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 := &gosec.ReportInfo{ data := &gosec.ReportInfo{
Errors: map[string][]gosec.Error{}, Errors: map[string][]gosec.Error{},
Issues: []*gosec.Issue{ Issues: []*issue.Issue{
{ {
Severity: 2, Severity: 2,
Confidence: 0, Confidence: 0,
@ -141,7 +142,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 := &gosec.ReportInfo{ data := &gosec.ReportInfo{
Errors: map[string][]gosec.Error{}, Errors: map[string][]gosec.Error{},
Issues: []*gosec.Issue{ Issues: []*issue.Issue{
{ {
Severity: 2, Severity: 2,
Confidence: 0, Confidence: 0,

View file

@ -12,6 +12,7 @@ import (
"github.com/gookit/color" "github.com/gookit/color"
"github.com/securego/gosec/v2" "github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
) )
var ( var (
@ -49,7 +50,7 @@ func plainTextFuncMap(enableColor bool) template.FuncMap {
// by default those functions return the given content untouched // by default those functions return the given content untouched
return template.FuncMap{ return template.FuncMap{
"highlight": func(t string, s gosec.Score, ignored bool) string { "highlight": func(t string, s issue.Score, ignored bool) string {
return t return t
}, },
"danger": fmt.Sprint, "danger": fmt.Sprint,
@ -60,14 +61,14 @@ func plainTextFuncMap(enableColor bool) template.FuncMap {
} }
// highlight returns content t colored based on Score // highlight returns content t colored based on Score
func highlight(t string, s gosec.Score, ignored bool) string { func highlight(t string, s issue.Score, ignored bool) string {
if ignored { if ignored {
return defaultTheme.Sprint(t) return defaultTheme.Sprint(t)
} }
switch s { switch s {
case gosec.High: case issue.High:
return errorTheme.Sprint(t) return errorTheme.Sprint(t)
case gosec.Medium: case issue.Medium:
return warningTheme.Sprint(t) return warningTheme.Sprint(t)
default: default:
return defaultTheme.Sprint(t) return defaultTheme.Sprint(t)
@ -75,7 +76,7 @@ func highlight(t string, s gosec.Score, ignored bool) string {
} }
// printCodeSnippet prints the code snippet from the issue by adding a marker to the affected line // printCodeSnippet prints the code snippet from the issue by adding a marker to the affected line
func printCodeSnippet(issue *gosec.Issue) string { func printCodeSnippet(issue *issue.Issue) string {
start, end := parseLine(issue.Line) start, end := parseLine(issue.Line)
scanner := bufio.NewScanner(strings.NewReader(issue.Code)) scanner := bufio.NewScanner(strings.NewReader(issue.Code))
var buf bytes.Buffer var buf bytes.Buffer

View file

@ -15,12 +15,14 @@ package gosec
import ( import (
"go/ast" "go/ast"
"reflect" "reflect"
"github.com/securego/gosec/v2/issue"
) )
// The Rule interface used by all rules supported by gosec. // The Rule interface used by all rules supported by gosec.
type Rule interface { type Rule interface {
ID() string ID() string
Match(ast.Node, *Context) (*Issue, error) Match(ast.Node, *Context) (*issue.Issue, error)
} }
// RuleBuilder is used to register a rule definition with the analyzer // RuleBuilder is used to register a rule definition with the analyzer

View file

@ -7,10 +7,11 @@ import (
. "github.com/onsi/ginkgo/v2" . "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"github.com/securego/gosec/v2" "github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
) )
type mockrule struct { type mockrule struct {
issue *gosec.Issue issue *issue.Issue
err error err error
callback func(n ast.Node, ctx *gosec.Context) bool callback func(n ast.Node, ctx *gosec.Context) bool
} }
@ -19,7 +20,7 @@ func (m *mockrule) ID() string {
return "MOCK" return "MOCK"
} }
func (m *mockrule) Match(n ast.Node, ctx *gosec.Context) (*gosec.Issue, error) { func (m *mockrule) Match(n ast.Node, ctx *gosec.Context) (*issue.Issue, error) {
if m.callback(n, ctx) { if m.callback(n, ctx) {
return m.issue, nil return m.issue, nil
} }
@ -42,9 +43,9 @@ var _ = Describe("Rule", func() {
callback: func(n ast.Node, ctx *gosec.Context) bool { return false }, callback: func(n ast.Node, ctx *gosec.Context) bool { return false },
} }
dummyIssueRule = &mockrule{ dummyIssueRule = &mockrule{
issue: &gosec.Issue{ issue: &issue.Issue{
Severity: gosec.High, Severity: issue.High,
Confidence: gosec.High, Confidence: issue.High,
What: `Some explanation of the thing`, What: `Some explanation of the thing`,
File: "main.go", File: "main.go",
Code: `#include <stdio.h> int main(){ puts("hello world"); }`, Code: `#include <stdio.h> int main(){ puts("hello world"); }`,

View file

@ -5,10 +5,11 @@ import (
"go/types" "go/types"
"github.com/securego/gosec/v2" "github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
) )
type archive struct { type archive struct {
gosec.MetaData issue.MetaData
calls gosec.CallList calls gosec.CallList
argTypes []string argTypes []string
} }
@ -18,7 +19,7 @@ func (a *archive) ID() string {
} }
// Match inspects AST nodes to determine if the filepath.Joins uses any argument derived from type zip.File or tar.Header // Match inspects AST nodes to determine if the filepath.Joins uses any argument derived from type zip.File or tar.Header
func (a *archive) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) { func (a *archive) Match(n ast.Node, c *gosec.Context) (*issue.Issue, error) {
if node := a.calls.ContainsPkgCallExpr(n, c, false); node != nil { if node := a.calls.ContainsPkgCallExpr(n, c, false); node != nil {
for _, arg := range node.Args { for _, arg := range node.Args {
var argType types.Type var argType types.Type
@ -38,7 +39,7 @@ func (a *archive) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
if argType != nil { if argType != nil {
for _, t := range a.argTypes { for _, t := range a.argTypes {
if argType.String() == t { if argType.String() == t {
return gosec.NewIssue(c, n, a.ID(), a.What, a.Severity, a.Confidence), nil return c.NewIssue(n, a.ID(), a.What, a.Severity, a.Confidence), nil
} }
} }
} }
@ -55,10 +56,10 @@ func NewArchive(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
return &archive{ return &archive{
calls: calls, calls: calls,
argTypes: []string{"*archive/zip.File", "*archive/tar.Header"}, argTypes: []string{"*archive/zip.File", "*archive/tar.Header"},
MetaData: gosec.MetaData{ MetaData: issue.MetaData{
ID: id, ID: id,
Severity: gosec.Medium, Severity: issue.Medium,
Confidence: gosec.High, Confidence: issue.High,
What: "File traversal when extracting zip/tar archive", What: "File traversal when extracting zip/tar archive",
}, },
}, []ast.Node{(*ast.CallExpr)(nil)} }, []ast.Node{(*ast.CallExpr)(nil)}

View file

@ -6,6 +6,7 @@ import (
"strings" "strings"
"github.com/securego/gosec/v2" "github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
) )
type deferType struct { type deferType struct {
@ -14,7 +15,7 @@ type deferType struct {
} }
type badDefer struct { type badDefer struct {
gosec.MetaData issue.MetaData
types []deferType types []deferType
} }
@ -35,12 +36,12 @@ func contains(methods []string, method string) bool {
return false return false
} }
func (r *badDefer) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) { func (r *badDefer) Match(n ast.Node, c *gosec.Context) (*issue.Issue, error) {
if deferStmt, ok := n.(*ast.DeferStmt); ok { if deferStmt, ok := n.(*ast.DeferStmt); ok {
for _, deferTyp := range r.types { for _, deferTyp := range r.types {
if typ, method, err := gosec.GetCallInfo(deferStmt.Call, c); err == nil { if typ, method, err := gosec.GetCallInfo(deferStmt.Call, c); err == nil {
if normalize(typ) == deferTyp.typ && contains(deferTyp.methods, method) { if normalize(typ) == deferTyp.typ && contains(deferTyp.methods, method) {
return gosec.NewIssue(c, n, r.ID(), fmt.Sprintf(r.What, method, typ), r.Severity, r.Confidence), nil return c.NewIssue(n, r.ID(), fmt.Sprintf(r.What, method, typ), r.Severity, r.Confidence), nil
} }
} }
} }
@ -86,10 +87,10 @@ func NewDeferredClosing(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
methods: []string{"Close"}, methods: []string{"Close"},
}, },
}, },
MetaData: gosec.MetaData{ MetaData: issue.MetaData{
ID: id, ID: id,
Severity: gosec.Medium, Severity: issue.Medium,
Confidence: gosec.High, Confidence: issue.High,
What: "Deferring unsafe method %q on type %q", What: "Deferring unsafe method %q on type %q",
}, },
}, []ast.Node{(*ast.DeferStmt)(nil)} }, []ast.Node{(*ast.DeferStmt)(nil)}

View file

@ -19,11 +19,12 @@ import (
"regexp" "regexp"
"github.com/securego/gosec/v2" "github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
) )
// Looks for net.Listen("0.0.0.0") or net.Listen(":8080") // Looks for net.Listen("0.0.0.0") or net.Listen(":8080")
type bindsToAllNetworkInterfaces struct { type bindsToAllNetworkInterfaces struct {
gosec.MetaData issue.MetaData
calls gosec.CallList calls gosec.CallList
pattern *regexp.Regexp pattern *regexp.Regexp
} }
@ -32,7 +33,7 @@ func (r *bindsToAllNetworkInterfaces) ID() string {
return r.MetaData.ID return r.MetaData.ID
} }
func (r *bindsToAllNetworkInterfaces) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) { func (r *bindsToAllNetworkInterfaces) Match(n ast.Node, c *gosec.Context) (*issue.Issue, error) {
callExpr := r.calls.ContainsPkgCallExpr(n, c, false) callExpr := r.calls.ContainsPkgCallExpr(n, c, false)
if callExpr == nil { if callExpr == nil {
return nil, nil return nil, nil
@ -42,14 +43,14 @@ func (r *bindsToAllNetworkInterfaces) Match(n ast.Node, c *gosec.Context) (*gose
if bl, ok := arg.(*ast.BasicLit); ok { if bl, ok := arg.(*ast.BasicLit); ok {
if arg, err := gosec.GetString(bl); err == nil { if arg, err := gosec.GetString(bl); err == nil {
if r.pattern.MatchString(arg) { if r.pattern.MatchString(arg) {
return gosec.NewIssue(c, n, r.ID(), r.What, r.Severity, r.Confidence), nil return c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence), nil
} }
} }
} else if ident, ok := arg.(*ast.Ident); ok { } else if ident, ok := arg.(*ast.Ident); ok {
values := gosec.GetIdentStringValues(ident) values := gosec.GetIdentStringValues(ident)
for _, value := range values { for _, value := range values {
if r.pattern.MatchString(value) { if r.pattern.MatchString(value) {
return gosec.NewIssue(c, n, r.ID(), r.What, r.Severity, r.Confidence), nil return c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence), nil
} }
} }
} }
@ -57,7 +58,7 @@ func (r *bindsToAllNetworkInterfaces) Match(n ast.Node, c *gosec.Context) (*gose
values := gosec.GetCallStringArgsValues(callExpr.Args[0], c) values := gosec.GetCallStringArgsValues(callExpr.Args[0], c)
for _, value := range values { for _, value := range values {
if r.pattern.MatchString(value) { if r.pattern.MatchString(value) {
return gosec.NewIssue(c, n, r.ID(), r.What, r.Severity, r.Confidence), nil return c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence), nil
} }
} }
} }
@ -73,10 +74,10 @@ func NewBindsToAllNetworkInterfaces(id string, conf gosec.Config) (gosec.Rule, [
return &bindsToAllNetworkInterfaces{ return &bindsToAllNetworkInterfaces{
calls: calls, calls: calls,
pattern: regexp.MustCompile(`^(0.0.0.0|:).*$`), pattern: regexp.MustCompile(`^(0.0.0.0|:).*$`),
MetaData: gosec.MetaData{ MetaData: issue.MetaData{
ID: id, ID: id,
Severity: gosec.Medium, Severity: issue.Medium,
Confidence: gosec.High, Confidence: issue.High,
What: "Binds to all network interfaces", What: "Binds to all network interfaces",
}, },
}, []ast.Node{(*ast.CallExpr)(nil)} }, []ast.Node{(*ast.CallExpr)(nil)}

View file

@ -19,10 +19,11 @@ import (
"strings" "strings"
"github.com/securego/gosec/v2" "github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
) )
type blocklistedImport struct { type blocklistedImport struct {
gosec.MetaData issue.MetaData
Blocklisted map[string]string Blocklisted map[string]string
} }
@ -36,10 +37,10 @@ func (r *blocklistedImport) ID() string {
return r.MetaData.ID return r.MetaData.ID
} }
func (r *blocklistedImport) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) { func (r *blocklistedImport) Match(n ast.Node, c *gosec.Context) (*issue.Issue, error) {
if node, ok := n.(*ast.ImportSpec); ok { if node, ok := n.(*ast.ImportSpec); ok {
if description, ok := r.Blocklisted[unquote(node.Path.Value)]; ok { if description, ok := r.Blocklisted[unquote(node.Path.Value)]; ok {
return gosec.NewIssue(c, node, r.ID(), description, r.Severity, r.Confidence), nil return c.NewIssue(node, r.ID(), description, r.Severity, r.Confidence), nil
} }
} }
return nil, nil return nil, nil
@ -49,10 +50,10 @@ func (r *blocklistedImport) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, e
// Typically when a deprecated technology is being used. // Typically when a deprecated technology is being used.
func NewBlocklistedImports(id string, conf gosec.Config, blocklist map[string]string) (gosec.Rule, []ast.Node) { func NewBlocklistedImports(id string, conf gosec.Config, blocklist map[string]string) (gosec.Rule, []ast.Node) {
return &blocklistedImport{ return &blocklistedImport{
MetaData: gosec.MetaData{ MetaData: issue.MetaData{
ID: id, ID: id,
Severity: gosec.Medium, Severity: issue.Medium,
Confidence: gosec.High, Confidence: issue.High,
}, },
Blocklisted: blocklist, Blocklisted: blocklist,
}, []ast.Node{(*ast.ImportSpec)(nil)} }, []ast.Node{(*ast.ImportSpec)(nil)}

View file

@ -19,10 +19,11 @@ import (
"go/ast" "go/ast"
"github.com/securego/gosec/v2" "github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
) )
type decompressionBombCheck struct { type decompressionBombCheck struct {
gosec.MetaData issue.MetaData
readerCalls gosec.CallList readerCalls gosec.CallList
copyCalls gosec.CallList copyCalls gosec.CallList
} }
@ -40,7 +41,7 @@ func containsReaderCall(node ast.Node, ctx *gosec.Context, list gosec.CallList)
return list.Contains(s, idt) return list.Contains(s, idt)
} }
func (d *decompressionBombCheck) Match(node ast.Node, ctx *gosec.Context) (*gosec.Issue, error) { func (d *decompressionBombCheck) Match(node ast.Node, ctx *gosec.Context) (*issue.Issue, error) {
var readerVarObj map[*ast.Object]struct{} var readerVarObj map[*ast.Object]struct{}
// To check multiple lines, ctx.PassedValues is used to store temporary data. // To check multiple lines, ctx.PassedValues is used to store temporary data.
@ -72,7 +73,7 @@ func (d *decompressionBombCheck) Match(node ast.Node, ctx *gosec.Context) (*gose
if idt, ok := n.Args[1].(*ast.Ident); ok { if idt, ok := n.Args[1].(*ast.Ident); ok {
if _, ok := readerVarObj[idt.Obj]; ok { if _, ok := readerVarObj[idt.Obj]; ok {
// Detect io.Copy(x, r) // Detect io.Copy(x, r)
return gosec.NewIssue(ctx, n, d.ID(), d.What, d.Severity, d.Confidence), nil return ctx.NewIssue(n, d.ID(), d.What, d.Severity, d.Confidence), nil
} }
} }
} }
@ -98,10 +99,10 @@ func NewDecompressionBombCheck(id string, conf gosec.Config) (gosec.Rule, []ast.
copyCalls.Add("io", "CopyBuffer") copyCalls.Add("io", "CopyBuffer")
return &decompressionBombCheck{ return &decompressionBombCheck{
MetaData: gosec.MetaData{ MetaData: issue.MetaData{
ID: id, ID: id,
Severity: gosec.Medium, Severity: issue.Medium,
Confidence: gosec.Medium, Confidence: issue.Medium,
What: "Potential DoS vulnerability via decompression bomb", What: "Potential DoS vulnerability via decompression bomb",
}, },
readerCalls: readerCalls, readerCalls: readerCalls,

View file

@ -5,18 +5,19 @@ import (
"regexp" "regexp"
"github.com/securego/gosec/v2" "github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
) )
type traversal struct { type traversal struct {
pattern *regexp.Regexp pattern *regexp.Regexp
gosec.MetaData issue.MetaData
} }
func (r *traversal) ID() string { func (r *traversal) ID() string {
return r.MetaData.ID return r.MetaData.ID
} }
func (r *traversal) Match(n ast.Node, ctx *gosec.Context) (*gosec.Issue, error) { func (r *traversal) Match(n ast.Node, ctx *gosec.Context) (*issue.Issue, error) {
switch node := n.(type) { switch node := n.(type) {
case *ast.CallExpr: case *ast.CallExpr:
return r.matchCallExpr(node, ctx) return r.matchCallExpr(node, ctx)
@ -24,14 +25,14 @@ func (r *traversal) Match(n ast.Node, ctx *gosec.Context) (*gosec.Issue, error)
return nil, nil return nil, nil
} }
func (r *traversal) matchCallExpr(assign *ast.CallExpr, ctx *gosec.Context) (*gosec.Issue, error) { func (r *traversal) matchCallExpr(assign *ast.CallExpr, ctx *gosec.Context) (*issue.Issue, error) {
for _, i := range assign.Args { for _, i := range assign.Args {
if basiclit, ok1 := i.(*ast.BasicLit); ok1 { if basiclit, ok1 := i.(*ast.BasicLit); ok1 {
if fun, ok2 := assign.Fun.(*ast.SelectorExpr); ok2 { if fun, ok2 := assign.Fun.(*ast.SelectorExpr); ok2 {
if x, ok3 := fun.X.(*ast.Ident); ok3 { if x, ok3 := fun.X.(*ast.Ident); ok3 {
string := x.Name + "." + fun.Sel.Name + "(" + basiclit.Value + ")" string := x.Name + "." + fun.Sel.Name + "(" + basiclit.Value + ")"
if r.pattern.MatchString(string) { if r.pattern.MatchString(string) {
return gosec.NewIssue(ctx, assign, r.ID(), r.What, r.Severity, r.Confidence), nil return ctx.NewIssue(assign, r.ID(), r.What, r.Severity, r.Confidence), nil
} }
} }
} }
@ -54,11 +55,11 @@ func NewDirectoryTraversal(id string, conf gosec.Config) (gosec.Rule, []ast.Node
return &traversal{ return &traversal{
pattern: regexp.MustCompile(pattern), pattern: regexp.MustCompile(pattern),
MetaData: gosec.MetaData{ MetaData: issue.MetaData{
ID: id, ID: id,
What: "Potential directory traversal", What: "Potential directory traversal",
Confidence: gosec.Medium, Confidence: issue.Medium,
Severity: gosec.Medium, Severity: issue.Medium,
}, },
}, []ast.Node{(*ast.CallExpr)(nil)} }, []ast.Node{(*ast.CallExpr)(nil)}
} }

View file

@ -19,10 +19,11 @@ import (
"go/types" "go/types"
"github.com/securego/gosec/v2" "github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
) )
type noErrorCheck struct { type noErrorCheck struct {
gosec.MetaData issue.MetaData
whitelist gosec.CallList whitelist gosec.CallList
} }
@ -49,7 +50,7 @@ func returnsError(callExpr *ast.CallExpr, ctx *gosec.Context) int {
return -1 return -1
} }
func (r *noErrorCheck) Match(n ast.Node, ctx *gosec.Context) (*gosec.Issue, error) { func (r *noErrorCheck) Match(n ast.Node, ctx *gosec.Context) (*issue.Issue, error) {
switch stmt := n.(type) { switch stmt := n.(type) {
case *ast.AssignStmt: case *ast.AssignStmt:
cfg := ctx.Config cfg := ctx.Config
@ -61,7 +62,7 @@ func (r *noErrorCheck) Match(n ast.Node, ctx *gosec.Context) (*gosec.Issue, erro
return nil, nil return nil, nil
} }
if id, ok := stmt.Lhs[pos].(*ast.Ident); ok && id.Name == "_" { if id, ok := stmt.Lhs[pos].(*ast.Ident); ok && id.Name == "_" {
return gosec.NewIssue(ctx, n, r.ID(), r.What, r.Severity, r.Confidence), nil return ctx.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence), nil
} }
} }
} }
@ -70,7 +71,7 @@ func (r *noErrorCheck) Match(n ast.Node, ctx *gosec.Context) (*gosec.Issue, erro
if callExpr, ok := stmt.X.(*ast.CallExpr); ok && r.whitelist.ContainsCallExpr(stmt.X, ctx) == nil { if callExpr, ok := stmt.X.(*ast.CallExpr); ok && r.whitelist.ContainsCallExpr(stmt.X, ctx) == nil {
pos := returnsError(callExpr, ctx) pos := returnsError(callExpr, ctx)
if pos >= 0 { if pos >= 0 {
return gosec.NewIssue(ctx, n, r.ID(), r.What, r.Severity, r.Confidence), nil return ctx.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence), nil
} }
} }
} }
@ -100,10 +101,10 @@ func NewNoErrorCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
} }
return &noErrorCheck{ return &noErrorCheck{
MetaData: gosec.MetaData{ MetaData: issue.MetaData{
ID: id, ID: id,
Severity: gosec.Low, Severity: issue.Low,
Confidence: gosec.High, Confidence: issue.High,
What: "Errors unhandled.", What: "Errors unhandled.",
}, },
whitelist: whitelist, whitelist: whitelist,

View file

@ -20,10 +20,11 @@ import (
"strconv" "strconv"
"github.com/securego/gosec/v2" "github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
) )
type filePermissions struct { type filePermissions struct {
gosec.MetaData issue.MetaData
mode int64 mode int64
pkgs []string pkgs []string
calls []string calls []string
@ -54,12 +55,12 @@ func modeIsSubset(subset int64, superset int64) bool {
return (subset | superset) == superset return (subset | superset) == superset
} }
func (r *filePermissions) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) { func (r *filePermissions) Match(n ast.Node, c *gosec.Context) (*issue.Issue, error) {
for _, pkg := range r.pkgs { for _, pkg := range r.pkgs {
if callexpr, matched := gosec.MatchCallByPackage(n, c, pkg, r.calls...); matched { if callexpr, matched := gosec.MatchCallByPackage(n, c, pkg, r.calls...); matched {
modeArg := callexpr.Args[len(callexpr.Args)-1] modeArg := callexpr.Args[len(callexpr.Args)-1]
if mode, err := gosec.GetInt(modeArg); err == nil && !modeIsSubset(mode, r.mode) { if mode, err := gosec.GetInt(modeArg); err == nil && !modeIsSubset(mode, r.mode) {
return gosec.NewIssue(c, n, r.ID(), r.What, r.Severity, r.Confidence), nil return c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence), nil
} }
} }
} }
@ -73,10 +74,10 @@ func NewWritePerms(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
mode: mode, mode: mode,
pkgs: []string{"io/ioutil", "os"}, pkgs: []string{"io/ioutil", "os"},
calls: []string{"WriteFile"}, calls: []string{"WriteFile"},
MetaData: gosec.MetaData{ MetaData: issue.MetaData{
ID: id, ID: id,
Severity: gosec.Medium, Severity: issue.Medium,
Confidence: gosec.High, Confidence: issue.High,
What: fmt.Sprintf("Expect WriteFile permissions to be %#o or less", mode), What: fmt.Sprintf("Expect WriteFile permissions to be %#o or less", mode),
}, },
}, []ast.Node{(*ast.CallExpr)(nil)} }, []ast.Node{(*ast.CallExpr)(nil)}
@ -90,10 +91,10 @@ func NewFilePerms(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
mode: mode, mode: mode,
pkgs: []string{"os"}, pkgs: []string{"os"},
calls: []string{"OpenFile", "Chmod"}, calls: []string{"OpenFile", "Chmod"},
MetaData: gosec.MetaData{ MetaData: issue.MetaData{
ID: id, ID: id,
Severity: gosec.Medium, Severity: issue.Medium,
Confidence: gosec.High, Confidence: issue.High,
What: fmt.Sprintf("Expect file permissions to be %#o or less", mode), What: fmt.Sprintf("Expect file permissions to be %#o or less", mode),
}, },
}, []ast.Node{(*ast.CallExpr)(nil)} }, []ast.Node{(*ast.CallExpr)(nil)}
@ -107,10 +108,10 @@ func NewMkdirPerms(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
mode: mode, mode: mode,
pkgs: []string{"os"}, pkgs: []string{"os"},
calls: []string{"Mkdir", "MkdirAll"}, calls: []string{"Mkdir", "MkdirAll"},
MetaData: gosec.MetaData{ MetaData: issue.MetaData{
ID: id, ID: id,
Severity: gosec.Medium, Severity: issue.Medium,
Confidence: gosec.High, Confidence: issue.High,
What: fmt.Sprintf("Expect directory permissions to be %#o or less", mode), What: fmt.Sprintf("Expect directory permissions to be %#o or less", mode),
}, },
}, []ast.Node{(*ast.CallExpr)(nil)} }, []ast.Node{(*ast.CallExpr)(nil)}

View file

@ -22,10 +22,11 @@ import (
zxcvbn "github.com/nbutton23/zxcvbn-go" zxcvbn "github.com/nbutton23/zxcvbn-go"
"github.com/securego/gosec/v2" "github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
) )
type credentials struct { type credentials struct {
gosec.MetaData issue.MetaData
pattern *regexp.Regexp pattern *regexp.Regexp
entropyThreshold float64 entropyThreshold float64
perCharThreshold float64 perCharThreshold float64
@ -53,7 +54,7 @@ func (r *credentials) isHighEntropyString(str string) bool {
entropyPerChar >= r.perCharThreshold)) entropyPerChar >= r.perCharThreshold))
} }
func (r *credentials) Match(n ast.Node, ctx *gosec.Context) (*gosec.Issue, error) { func (r *credentials) Match(n ast.Node, ctx *gosec.Context) (*issue.Issue, error) {
switch node := n.(type) { switch node := n.(type) {
case *ast.AssignStmt: case *ast.AssignStmt:
return r.matchAssign(node, ctx) return r.matchAssign(node, ctx)
@ -65,14 +66,14 @@ func (r *credentials) Match(n ast.Node, ctx *gosec.Context) (*gosec.Issue, error
return nil, nil return nil, nil
} }
func (r *credentials) matchAssign(assign *ast.AssignStmt, ctx *gosec.Context) (*gosec.Issue, error) { func (r *credentials) matchAssign(assign *ast.AssignStmt, ctx *gosec.Context) (*issue.Issue, error) {
for _, i := range assign.Lhs { for _, i := range assign.Lhs {
if ident, ok := i.(*ast.Ident); ok { if ident, ok := i.(*ast.Ident); ok {
if r.pattern.MatchString(ident.Name) { if r.pattern.MatchString(ident.Name) {
for _, e := range assign.Rhs { for _, e := range assign.Rhs {
if val, err := gosec.GetString(e); err == nil { if val, err := gosec.GetString(e); err == nil {
if r.ignoreEntropy || (!r.ignoreEntropy && r.isHighEntropyString(val)) { if r.ignoreEntropy || (!r.ignoreEntropy && r.isHighEntropyString(val)) {
return gosec.NewIssue(ctx, assign, r.ID(), r.What, r.Severity, r.Confidence), nil return ctx.NewIssue(assign, r.ID(), r.What, r.Severity, r.Confidence), nil
} }
} }
} }
@ -82,7 +83,7 @@ func (r *credentials) matchAssign(assign *ast.AssignStmt, ctx *gosec.Context) (*
return nil, nil return nil, nil
} }
func (r *credentials) matchValueSpec(valueSpec *ast.ValueSpec, ctx *gosec.Context) (*gosec.Issue, error) { func (r *credentials) matchValueSpec(valueSpec *ast.ValueSpec, ctx *gosec.Context) (*issue.Issue, error) {
for index, ident := range valueSpec.Names { for index, ident := range valueSpec.Names {
if r.pattern.MatchString(ident.Name) && valueSpec.Values != nil { if r.pattern.MatchString(ident.Name) && valueSpec.Values != nil {
// const foo, bar = "same value" // const foo, bar = "same value"
@ -91,7 +92,7 @@ func (r *credentials) matchValueSpec(valueSpec *ast.ValueSpec, ctx *gosec.Contex
} }
if val, err := gosec.GetString(valueSpec.Values[index]); err == nil { if val, err := gosec.GetString(valueSpec.Values[index]); err == nil {
if r.ignoreEntropy || (!r.ignoreEntropy && r.isHighEntropyString(val)) { if r.ignoreEntropy || (!r.ignoreEntropy && r.isHighEntropyString(val)) {
return gosec.NewIssue(ctx, valueSpec, r.ID(), r.What, r.Severity, r.Confidence), nil return ctx.NewIssue(valueSpec, r.ID(), r.What, r.Severity, r.Confidence), nil
} }
} }
} }
@ -99,7 +100,7 @@ func (r *credentials) matchValueSpec(valueSpec *ast.ValueSpec, ctx *gosec.Contex
return nil, nil return nil, nil
} }
func (r *credentials) matchEqualityCheck(binaryExpr *ast.BinaryExpr, ctx *gosec.Context) (*gosec.Issue, error) { func (r *credentials) matchEqualityCheck(binaryExpr *ast.BinaryExpr, ctx *gosec.Context) (*issue.Issue, error) {
if binaryExpr.Op == token.EQL || binaryExpr.Op == token.NEQ { if binaryExpr.Op == token.EQL || binaryExpr.Op == token.NEQ {
ident, ok := binaryExpr.X.(*ast.Ident) ident, ok := binaryExpr.X.(*ast.Ident)
if !ok { if !ok {
@ -113,7 +114,7 @@ func (r *credentials) matchEqualityCheck(binaryExpr *ast.BinaryExpr, ctx *gosec.
} }
if val, err := gosec.GetString(valueNode); err == nil { if val, err := gosec.GetString(valueNode); err == nil {
if r.ignoreEntropy || (!r.ignoreEntropy && r.isHighEntropyString(val)) { if r.ignoreEntropy || (!r.ignoreEntropy && r.isHighEntropyString(val)) {
return gosec.NewIssue(ctx, binaryExpr, r.ID(), r.What, r.Severity, r.Confidence), nil return ctx.NewIssue(binaryExpr, r.ID(), r.What, r.Severity, r.Confidence), nil
} }
} }
} }
@ -170,11 +171,11 @@ func NewHardcodedCredentials(id string, conf gosec.Config) (gosec.Rule, []ast.No
perCharThreshold: perCharThreshold, perCharThreshold: perCharThreshold,
ignoreEntropy: ignoreEntropy, ignoreEntropy: ignoreEntropy,
truncate: truncateString, truncate: truncateString,
MetaData: gosec.MetaData{ MetaData: issue.MetaData{
ID: id, ID: id,
What: "Potential hardcoded credentials", What: "Potential hardcoded credentials",
Confidence: gosec.Low, Confidence: issue.Low,
Severity: gosec.High, Severity: issue.High,
}, },
}, []ast.Node{(*ast.AssignStmt)(nil), (*ast.ValueSpec)(nil), (*ast.BinaryExpr)(nil)} }, []ast.Node{(*ast.AssignStmt)(nil), (*ast.ValueSpec)(nil), (*ast.BinaryExpr)(nil)}
} }

View file

@ -4,10 +4,11 @@ import (
"go/ast" "go/ast"
"github.com/securego/gosec/v2" "github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
) )
type httpServeWithoutTimeouts struct { type httpServeWithoutTimeouts struct {
gosec.MetaData issue.MetaData
pkg string pkg string
calls []string calls []string
} }
@ -16,9 +17,9 @@ func (r *httpServeWithoutTimeouts) ID() string {
return r.MetaData.ID return r.MetaData.ID
} }
func (r *httpServeWithoutTimeouts) Match(n ast.Node, c *gosec.Context) (gi *gosec.Issue, err error) { func (r *httpServeWithoutTimeouts) Match(n ast.Node, c *gosec.Context) (gi *issue.Issue, err error) {
if _, matches := gosec.MatchCallByPackage(n, c, r.pkg, r.calls...); matches { if _, matches := gosec.MatchCallByPackage(n, c, r.pkg, r.calls...); matches {
return gosec.NewIssue(c, n, r.ID(), r.What, r.Severity, r.Confidence), nil return c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence), nil
} }
return nil, nil return nil, nil
} }
@ -28,11 +29,11 @@ func NewHTTPServeWithoutTimeouts(id string, conf gosec.Config) (gosec.Rule, []as
return &httpServeWithoutTimeouts{ return &httpServeWithoutTimeouts{
pkg: "net/http", pkg: "net/http",
calls: []string{"ListenAndServe", "ListenAndServeTLS", "Serve", "ServeTLS"}, calls: []string{"ListenAndServe", "ListenAndServeTLS", "Serve", "ServeTLS"},
MetaData: gosec.MetaData{ MetaData: issue.MetaData{
ID: id, ID: id,
What: "Use of net/http serve function that has no support for setting timeouts", What: "Use of net/http serve function that has no support for setting timeouts",
Severity: gosec.Medium, Severity: issue.Medium,
Confidence: gosec.High, Confidence: issue.High,
}, },
}, []ast.Node{(*ast.CallExpr)(nil)} }, []ast.Node{(*ast.CallExpr)(nil)}
} }

View file

@ -5,10 +5,11 @@ import (
"go/token" "go/token"
"github.com/securego/gosec/v2" "github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
) )
type implicitAliasing struct { type implicitAliasing struct {
gosec.MetaData issue.MetaData
aliases map[*ast.Object]struct{} aliases map[*ast.Object]struct{}
rightBrace token.Pos rightBrace token.Pos
acceptableAlias []*ast.UnaryExpr acceptableAlias []*ast.UnaryExpr
@ -27,7 +28,7 @@ func containsUnary(exprs []*ast.UnaryExpr, expr *ast.UnaryExpr) bool {
return false return false
} }
func (r *implicitAliasing) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) { func (r *implicitAliasing) Match(n ast.Node, c *gosec.Context) (*issue.Issue, error) {
switch node := n.(type) { switch node := n.(type) {
case *ast.RangeStmt: case *ast.RangeStmt:
// When presented with a range statement, get the underlying Object bound to // When presented with a range statement, get the underlying Object bound to
@ -73,7 +74,7 @@ func (r *implicitAliasing) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, er
// If we find a unary op of & (reference) of an object within r.aliases, complain. // If we find a unary op of & (reference) of an object within r.aliases, complain.
if ident, ok := node.X.(*ast.Ident); ok && node.Op.String() == "&" { if ident, ok := node.X.(*ast.Ident); ok && node.Op.String() == "&" {
if _, contains := r.aliases[ident.Obj]; contains { if _, contains := r.aliases[ident.Obj]; contains {
return gosec.NewIssue(c, n, r.ID(), r.What, r.Severity, r.Confidence), nil return c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence), nil
} }
} }
case *ast.ReturnStmt: case *ast.ReturnStmt:
@ -94,10 +95,10 @@ func NewImplicitAliasing(id string, conf gosec.Config) (gosec.Rule, []ast.Node)
aliases: make(map[*ast.Object]struct{}), aliases: make(map[*ast.Object]struct{}),
rightBrace: token.NoPos, rightBrace: token.NoPos,
acceptableAlias: make([]*ast.UnaryExpr, 0), acceptableAlias: make([]*ast.UnaryExpr, 0),
MetaData: gosec.MetaData{ MetaData: issue.MetaData{
ID: id, ID: id,
Severity: gosec.Medium, Severity: issue.Medium,
Confidence: gosec.Medium, Confidence: issue.Medium,
What: "Implicit memory aliasing in for loop.", What: "Implicit memory aliasing in for loop.",
}, },
}, []ast.Node{(*ast.RangeStmt)(nil), (*ast.UnaryExpr)(nil), (*ast.ReturnStmt)(nil)} }, []ast.Node{(*ast.RangeStmt)(nil), (*ast.UnaryExpr)(nil), (*ast.ReturnStmt)(nil)}

View file

@ -19,10 +19,11 @@ import (
"go/ast" "go/ast"
"github.com/securego/gosec/v2" "github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
) )
type integerOverflowCheck struct { type integerOverflowCheck struct {
gosec.MetaData issue.MetaData
calls gosec.CallList calls gosec.CallList
} }
@ -30,7 +31,7 @@ func (i *integerOverflowCheck) ID() string {
return i.MetaData.ID return i.MetaData.ID
} }
func (i *integerOverflowCheck) Match(node ast.Node, ctx *gosec.Context) (*gosec.Issue, error) { func (i *integerOverflowCheck) Match(node ast.Node, ctx *gosec.Context) (*issue.Issue, error) {
var atoiVarObj map[*ast.Object]ast.Node var atoiVarObj map[*ast.Object]ast.Node
// To check multiple lines, ctx.PassedValues is used to store temporary data. // To check multiple lines, ctx.PassedValues is used to store temporary data.
@ -63,7 +64,7 @@ func (i *integerOverflowCheck) Match(node ast.Node, ctx *gosec.Context) (*gosec.
if idt, ok := n.Args[0].(*ast.Ident); ok { if idt, ok := n.Args[0].(*ast.Ident); ok {
if _, ok := atoiVarObj[idt.Obj]; ok { if _, ok := atoiVarObj[idt.Obj]; ok {
// Detect int32(v) and int16(v) // Detect int32(v) and int16(v)
return gosec.NewIssue(ctx, n, i.ID(), i.What, i.Severity, i.Confidence), nil return ctx.NewIssue(n, i.ID(), i.What, i.Severity, i.Confidence), nil
} }
} }
} }
@ -78,10 +79,10 @@ func NewIntegerOverflowCheck(id string, conf gosec.Config) (gosec.Rule, []ast.No
calls := gosec.NewCallList() calls := gosec.NewCallList()
calls.Add("strconv", "Atoi") calls.Add("strconv", "Atoi")
return &integerOverflowCheck{ return &integerOverflowCheck{
MetaData: gosec.MetaData{ MetaData: issue.MetaData{
ID: id, ID: id,
Severity: gosec.High, Severity: issue.High,
Confidence: gosec.Medium, Confidence: issue.Medium,
What: "Potential Integer overflow made by strconv.Atoi result conversion to int16/32", What: "Potential Integer overflow made by strconv.Atoi result conversion to int16/32",
}, },
calls: calls, calls: calls,

View file

@ -4,10 +4,11 @@ import (
"go/ast" "go/ast"
"github.com/securego/gosec/v2" "github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
) )
type usingOldMathBig struct { type usingOldMathBig struct {
gosec.MetaData issue.MetaData
calls gosec.CallList calls gosec.CallList
} }
@ -15,18 +16,18 @@ func (r *usingOldMathBig) ID() string {
return r.MetaData.ID return r.MetaData.ID
} }
func (r *usingOldMathBig) Match(node ast.Node, ctx *gosec.Context) (gi *gosec.Issue, err error) { func (r *usingOldMathBig) Match(node ast.Node, ctx *gosec.Context) (gi *issue.Issue, err error) {
if callExpr := r.calls.ContainsPkgCallExpr(node, ctx, false); callExpr == nil { if callExpr := r.calls.ContainsPkgCallExpr(node, ctx, false); callExpr == nil {
return nil, nil return nil, nil
} }
confidence := gosec.Low confidence := issue.Low
major, minor, build := gosec.GoVersion() major, minor, build := gosec.GoVersion()
if major == 1 && (minor == 16 && build < 14 || minor == 17 && build < 7) { if major == 1 && (minor == 16 && build < 14 || minor == 17 && build < 7) {
confidence = gosec.Medium confidence = issue.Medium
} }
return gosec.NewIssue(ctx, node, r.ID(), r.What, r.Severity, confidence), nil return ctx.NewIssue(node, r.ID(), r.What, r.Severity, confidence), nil
} }
// NewUsingOldMathBig rule detects the use of Rat.SetString from math/big. // NewUsingOldMathBig rule detects the use of Rat.SetString from math/big.
@ -35,10 +36,10 @@ func NewUsingOldMathBig(id string, _ gosec.Config) (gosec.Rule, []ast.Node) {
calls.Add("math/big.Rat", "SetString") calls.Add("math/big.Rat", "SetString")
return &usingOldMathBig{ return &usingOldMathBig{
calls: calls, calls: calls,
MetaData: gosec.MetaData{ MetaData: issue.MetaData{
ID: id, ID: id,
What: "Potential uncontrolled memory consumption in Rat.SetString (CVE-2022-23772)", What: "Potential uncontrolled memory consumption in Rat.SetString (CVE-2022-23772)",
Severity: gosec.High, Severity: issue.High,
}, },
}, []ast.Node{(*ast.CallExpr)(nil)} }, []ast.Node{(*ast.CallExpr)(nil)}
} }

View file

@ -4,10 +4,11 @@ import (
"go/ast" "go/ast"
"github.com/securego/gosec/v2" "github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
) )
type pprofCheck struct { type pprofCheck struct {
gosec.MetaData issue.MetaData
importPath string importPath string
importName string importName string
} }
@ -18,10 +19,10 @@ func (p *pprofCheck) ID() string {
} }
// Match checks for pprof imports // Match checks for pprof imports
func (p *pprofCheck) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) { func (p *pprofCheck) Match(n ast.Node, c *gosec.Context) (*issue.Issue, error) {
if node, ok := n.(*ast.ImportSpec); ok { if node, ok := n.(*ast.ImportSpec); ok {
if p.importPath == unquote(node.Path.Value) && node.Name != nil && p.importName == node.Name.Name { if p.importPath == unquote(node.Path.Value) && node.Name != nil && p.importName == node.Name.Name {
return gosec.NewIssue(c, node, p.ID(), p.What, p.Severity, p.Confidence), nil return c.NewIssue(node, p.ID(), p.What, p.Severity, p.Confidence), nil
} }
} }
return nil, nil return nil, nil
@ -30,10 +31,10 @@ func (p *pprofCheck) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
// NewPprofCheck detects when the profiling endpoint is automatically exposed // NewPprofCheck detects when the profiling endpoint is automatically exposed
func NewPprofCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) { func NewPprofCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
return &pprofCheck{ return &pprofCheck{
MetaData: gosec.MetaData{ MetaData: issue.MetaData{
ID: id, ID: id,
Severity: gosec.High, Severity: issue.High,
Confidence: gosec.High, Confidence: issue.High,
What: "Profiling endpoint is automatically exposed on /debug/pprof", What: "Profiling endpoint is automatically exposed on /debug/pprof",
}, },
importPath: "net/http/pprof", importPath: "net/http/pprof",

View file

@ -18,10 +18,11 @@ import (
"go/ast" "go/ast"
"github.com/securego/gosec/v2" "github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
) )
type weakRand struct { type weakRand struct {
gosec.MetaData issue.MetaData
funcNames []string funcNames []string
packagePath string packagePath string
} }
@ -30,10 +31,10 @@ func (w *weakRand) ID() string {
return w.MetaData.ID return w.MetaData.ID
} }
func (w *weakRand) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) { func (w *weakRand) Match(n ast.Node, c *gosec.Context) (*issue.Issue, error) {
for _, funcName := range w.funcNames { for _, funcName := range w.funcNames {
if _, matched := gosec.MatchCallByPackage(n, c, w.packagePath, funcName); matched { if _, matched := gosec.MatchCallByPackage(n, c, w.packagePath, funcName); matched {
return gosec.NewIssue(c, n, w.ID(), w.What, w.Severity, w.Confidence), nil return c.NewIssue(n, w.ID(), w.What, w.Severity, w.Confidence), nil
} }
} }
@ -48,10 +49,10 @@ func NewWeakRandCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
"Int31n", "Int63", "Int63n", "Intn", "NormalFloat64", "Uint32", "Uint64", "Int31n", "Int63", "Int63n", "Intn", "NormalFloat64", "Uint32", "Uint64",
}, },
packagePath: "math/rand", packagePath: "math/rand",
MetaData: gosec.MetaData{ MetaData: issue.MetaData{
ID: id, ID: id,
Severity: gosec.High, Severity: issue.High,
Confidence: gosec.Medium, Confidence: issue.Medium,
What: "Use of weak random number generator (math/rand instead of crypto/rand)", What: "Use of weak random number generator (math/rand instead of crypto/rand)",
}, },
}, []ast.Node{(*ast.CallExpr)(nil)} }, []ast.Node{(*ast.CallExpr)(nil)}

View file

@ -19,10 +19,11 @@ import (
"go/types" "go/types"
"github.com/securego/gosec/v2" "github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
) )
type readfile struct { type readfile struct {
gosec.MetaData issue.MetaData
gosec.CallList gosec.CallList
pathJoin gosec.CallList pathJoin gosec.CallList
clean gosec.CallList clean gosec.CallList
@ -86,7 +87,7 @@ func (r *readfile) trackFilepathClean(n ast.Node) {
} }
// Match inspects AST nodes to determine if the match the methods `os.Open` or `ioutil.ReadFile` // Match inspects AST nodes to determine if the match the methods `os.Open` or `ioutil.ReadFile`
func (r *readfile) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) { func (r *readfile) Match(n ast.Node, c *gosec.Context) (*issue.Issue, error) {
if node := r.clean.ContainsPkgCallExpr(n, c, false); node != nil { if node := r.clean.ContainsPkgCallExpr(n, c, false); node != nil {
r.trackFilepathClean(n) r.trackFilepathClean(n)
return nil, nil return nil, nil
@ -96,14 +97,14 @@ func (r *readfile) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
// eg. os.Open(filepath.Join("/tmp/", file)) // eg. os.Open(filepath.Join("/tmp/", file))
if callExpr, ok := arg.(*ast.CallExpr); ok { if callExpr, ok := arg.(*ast.CallExpr); ok {
if r.isJoinFunc(callExpr, c) { if r.isJoinFunc(callExpr, c) {
return gosec.NewIssue(c, n, r.ID(), r.What, r.Severity, r.Confidence), nil return c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence), nil
} }
} }
// handles binary string concatenation eg. ioutil.Readfile("/tmp/" + file + "/blob") // handles binary string concatenation eg. ioutil.Readfile("/tmp/" + file + "/blob")
if binExp, ok := arg.(*ast.BinaryExpr); ok { if binExp, ok := arg.(*ast.BinaryExpr); ok {
// resolve all found identities from the BinaryExpr // resolve all found identities from the BinaryExpr
if _, ok := gosec.FindVarIdentities(binExp, c); ok { if _, ok := gosec.FindVarIdentities(binExp, c); ok {
return gosec.NewIssue(c, n, r.ID(), r.What, r.Severity, r.Confidence), nil return c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence), nil
} }
} }
@ -112,7 +113,7 @@ func (r *readfile) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
if _, ok := obj.(*types.Var); ok && if _, ok := obj.(*types.Var); ok &&
!gosec.TryResolve(ident, c) && !gosec.TryResolve(ident, c) &&
!r.isFilepathClean(ident, c) { !r.isFilepathClean(ident, c) {
return gosec.NewIssue(c, n, r.ID(), r.What, r.Severity, r.Confidence), nil return c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence), nil
} }
} }
} }
@ -126,11 +127,11 @@ func NewReadFile(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
pathJoin: gosec.NewCallList(), pathJoin: gosec.NewCallList(),
clean: gosec.NewCallList(), clean: gosec.NewCallList(),
CallList: gosec.NewCallList(), CallList: gosec.NewCallList(),
MetaData: gosec.MetaData{ MetaData: issue.MetaData{
ID: id, ID: id,
What: "Potential file inclusion via variable", What: "Potential file inclusion via variable",
Severity: gosec.Medium, Severity: issue.Medium,
Confidence: gosec.High, Confidence: issue.High,
}, },
cleanedVar: map[any]ast.Node{}, cleanedVar: map[any]ast.Node{},
} }

View file

@ -19,10 +19,11 @@ import (
"go/ast" "go/ast"
"github.com/securego/gosec/v2" "github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
) )
type weakKeyStrength struct { type weakKeyStrength struct {
gosec.MetaData issue.MetaData
calls gosec.CallList calls gosec.CallList
bits int bits int
} }
@ -31,10 +32,10 @@ func (w *weakKeyStrength) ID() string {
return w.MetaData.ID return w.MetaData.ID
} }
func (w *weakKeyStrength) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) { func (w *weakKeyStrength) Match(n ast.Node, c *gosec.Context) (*issue.Issue, error) {
if callExpr := w.calls.ContainsPkgCallExpr(n, c, false); callExpr != nil { if callExpr := w.calls.ContainsPkgCallExpr(n, c, false); callExpr != nil {
if bits, err := gosec.GetInt(callExpr.Args[1]); err == nil && bits < (int64)(w.bits) { if bits, err := gosec.GetInt(callExpr.Args[1]); err == nil && bits < (int64)(w.bits) {
return gosec.NewIssue(c, n, w.ID(), w.What, w.Severity, w.Confidence), nil return c.NewIssue(n, w.ID(), w.What, w.Severity, w.Confidence), nil
} }
} }
return nil, nil return nil, nil
@ -48,10 +49,10 @@ func NewWeakKeyStrength(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
return &weakKeyStrength{ return &weakKeyStrength{
calls: calls, calls: calls,
bits: bits, bits: bits,
MetaData: gosec.MetaData{ MetaData: issue.MetaData{
ID: id, ID: id,
Severity: gosec.Medium, Severity: issue.Medium,
Confidence: gosec.High, Confidence: issue.High,
What: fmt.Sprintf("RSA keys should be at least %d bits", bits), What: fmt.Sprintf("RSA keys should be at least %d bits", bits),
}, },
}, []ast.Node{(*ast.CallExpr)(nil)} }, []ast.Node{(*ast.CallExpr)(nil)}

View file

@ -18,10 +18,11 @@ import (
"go/ast" "go/ast"
"github.com/securego/gosec/v2" "github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
) )
type slowloris struct { type slowloris struct {
gosec.MetaData issue.MetaData
} }
func (r *slowloris) ID() string { func (r *slowloris) ID() string {
@ -44,13 +45,13 @@ func containsReadHeaderTimeout(node *ast.CompositeLit) bool {
return false return false
} }
func (r *slowloris) Match(n ast.Node, ctx *gosec.Context) (*gosec.Issue, error) { func (r *slowloris) Match(n ast.Node, ctx *gosec.Context) (*issue.Issue, error) {
switch node := n.(type) { switch node := n.(type) {
case *ast.CompositeLit: case *ast.CompositeLit:
actualType := ctx.Info.TypeOf(node.Type) actualType := ctx.Info.TypeOf(node.Type)
if actualType != nil && actualType.String() == "net/http.Server" { if actualType != nil && actualType.String() == "net/http.Server" {
if !containsReadHeaderTimeout(node) { if !containsReadHeaderTimeout(node) {
return gosec.NewIssue(ctx, node, r.ID(), r.What, r.Severity, r.Confidence), nil return ctx.NewIssue(node, r.ID(), r.What, r.Severity, r.Confidence), nil
} }
} }
} }
@ -60,11 +61,11 @@ func (r *slowloris) Match(n ast.Node, ctx *gosec.Context) (*gosec.Issue, error)
// NewSlowloris attempts to find the http.Server struct and check if the ReadHeaderTimeout is configured. // NewSlowloris attempts to find the http.Server struct and check if the ReadHeaderTimeout is configured.
func NewSlowloris(id string, conf gosec.Config) (gosec.Rule, []ast.Node) { func NewSlowloris(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
return &slowloris{ return &slowloris{
MetaData: gosec.MetaData{ MetaData: issue.MetaData{
ID: id, ID: id,
What: "Potential Slowloris Attack because ReadHeaderTimeout is not configured in the http.Server", What: "Potential Slowloris Attack because ReadHeaderTimeout is not configured in the http.Server",
Confidence: gosec.Low, Confidence: issue.Low,
Severity: gosec.Medium, Severity: issue.Medium,
}, },
}, []ast.Node{(*ast.CompositeLit)(nil)} }, []ast.Node{(*ast.CompositeLit)(nil)}
} }

View file

@ -20,10 +20,11 @@ import (
"regexp" "regexp"
"github.com/securego/gosec/v2" "github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
) )
type sqlStatement struct { type sqlStatement struct {
gosec.MetaData issue.MetaData
gosec.CallList gosec.CallList
// Contains a list of patterns which must all match for the rule to match. // Contains a list of patterns which must all match for the rule to match.
@ -113,7 +114,7 @@ func (s *sqlStrConcat) checkObject(n *ast.Ident, c *gosec.Context) bool {
} }
// checkQuery verifies if the query parameters is a string concatenation // checkQuery verifies if the query parameters is a string concatenation
func (s *sqlStrConcat) checkQuery(call *ast.CallExpr, ctx *gosec.Context) (*gosec.Issue, error) { func (s *sqlStrConcat) checkQuery(call *ast.CallExpr, ctx *gosec.Context) (*issue.Issue, error) {
query, err := findQueryArg(call, ctx) query, err := findQueryArg(call, ctx)
if err != nil { if err != nil {
return nil, err return nil, err
@ -134,7 +135,7 @@ func (s *sqlStrConcat) checkQuery(call *ast.CallExpr, ctx *gosec.Context) (*gose
if op, ok := op.(*ast.Ident); ok && s.checkObject(op, ctx) { if op, ok := op.(*ast.Ident); ok && s.checkObject(op, ctx) {
continue continue
} }
return gosec.NewIssue(ctx, be, s.ID(), s.What, s.Severity, s.Confidence), nil return ctx.NewIssue(be, s.ID(), s.What, s.Severity, s.Confidence), nil
} }
} }
} }
@ -143,7 +144,7 @@ func (s *sqlStrConcat) checkQuery(call *ast.CallExpr, ctx *gosec.Context) (*gose
} }
// Checks SQL query concatenation issues such as "SELECT * FROM table WHERE " + " ' OR 1=1" // Checks SQL query concatenation issues such as "SELECT * FROM table WHERE " + " ' OR 1=1"
func (s *sqlStrConcat) Match(n ast.Node, ctx *gosec.Context) (*gosec.Issue, error) { func (s *sqlStrConcat) Match(n ast.Node, ctx *gosec.Context) (*issue.Issue, error) {
switch stmt := n.(type) { switch stmt := n.(type) {
case *ast.AssignStmt: case *ast.AssignStmt:
for _, expr := range stmt.Rhs { for _, expr := range stmt.Rhs {
@ -166,10 +167,10 @@ func NewSQLStrConcat(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
patterns: []*regexp.Regexp{ patterns: []*regexp.Regexp{
regexp.MustCompile(`(?i)(SELECT|DELETE|INSERT|UPDATE|INTO|FROM|WHERE) `), regexp.MustCompile(`(?i)(SELECT|DELETE|INSERT|UPDATE|INTO|FROM|WHERE) `),
}, },
MetaData: gosec.MetaData{ MetaData: issue.MetaData{
ID: id, ID: id,
Severity: gosec.Medium, Severity: issue.Medium,
Confidence: gosec.High, Confidence: issue.High,
What: "SQL string concatenation", What: "SQL string concatenation",
}, },
CallList: gosec.NewCallList(), CallList: gosec.NewCallList(),
@ -212,7 +213,7 @@ func (s *sqlStrFormat) constObject(e ast.Expr, c *gosec.Context) bool {
return false return false
} }
func (s *sqlStrFormat) checkQuery(call *ast.CallExpr, ctx *gosec.Context) (*gosec.Issue, error) { func (s *sqlStrFormat) checkQuery(call *ast.CallExpr, ctx *gosec.Context) (*issue.Issue, error) {
query, err := findQueryArg(call, ctx) query, err := findQueryArg(call, ctx)
if err != nil { if err != nil {
return nil, err return nil, err
@ -233,7 +234,7 @@ func (s *sqlStrFormat) checkQuery(call *ast.CallExpr, ctx *gosec.Context) (*gose
return nil, nil return nil, nil
} }
func (s *sqlStrFormat) checkFormatting(n ast.Node, ctx *gosec.Context) *gosec.Issue { func (s *sqlStrFormat) checkFormatting(n ast.Node, ctx *gosec.Context) *issue.Issue {
// argIndex changes the function argument which gets matched to the regex // argIndex changes the function argument which gets matched to the regex
argIndex := 0 argIndex := 0
if node := s.fmtCalls.ContainsPkgCallExpr(n, ctx, false); node != nil { if node := s.fmtCalls.ContainsPkgCallExpr(n, ctx, false); node != nil {
@ -286,14 +287,14 @@ func (s *sqlStrFormat) checkFormatting(n ast.Node, ctx *gosec.Context) *gosec.Is
} }
} }
if s.MatchPatterns(formatter) { if s.MatchPatterns(formatter) {
return gosec.NewIssue(ctx, n, s.ID(), s.What, s.Severity, s.Confidence) return ctx.NewIssue(n, s.ID(), s.What, s.Severity, s.Confidence)
} }
} }
return nil return nil
} }
// Check SQL query formatting issues such as "fmt.Sprintf("SELECT * FROM foo where '%s', userInput)" // Check SQL query formatting issues such as "fmt.Sprintf("SELECT * FROM foo where '%s', userInput)"
func (s *sqlStrFormat) Match(n ast.Node, ctx *gosec.Context) (*gosec.Issue, error) { func (s *sqlStrFormat) Match(n ast.Node, ctx *gosec.Context) (*issue.Issue, error) {
switch stmt := n.(type) { switch stmt := n.(type) {
case *ast.AssignStmt: case *ast.AssignStmt:
for _, expr := range stmt.Rhs { for _, expr := range stmt.Rhs {
@ -334,10 +335,10 @@ func NewSQLStrFormat(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
regexp.MustCompile("(?i)(SELECT|DELETE|INSERT|UPDATE|INTO|FROM|WHERE)( |\n|\r|\t)"), regexp.MustCompile("(?i)(SELECT|DELETE|INSERT|UPDATE|INTO|FROM|WHERE)( |\n|\r|\t)"),
regexp.MustCompile("%[^bdoxXfFp]"), regexp.MustCompile("%[^bdoxXfFp]"),
}, },
MetaData: gosec.MetaData{ MetaData: issue.MetaData{
ID: id, ID: id,
Severity: gosec.Medium, Severity: issue.Medium,
Confidence: gosec.High, Confidence: issue.High,
What: "SQL string formatting", What: "SQL string formatting",
}, },
}, },

View file

@ -4,10 +4,11 @@ import (
"go/ast" "go/ast"
"github.com/securego/gosec/v2" "github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
) )
type sshHostKey struct { type sshHostKey struct {
gosec.MetaData issue.MetaData
pkg string pkg string
calls []string calls []string
} }
@ -16,9 +17,9 @@ func (r *sshHostKey) ID() string {
return r.MetaData.ID return r.MetaData.ID
} }
func (r *sshHostKey) Match(n ast.Node, c *gosec.Context) (gi *gosec.Issue, err error) { func (r *sshHostKey) Match(n ast.Node, c *gosec.Context) (gi *issue.Issue, err error) {
if _, matches := gosec.MatchCallByPackage(n, c, r.pkg, r.calls...); matches { if _, matches := gosec.MatchCallByPackage(n, c, r.pkg, r.calls...); matches {
return gosec.NewIssue(c, n, r.ID(), r.What, r.Severity, r.Confidence), nil return c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence), nil
} }
return nil, nil return nil, nil
} }
@ -28,11 +29,11 @@ func NewSSHHostKey(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
return &sshHostKey{ return &sshHostKey{
pkg: "golang.org/x/crypto/ssh", pkg: "golang.org/x/crypto/ssh",
calls: []string{"InsecureIgnoreHostKey"}, calls: []string{"InsecureIgnoreHostKey"},
MetaData: gosec.MetaData{ MetaData: issue.MetaData{
ID: id, ID: id,
What: "Use of ssh InsecureIgnoreHostKey should be audited", What: "Use of ssh InsecureIgnoreHostKey should be audited",
Severity: gosec.Medium, Severity: issue.Medium,
Confidence: gosec.High, Confidence: issue.High,
}, },
}, []ast.Node{(*ast.CallExpr)(nil)} }, []ast.Node{(*ast.CallExpr)(nil)}
} }

View file

@ -5,10 +5,11 @@ import (
"go/types" "go/types"
"github.com/securego/gosec/v2" "github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
) )
type ssrf struct { type ssrf struct {
gosec.MetaData issue.MetaData
gosec.CallList gosec.CallList
} }
@ -40,11 +41,11 @@ func (r *ssrf) ResolveVar(n *ast.CallExpr, c *gosec.Context) bool {
} }
// Match inspects AST nodes to determine if certain net/http methods are called with variable input // Match inspects AST nodes to determine if certain net/http methods are called with variable input
func (r *ssrf) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) { func (r *ssrf) Match(n ast.Node, c *gosec.Context) (*issue.Issue, error) {
// Call expression is using http package directly // Call expression is using http package directly
if node := r.ContainsPkgCallExpr(n, c, false); node != nil { if node := r.ContainsPkgCallExpr(n, c, false); node != nil {
if r.ResolveVar(node, c) { if r.ResolveVar(node, c) {
return gosec.NewIssue(c, n, r.ID(), r.What, r.Severity, r.Confidence), nil return c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence), nil
} }
} }
return nil, nil return nil, nil
@ -54,11 +55,11 @@ func (r *ssrf) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
func NewSSRFCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) { func NewSSRFCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
rule := &ssrf{ rule := &ssrf{
CallList: gosec.NewCallList(), CallList: gosec.NewCallList(),
MetaData: gosec.MetaData{ MetaData: issue.MetaData{
ID: id, ID: id,
What: "Potential HTTP request made with variable url", What: "Potential HTTP request made with variable url",
Severity: gosec.Medium, Severity: issue.Medium,
Confidence: gosec.Medium, Confidence: issue.Medium,
}, },
} }
rule.AddAll("net/http", "Do", "Get", "Head", "Post", "PostForm", "RoundTrip") rule.AddAll("net/http", "Do", "Get", "Head", "Post", "PostForm", "RoundTrip")

View file

@ -19,10 +19,11 @@ import (
"go/types" "go/types"
"github.com/securego/gosec/v2" "github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
) )
type subprocess struct { type subprocess struct {
gosec.MetaData issue.MetaData
gosec.CallList gosec.CallList
} }
@ -39,7 +40,7 @@ func (r *subprocess) ID() string {
// is unsafe. For example: // is unsafe. For example:
// //
// syscall.Exec("echo", "foobar" + tainted) // syscall.Exec("echo", "foobar" + tainted)
func (r *subprocess) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) { func (r *subprocess) Match(n ast.Node, c *gosec.Context) (*issue.Issue, error) {
if node := r.ContainsPkgCallExpr(n, c, false); node != nil { if node := r.ContainsPkgCallExpr(n, c, false); node != nil {
args := node.Args args := node.Args
if r.isContext(n, c) { if r.isContext(n, c) {
@ -64,7 +65,7 @@ func (r *subprocess) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
_, assignment := ident.Obj.Decl.(*ast.AssignStmt) _, assignment := ident.Obj.Decl.(*ast.AssignStmt)
if variable && assignment { if variable && assignment {
if !gosec.TryResolve(ident, c) { if !gosec.TryResolve(ident, c) {
return gosec.NewIssue(c, n, r.ID(), "Subprocess launched with variable", gosec.Medium, gosec.High), nil return c.NewIssue(n, r.ID(), "Subprocess launched with variable", issue.Medium, issue.High), nil
} }
} }
case *ast.Field: case *ast.Field:
@ -74,21 +75,21 @@ func (r *subprocess) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
vv, vvok := obj.(*types.Var) vv, vvok := obj.(*types.Var)
if vvok && vv.Parent().Lookup(ident.Name) == nil { if vvok && vv.Parent().Lookup(ident.Name) == nil {
return gosec.NewIssue(c, n, r.ID(), "Subprocess launched with variable", gosec.Medium, gosec.High), nil return c.NewIssue(n, r.ID(), "Subprocess launched with variable", issue.Medium, issue.High), nil
} }
} }
case *ast.ValueSpec: case *ast.ValueSpec:
_, valueSpec := ident.Obj.Decl.(*ast.ValueSpec) _, valueSpec := ident.Obj.Decl.(*ast.ValueSpec)
if variable && valueSpec { if variable && valueSpec {
if !gosec.TryResolve(ident, c) { if !gosec.TryResolve(ident, c) {
return gosec.NewIssue(c, n, r.ID(), "Subprocess launched with variable", gosec.Medium, gosec.High), nil return c.NewIssue(n, r.ID(), "Subprocess launched with variable", issue.Medium, issue.High), nil
} }
} }
} }
} }
} else if !gosec.TryResolve(arg, c) { } else if !gosec.TryResolve(arg, c) {
// the arg is not a constant or a variable but instead a function call or os.Args[i] // the arg is not a constant or a variable but instead a function call or os.Args[i]
return gosec.NewIssue(c, n, r.ID(), "Subprocess launched with a potential tainted input or cmd arguments", gosec.Medium, gosec.High), nil return c.NewIssue(n, r.ID(), "Subprocess launched with a potential tainted input or cmd arguments", issue.Medium, issue.High), nil
} }
} }
} }
@ -110,7 +111,7 @@ func (r *subprocess) isContext(n ast.Node, ctx *gosec.Context) bool {
// NewSubproc detects cases where we are forking out to an external process // NewSubproc detects cases where we are forking out to an external process
func NewSubproc(id string, conf gosec.Config) (gosec.Rule, []ast.Node) { func NewSubproc(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
rule := &subprocess{gosec.MetaData{ID: id}, gosec.NewCallList()} rule := &subprocess{issue.MetaData{ID: id}, gosec.NewCallList()}
rule.Add("os/exec", "Command") rule.Add("os/exec", "Command")
rule.Add("os/exec", "CommandContext") rule.Add("os/exec", "CommandContext")
rule.Add("syscall", "Exec") rule.Add("syscall", "Exec")

View file

@ -19,10 +19,11 @@ import (
"regexp" "regexp"
"github.com/securego/gosec/v2" "github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
) )
type badTempFile struct { type badTempFile struct {
gosec.MetaData issue.MetaData
calls gosec.CallList calls gosec.CallList
args *regexp.Regexp args *regexp.Regexp
argCalls gosec.CallList argCalls gosec.CallList
@ -33,15 +34,15 @@ func (t *badTempFile) ID() string {
return t.MetaData.ID return t.MetaData.ID
} }
func (t *badTempFile) findTempDirArgs(n ast.Node, c *gosec.Context, suspect ast.Node) *gosec.Issue { func (t *badTempFile) findTempDirArgs(n ast.Node, c *gosec.Context, suspect ast.Node) *issue.Issue {
if s, e := gosec.GetString(suspect); e == nil { if s, e := gosec.GetString(suspect); e == nil {
if t.args.MatchString(s) { if t.args.MatchString(s) {
return gosec.NewIssue(c, n, t.ID(), t.What, t.Severity, t.Confidence) return c.NewIssue(n, t.ID(), t.What, t.Severity, t.Confidence)
} }
return nil return nil
} }
if ce := t.argCalls.ContainsPkgCallExpr(suspect, c, false); ce != nil { if ce := t.argCalls.ContainsPkgCallExpr(suspect, c, false); ce != nil {
return gosec.NewIssue(c, n, t.ID(), t.What, t.Severity, t.Confidence) return c.NewIssue(n, t.ID(), t.What, t.Severity, t.Confidence)
} }
if be, ok := suspect.(*ast.BinaryExpr); ok { if be, ok := suspect.(*ast.BinaryExpr); ok {
if ops := gosec.GetBinaryExprOperands(be); len(ops) != 0 { if ops := gosec.GetBinaryExprOperands(be); len(ops) != 0 {
@ -55,7 +56,7 @@ func (t *badTempFile) findTempDirArgs(n ast.Node, c *gosec.Context, suspect ast.
return nil return nil
} }
func (t *badTempFile) Match(n ast.Node, c *gosec.Context) (gi *gosec.Issue, err error) { func (t *badTempFile) Match(n ast.Node, c *gosec.Context) (gi *issue.Issue, err error) {
if node := t.calls.ContainsPkgCallExpr(n, c, false); node != nil { if node := t.calls.ContainsPkgCallExpr(n, c, false); node != nil {
return t.findTempDirArgs(n, c, node.Args[0]), nil return t.findTempDirArgs(n, c, node.Args[0]), nil
} }
@ -77,10 +78,10 @@ func NewBadTempFile(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
args: regexp.MustCompile(`^(/(usr|var))?/tmp(/.*)?$`), args: regexp.MustCompile(`^(/(usr|var))?/tmp(/.*)?$`),
argCalls: argCalls, argCalls: argCalls,
nestedCalls: nestedCalls, nestedCalls: nestedCalls,
MetaData: gosec.MetaData{ MetaData: issue.MetaData{
ID: id, ID: id,
Severity: gosec.Medium, Severity: issue.Medium,
Confidence: gosec.High, Confidence: issue.High,
What: "File creation in shared tmp directory without using ioutil.Tempfile", What: "File creation in shared tmp directory without using ioutil.Tempfile",
}, },
}, []ast.Node{(*ast.CallExpr)(nil)} }, []ast.Node{(*ast.CallExpr)(nil)}

View file

@ -18,10 +18,11 @@ import (
"go/ast" "go/ast"
"github.com/securego/gosec/v2" "github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
) )
type templateCheck struct { type templateCheck struct {
gosec.MetaData issue.MetaData
calls gosec.CallList calls gosec.CallList
} }
@ -29,11 +30,11 @@ func (t *templateCheck) ID() string {
return t.MetaData.ID return t.MetaData.ID
} }
func (t *templateCheck) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) { func (t *templateCheck) Match(n ast.Node, c *gosec.Context) (*issue.Issue, error) {
if node := t.calls.ContainsPkgCallExpr(n, c, false); node != nil { if node := t.calls.ContainsPkgCallExpr(n, c, false); node != nil {
for _, arg := range node.Args { for _, arg := range node.Args {
if _, ok := arg.(*ast.BasicLit); !ok { // basic lits are safe if _, ok := arg.(*ast.BasicLit); !ok { // basic lits are safe
return gosec.NewIssue(c, n, t.ID(), t.What, t.Severity, t.Confidence), nil return c.NewIssue(n, t.ID(), t.What, t.Severity, t.Confidence), nil
} }
} }
} }
@ -50,10 +51,10 @@ func NewTemplateCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
calls.Add("html/template", "URL") calls.Add("html/template", "URL")
return &templateCheck{ return &templateCheck{
calls: calls, calls: calls,
MetaData: gosec.MetaData{ MetaData: issue.MetaData{
ID: id, ID: id,
Severity: gosec.Medium, Severity: issue.Medium,
Confidence: gosec.Low, Confidence: issue.Low,
What: "The used method does not auto-escape HTML. This can potentially lead to 'Cross-site Scripting' vulnerabilities, in case the attacker controls the input.", What: "The used method does not auto-escape HTML. This can potentially lead to 'Cross-site Scripting' vulnerabilities, in case the attacker controls the input.",
}, },
}, []ast.Node{(*ast.CallExpr)(nil)} }, []ast.Node{(*ast.CallExpr)(nil)}

View file

@ -24,10 +24,11 @@ import (
"strconv" "strconv"
"github.com/securego/gosec/v2" "github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
) )
type insecureConfigTLS struct { type insecureConfigTLS struct {
gosec.MetaData issue.MetaData
MinVersion int64 MinVersion int64
MaxVersion int64 MaxVersion int64
requiredType string requiredType string
@ -49,13 +50,13 @@ func stringInSlice(a string, list []string) bool {
return false return false
} }
func (t *insecureConfigTLS) processTLSCipherSuites(n ast.Node, c *gosec.Context) *gosec.Issue { func (t *insecureConfigTLS) processTLSCipherSuites(n ast.Node, c *gosec.Context) *issue.Issue {
if ciphers, ok := n.(*ast.CompositeLit); ok { if ciphers, ok := n.(*ast.CompositeLit); ok {
for _, cipher := range ciphers.Elts { for _, cipher := range ciphers.Elts {
if ident, ok := cipher.(*ast.SelectorExpr); ok { if ident, ok := cipher.(*ast.SelectorExpr); ok {
if !stringInSlice(ident.Sel.Name, t.goodCiphers) { if !stringInSlice(ident.Sel.Name, t.goodCiphers) {
err := fmt.Sprintf("TLS Bad Cipher Suite: %s", ident.Sel.Name) err := fmt.Sprintf("TLS Bad Cipher Suite: %s", ident.Sel.Name)
return gosec.NewIssue(c, ident, t.ID(), err, gosec.High, gosec.High) return c.NewIssue(ident, t.ID(), err, issue.High, issue.High)
} }
} }
} }
@ -63,7 +64,7 @@ func (t *insecureConfigTLS) processTLSCipherSuites(n ast.Node, c *gosec.Context)
return nil return nil
} }
func (t *insecureConfigTLS) processTLSConf(n ast.Node, c *gosec.Context) *gosec.Issue { func (t *insecureConfigTLS) processTLSConf(n ast.Node, c *gosec.Context) *issue.Issue {
if kve, ok := n.(*ast.KeyValueExpr); ok { if kve, ok := n.(*ast.KeyValueExpr); ok {
issue := t.processTLSConfVal(kve.Key, kve.Value, c) issue := t.processTLSConfVal(kve.Key, kve.Value, c)
if issue != nil { if issue != nil {
@ -83,27 +84,27 @@ func (t *insecureConfigTLS) processTLSConf(n ast.Node, c *gosec.Context) *gosec.
return nil return nil
} }
func (t *insecureConfigTLS) processTLSConfVal(key ast.Expr, value ast.Expr, c *gosec.Context) *gosec.Issue { func (t *insecureConfigTLS) processTLSConfVal(key ast.Expr, value ast.Expr, c *gosec.Context) *issue.Issue {
if ident, ok := key.(*ast.Ident); ok { if ident, ok := key.(*ast.Ident); ok {
switch ident.Name { switch ident.Name {
case "InsecureSkipVerify": case "InsecureSkipVerify":
if node, ok := value.(*ast.Ident); ok { if node, ok := value.(*ast.Ident); ok {
if node.Name != "false" { if node.Name != "false" {
return gosec.NewIssue(c, value, t.ID(), "TLS InsecureSkipVerify set true.", gosec.High, gosec.High) return c.NewIssue(value, t.ID(), "TLS InsecureSkipVerify set true.", issue.High, issue.High)
} }
} else { } else {
// TODO(tk): symbol tab look up to get the actual value // TODO(tk): symbol tab look up to get the actual value
return gosec.NewIssue(c, value, t.ID(), "TLS InsecureSkipVerify may be true.", gosec.High, gosec.Low) return c.NewIssue(value, t.ID(), "TLS InsecureSkipVerify may be true.", issue.High, issue.Low)
} }
case "PreferServerCipherSuites": case "PreferServerCipherSuites":
if node, ok := value.(*ast.Ident); ok { if node, ok := value.(*ast.Ident); ok {
if node.Name == "false" { if node.Name == "false" {
return gosec.NewIssue(c, value, t.ID(), "TLS PreferServerCipherSuites set false.", gosec.Medium, gosec.High) return c.NewIssue(value, t.ID(), "TLS PreferServerCipherSuites set false.", issue.Medium, issue.High)
} }
} else { } else {
// TODO(tk): symbol tab look up to get the actual value // TODO(tk): symbol tab look up to get the actual value
return gosec.NewIssue(c, value, t.ID(), "TLS PreferServerCipherSuites may be false.", gosec.Medium, gosec.Low) return c.NewIssue(value, t.ID(), "TLS PreferServerCipherSuites may be false.", issue.Medium, issue.Low)
} }
case "MinVersion": case "MinVersion":
@ -188,16 +189,16 @@ func (t *insecureConfigTLS) mapVersion(version string) int64 {
return v return v
} }
func (t *insecureConfigTLS) checkVersion(n ast.Node, c *gosec.Context) *gosec.Issue { func (t *insecureConfigTLS) checkVersion(n ast.Node, c *gosec.Context) *issue.Issue {
if t.actualMaxVersion == 0 && t.actualMinVersion >= t.MinVersion { if t.actualMaxVersion == 0 && t.actualMinVersion >= t.MinVersion {
// no warning is generated since the min version is greater than the secure min version // no warning is generated since the min version is greater than the secure min version
return nil return nil
} }
if t.actualMinVersion < t.MinVersion { if t.actualMinVersion < t.MinVersion {
return gosec.NewIssue(c, n, t.ID(), "TLS MinVersion too low.", gosec.High, gosec.High) return c.NewIssue(n, t.ID(), "TLS MinVersion too low.", issue.High, issue.High)
} }
if t.actualMaxVersion < t.MaxVersion { if t.actualMaxVersion < t.MaxVersion {
return gosec.NewIssue(c, n, t.ID(), "TLS MaxVersion too low.", gosec.High, gosec.High) return c.NewIssue(n, t.ID(), "TLS MaxVersion too low.", issue.High, issue.High)
} }
return nil return nil
} }
@ -207,7 +208,7 @@ func (t *insecureConfigTLS) resetVersion() {
t.actualMinVersion = 0 t.actualMinVersion = 0
} }
func (t *insecureConfigTLS) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) { func (t *insecureConfigTLS) Match(n ast.Node, c *gosec.Context) (*issue.Issue, error) {
if complit, ok := n.(*ast.CompositeLit); ok && complit.Type != nil { if complit, ok := n.(*ast.CompositeLit); ok && complit.Type != nil {
actualType := c.Info.TypeOf(complit.Type) actualType := c.Info.TypeOf(complit.Type)
if actualType != nil && actualType.String() == t.requiredType { if actualType != nil && actualType.String() == t.requiredType {

View file

@ -4,13 +4,14 @@ import (
"go/ast" "go/ast"
"github.com/securego/gosec/v2" "github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
) )
// NewModernTLSCheck creates a check for Modern TLS ciphers // NewModernTLSCheck creates a check for Modern TLS ciphers
// DO NOT EDIT - generated by tlsconfig tool // DO NOT EDIT - generated by tlsconfig tool
func NewModernTLSCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) { func NewModernTLSCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
return &insecureConfigTLS{ return &insecureConfigTLS{
MetaData: gosec.MetaData{ID: id}, MetaData: issue.MetaData{ID: id},
requiredType: "crypto/tls.Config", requiredType: "crypto/tls.Config",
MinVersion: 0x0304, MinVersion: 0x0304,
MaxVersion: 0x0304, MaxVersion: 0x0304,
@ -26,7 +27,7 @@ func NewModernTLSCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
// DO NOT EDIT - generated by tlsconfig tool // DO NOT EDIT - generated by tlsconfig tool
func NewIntermediateTLSCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) { func NewIntermediateTLSCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
return &insecureConfigTLS{ return &insecureConfigTLS{
MetaData: gosec.MetaData{ID: id}, MetaData: issue.MetaData{ID: id},
requiredType: "crypto/tls.Config", requiredType: "crypto/tls.Config",
MinVersion: 0x0303, MinVersion: 0x0303,
MaxVersion: 0x0304, MaxVersion: 0x0304,
@ -52,7 +53,7 @@ func NewIntermediateTLSCheck(id string, conf gosec.Config) (gosec.Rule, []ast.No
// DO NOT EDIT - generated by tlsconfig tool // DO NOT EDIT - generated by tlsconfig tool
func NewOldTLSCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) { func NewOldTLSCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
return &insecureConfigTLS{ return &insecureConfigTLS{
MetaData: gosec.MetaData{ID: id}, MetaData: issue.MetaData{ID: id},
requiredType: "crypto/tls.Config", requiredType: "crypto/tls.Config",
MinVersion: 0x0301, MinVersion: 0x0301,
MaxVersion: 0x0304, MaxVersion: 0x0304,

View file

@ -18,10 +18,11 @@ import (
"go/ast" "go/ast"
"github.com/securego/gosec/v2" "github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
) )
type usingUnsafe struct { type usingUnsafe struct {
gosec.MetaData issue.MetaData
pkg string pkg string
calls []string calls []string
} }
@ -30,9 +31,9 @@ func (r *usingUnsafe) ID() string {
return r.MetaData.ID return r.MetaData.ID
} }
func (r *usingUnsafe) Match(n ast.Node, c *gosec.Context) (gi *gosec.Issue, err error) { func (r *usingUnsafe) Match(n ast.Node, c *gosec.Context) (gi *issue.Issue, err error) {
if _, matches := gosec.MatchCallByPackage(n, c, r.pkg, r.calls...); matches { if _, matches := gosec.MatchCallByPackage(n, c, r.pkg, r.calls...); matches {
return gosec.NewIssue(c, n, r.ID(), r.What, r.Severity, r.Confidence), nil return c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence), nil
} }
return nil, nil return nil, nil
} }
@ -43,11 +44,11 @@ func NewUsingUnsafe(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
return &usingUnsafe{ return &usingUnsafe{
pkg: "unsafe", pkg: "unsafe",
calls: []string{"Alignof", "Offsetof", "Sizeof", "Pointer"}, calls: []string{"Alignof", "Offsetof", "Sizeof", "Pointer"},
MetaData: gosec.MetaData{ MetaData: issue.MetaData{
ID: id, ID: id,
What: "Use of unsafe calls should be audited", What: "Use of unsafe calls should be audited",
Severity: gosec.Low, Severity: issue.Low,
Confidence: gosec.High, Confidence: issue.High,
}, },
}, []ast.Node{(*ast.CallExpr)(nil)} }, []ast.Node{(*ast.CallExpr)(nil)}
} }

View file

@ -18,10 +18,11 @@ import (
"go/ast" "go/ast"
"github.com/securego/gosec/v2" "github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
) )
type usesWeakCryptography struct { type usesWeakCryptography struct {
gosec.MetaData issue.MetaData
blocklist map[string][]string blocklist map[string][]string
} }
@ -29,10 +30,10 @@ func (r *usesWeakCryptography) ID() string {
return r.MetaData.ID return r.MetaData.ID
} }
func (r *usesWeakCryptography) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) { func (r *usesWeakCryptography) Match(n ast.Node, c *gosec.Context) (*issue.Issue, error) {
for pkg, funcs := range r.blocklist { for pkg, funcs := range r.blocklist {
if _, matched := gosec.MatchCallByPackage(n, c, pkg, funcs...); matched { if _, matched := gosec.MatchCallByPackage(n, c, pkg, funcs...); matched {
return gosec.NewIssue(c, n, r.ID(), r.What, r.Severity, r.Confidence), nil return c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence), nil
} }
} }
return nil, nil return nil, nil
@ -47,10 +48,10 @@ func NewUsesWeakCryptography(id string, conf gosec.Config) (gosec.Rule, []ast.No
calls["crypto/rc4"] = []string{"NewCipher"} calls["crypto/rc4"] = []string{"NewCipher"}
rule := &usesWeakCryptography{ rule := &usesWeakCryptography{
blocklist: calls, blocklist: calls,
MetaData: gosec.MetaData{ MetaData: issue.MetaData{
ID: id, ID: id,
Severity: gosec.Medium, Severity: issue.Medium,
Confidence: gosec.High, Confidence: issue.High,
What: "Use of weak cryptographic primitive", What: "Use of weak cryptographic primitive",
}, },
} }