mirror of
https://github.com/securego/gosec.git
synced 2024-12-24 11:35:52 +00:00
Extract the issue in its own package
This commit is contained in:
parent
31e63276f1
commit
de2c6a36fa
48 changed files with 439 additions and 378 deletions
5
Makefile
5
Makefile
|
@ -87,4 +87,7 @@ image-push: image
|
|||
docker push $(IMAGE_REPO)/$(BIN):$(GIT_TAG)
|
||||
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
|
||||
|
|
69
analyzer.go
69
analyzer.go
|
@ -32,6 +32,7 @@ import (
|
|||
"sync"
|
||||
|
||||
"github.com/securego/gosec/v2/analyzers"
|
||||
"github.com/securego/gosec/v2/issue"
|
||||
"golang.org/x/tools/go/analysis"
|
||||
"golang.org/x/tools/go/analysis/passes/buildssa"
|
||||
"golang.org/x/tools/go/packages"
|
||||
|
@ -68,10 +69,21 @@ type Context struct {
|
|||
Root *ast.File
|
||||
Imports *ImportTracker
|
||||
Config Config
|
||||
Ignores []map[string][]SuppressionInfo
|
||||
Ignores []map[string][]issue.SuppressionInfo
|
||||
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.
|
||||
type Metrics struct {
|
||||
NumFiles int `json:"files"`
|
||||
|
@ -88,7 +100,7 @@ type Analyzer struct {
|
|||
context *Context
|
||||
config Config
|
||||
logger *log.Logger
|
||||
issues []*Issue
|
||||
issues []*issue.Issue
|
||||
stats *Metrics
|
||||
errors map[string][]Error // keys are file paths; values are the golang errors in those files
|
||||
tests bool
|
||||
|
@ -99,13 +111,6 @@ type Analyzer struct {
|
|||
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.
|
||||
func NewAnalyzer(conf Config, tests bool, excludeGenerated bool, trackSuppressions bool, concurrency int, logger *log.Logger) *Analyzer {
|
||||
ignoreNoSec := false
|
||||
|
@ -126,7 +131,7 @@ func NewAnalyzer(conf Config, tests bool, excludeGenerated bool, trackSuppressio
|
|||
context: &Context{},
|
||||
config: conf,
|
||||
logger: logger,
|
||||
issues: make([]*Issue, 0, 16),
|
||||
issues: make([]*issue.Issue, 0, 16),
|
||||
stats: &Metrics{},
|
||||
errors: make(map[string][]Error),
|
||||
tests: tests,
|
||||
|
@ -371,8 +376,8 @@ func (gosec *Analyzer) CheckAnalyzers(pkg *packages.Package) {
|
|||
continue
|
||||
}
|
||||
if result != nil {
|
||||
if issue, ok := result.(*analyzers.Issue); ok {
|
||||
gosec.updateIssues(toGosecIssue(issue), false, []SuppressionInfo{})
|
||||
if aissue, ok := result.(*analyzers.Issue); ok {
|
||||
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
|
||||
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 {
|
||||
|
||||
// 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})`)
|
||||
matches := re.FindAllStringSubmatch(directive, -1)
|
||||
|
||||
suppression := SuppressionInfo{
|
||||
suppression := issue.SuppressionInfo{
|
||||
Kind: "inSource",
|
||||
Justification: justification,
|
||||
}
|
||||
|
||||
// Find the rule IDs to ignore.
|
||||
ignores := make(map[string]SuppressionInfo)
|
||||
ignores := make(map[string]issue.SuppressionInfo)
|
||||
for _, v := range matches {
|
||||
ignores[v[1]] = suppression
|
||||
}
|
||||
|
@ -525,7 +530,7 @@ func (gosec *Analyzer) Visit(n ast.Node) ast.Visitor {
|
|||
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 len(gosec.context.Ignores) > 0 {
|
||||
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)
|
||||
|
||||
// Now create the union of exclusions.
|
||||
ignores := map[string][]SuppressionInfo{}
|
||||
ignores := map[string][]issue.SuppressionInfo{}
|
||||
if len(gosec.context.Ignores) > 0 {
|
||||
for k, v := range gosec.context.Ignores[0] {
|
||||
ignores[k] = v
|
||||
|
@ -548,12 +553,12 @@ func (gosec *Analyzer) updateIgnoredRules(n ast.Node) (map[string][]SuppressionI
|
|||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
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.
|
||||
generalSuppressions, generalIgnored := ignores[aliasOfAllRules]
|
||||
// Check if the specific rule is ignored
|
||||
|
@ -565,7 +570,7 @@ func (gosec *Analyzer) updateSuppressions(id string, ignores map[string][]Suppre
|
|||
// Track external suppressions.
|
||||
if gosec.ruleset.IsRuleSuppressed(id) {
|
||||
ignored = true
|
||||
suppressions = append(suppressions, SuppressionInfo{
|
||||
suppressions = append(suppressions, issue.SuppressionInfo{
|
||||
Kind: "external",
|
||||
Justification: externalSuppressionJustification,
|
||||
})
|
||||
|
@ -573,7 +578,7 @@ func (gosec *Analyzer) updateSuppressions(id string, ignores map[string][]Suppre
|
|||
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 gosec.showIgnored {
|
||||
issue.NoSec = ignored
|
||||
|
@ -590,27 +595,27 @@ func (gosec *Analyzer) updateIssues(issue *Issue, ignored bool, suppressions []S
|
|||
}
|
||||
}
|
||||
|
||||
func toGosecIssue(issue *analyzers.Issue) *Issue {
|
||||
return &Issue{
|
||||
File: issue.File,
|
||||
Line: issue.Line,
|
||||
Col: issue.Col,
|
||||
RuleID: issue.AnalyzerID,
|
||||
What: issue.What,
|
||||
Confidence: Score(issue.Confidence),
|
||||
Severity: Score(issue.Severity),
|
||||
func toGosecIssue(aissue *analyzers.Issue) *issue.Issue {
|
||||
return &issue.Issue{
|
||||
File: aissue.File,
|
||||
Line: aissue.Line,
|
||||
Col: aissue.Col,
|
||||
RuleID: aissue.AnalyzerID,
|
||||
What: aissue.What,
|
||||
Confidence: issue.Score(aissue.Confidence),
|
||||
Severity: issue.Score(aissue.Severity),
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// Reset clears state such as context, issues and metrics from the configured analyzer
|
||||
func (gosec *Analyzer) Reset() {
|
||||
gosec.context = &Context{}
|
||||
gosec.issues = make([]*Issue, 0, 16)
|
||||
gosec.issues = make([]*issue.Issue, 0, 16)
|
||||
gosec.stats = &Metrics{}
|
||||
gosec.ruleset = NewRuleSet()
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ import (
|
|||
|
||||
"github.com/securego/gosec/v2"
|
||||
"github.com/securego/gosec/v2/cmd/vflag"
|
||||
"github.com/securego/gosec/v2/issue"
|
||||
"github.com/securego/gosec/v2/report"
|
||||
"github.com/securego/gosec/v2/rules"
|
||||
)
|
||||
|
@ -265,22 +266,22 @@ func saveReport(filename, format string, rootPaths []string, reportInfo *gosec.R
|
|||
return nil
|
||||
}
|
||||
|
||||
func convertToScore(value string) (gosec.Score, error) {
|
||||
func convertToScore(value string) (issue.Score, error) {
|
||||
value = strings.ToLower(value)
|
||||
switch value {
|
||||
case "low":
|
||||
return gosec.Low, nil
|
||||
return issue.Low, nil
|
||||
case "medium":
|
||||
return gosec.Medium, nil
|
||||
return issue.Medium, nil
|
||||
case "high":
|
||||
return gosec.High, nil
|
||||
return issue.High, nil
|
||||
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) {
|
||||
result := make([]*gosec.Issue, 0)
|
||||
func filterIssues(issues []*issue.Issue, severity issue.Score, confidence issue.Score) ([]*issue.Issue, int) {
|
||||
result := make([]*issue.Issue, 0)
|
||||
trueIssues := 0
|
||||
for _, issue := range issues {
|
||||
if issue.Severity >= severity && issue.Confidence >= confidence {
|
||||
|
@ -293,7 +294,7 @@ func filterIssues(issues []*gosec.Issue, severity gosec.Score, confidence gosec.
|
|||
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
|
||||
for _, issue := range issues {
|
||||
if len(issue.Suppressions) == 0 {
|
||||
|
|
|
@ -5,7 +5,7 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/securego/gosec/v2"
|
||||
"github.com/securego/gosec/v2/issue"
|
||||
)
|
||||
|
||||
// handle ranges
|
||||
|
@ -14,7 +14,7 @@ func extractLineNumber(s string) int {
|
|||
return lineNumber
|
||||
}
|
||||
|
||||
type sortBySeverity []*gosec.Issue
|
||||
type sortBySeverity []*issue.Issue
|
||||
|
||||
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] }
|
||||
|
||||
// sortIssues sorts the issues by severity in descending order
|
||||
func sortIssues(issues []*gosec.Issue) {
|
||||
func sortIssues(issues []*issue.Issue) {
|
||||
sort.Sort(sortBySeverity(issues))
|
||||
}
|
||||
|
|
|
@ -5,22 +5,22 @@ import (
|
|||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "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",
|
||||
Line: "1",
|
||||
Col: "1",
|
||||
RuleID: "ruleID",
|
||||
What: "test",
|
||||
Confidence: gosec.High,
|
||||
Severity: gosec.High,
|
||||
Confidence: issue.High,
|
||||
Severity: issue.High,
|
||||
Code: "1: testcode",
|
||||
Cwe: gosec.GetCweByRule("G101"),
|
||||
Cwe: issue.GetCweByRule("G101"),
|
||||
}
|
||||
|
||||
func createIssue() gosec.Issue {
|
||||
func createIssue() issue.Issue {
|
||||
return defaultIssue
|
||||
}
|
||||
|
||||
|
@ -29,8 +29,8 @@ func TestRules(t *testing.T) {
|
|||
RunSpecs(t, "Sort issues Suite")
|
||||
}
|
||||
|
||||
func firstIsGreater(less, greater *gosec.Issue) {
|
||||
slice := []*gosec.Issue{less, greater}
|
||||
func firstIsGreater(less, greater *issue.Issue) {
|
||||
slice := []*issue.Issue{less, greater}
|
||||
|
||||
sortIssues(slice)
|
||||
|
||||
|
@ -40,9 +40,9 @@ func firstIsGreater(less, greater *gosec.Issue) {
|
|||
var _ = Describe("Sorting by Severity", func() {
|
||||
It("sorts by severity", func() {
|
||||
less := createIssue()
|
||||
less.Severity = gosec.Low
|
||||
less.Severity = issue.Low
|
||||
greater := createIssue()
|
||||
less.Severity = gosec.High
|
||||
less.Severity = issue.High
|
||||
firstIsGreater(&less, &greater)
|
||||
})
|
||||
|
||||
|
|
|
@ -9,5 +9,6 @@ import (
|
|||
"go/ast"
|
||||
|
||||
"github.com/securego/gosec/v2"
|
||||
"github.com/securego/gosec/v2/issue"
|
||||
)
|
||||
`))
|
||||
|
|
|
@ -7,7 +7,7 @@ var generatedRuleTmpl = template.Must(template.New("generated").Parse(`
|
|||
// DO NOT EDIT - generated by tlsconfig tool
|
||||
func New{{.Name}}TLSCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
|
||||
return &insecureConfigTLS{
|
||||
MetaData: gosec.MetaData{ID: id},
|
||||
MetaData: issue.MetaData{ID: id},
|
||||
requiredType: "crypto/tls.Config",
|
||||
MinVersion: {{ .MinVersion }},
|
||||
MaxVersion: {{ .MaxVersion }},
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package gosec
|
||||
package issue
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
|
@ -105,8 +105,15 @@ type Issue struct {
|
|||
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
|
||||
func (i Issue) FileLocation() string {
|
||||
func (i *Issue) FileLocation() string {
|
||||
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
|
||||
}
|
||||
|
||||
// NewIssue creates a new Issue
|
||||
func NewIssue(ctx *Context, node ast.Node, ruleID, desc string, severity Score, confidence Score) *Issue {
|
||||
fobj := ctx.FileSet.File(node.Pos())
|
||||
// New creates a new Issue
|
||||
func New(fobj *token.File, node ast.Node, ruleID, desc string, severity, confidence Score) *Issue {
|
||||
name := fobj.Name()
|
||||
start, end := fobj.Line(node.Pos()), fobj.Line(node.End())
|
||||
line := strconv.Itoa(start)
|
|
@ -1,4 +1,4 @@
|
|||
package gosec_test
|
||||
package issue_test
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
|
@ -6,6 +6,7 @@ import (
|
|||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/securego/gosec/v2"
|
||||
"github.com/securego/gosec/v2/issue"
|
||||
"github.com/securego/gosec/v2/rules"
|
||||
"github.com/securego/gosec/v2/testutils"
|
||||
)
|
||||
|
@ -36,7 +37,8 @@ var _ = Describe("Issue", func() {
|
|||
ast.Walk(v, ctx.Root)
|
||||
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.Code).Should(MatchRegexp(`"bar"`))
|
||||
Expect(issue.Line).Should(Equal("2"))
|
||||
|
@ -79,10 +81,10 @@ var _ = Describe("Issue", func() {
|
|||
// Use hardcodeded rule to check assignment
|
||||
cfg := gosec.NewConfig()
|
||||
rule, _ := rules.NewHardcodedCredentials("TEST", cfg)
|
||||
issue, err := rule.Match(target, ctx)
|
||||
foundIssue, err := rule.Match(target, ctx)
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
Expect(issue).ShouldNot(BeNil())
|
||||
Expect(issue.FileLocation()).Should(MatchRegexp("foo.go:5"))
|
||||
Expect(foundIssue).ShouldNot(BeNil())
|
||||
Expect(foundIssue.FileLocation()).Should(MatchRegexp("foo.go:5"))
|
||||
})
|
||||
|
||||
It("should provide accurate line and file information", func() {
|
|
@ -1,15 +1,19 @@
|
|||
package gosec
|
||||
|
||||
import (
|
||||
"github.com/securego/gosec/v2/issue"
|
||||
)
|
||||
|
||||
// ReportInfo this is report information
|
||||
type ReportInfo struct {
|
||||
Errors map[string][]Error `json:"Golang errors"`
|
||||
Issues []*Issue
|
||||
Issues []*issue.Issue
|
||||
Stats *Metrics
|
||||
GosecVersion string
|
||||
}
|
||||
|
||||
// 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{
|
||||
Errors: errors,
|
||||
Issues: issues,
|
||||
|
|
|
@ -18,6 +18,7 @@ import (
|
|||
"io"
|
||||
|
||||
"github.com/securego/gosec/v2"
|
||||
"github.com/securego/gosec/v2/issue"
|
||||
"github.com/securego/gosec/v2/report/csv"
|
||||
"github.com/securego/gosec/v2/report/golint"
|
||||
"github.com/securego/gosec/v2/report/html"
|
||||
|
@ -81,8 +82,8 @@ func CreateReport(w io.Writer, format string, enableColor bool, rootPaths []stri
|
|||
return err
|
||||
}
|
||||
|
||||
func filterOutSuppressedIssues(issues []*gosec.Issue) []*gosec.Issue {
|
||||
nonSuppressedIssues := []*gosec.Issue{}
|
||||
func filterOutSuppressedIssues(issues []*issue.Issue) []*issue.Issue {
|
||||
nonSuppressedIssues := []*issue.Issue{}
|
||||
for _, issue := range issues {
|
||||
if len(issue.Suppressions) == 0 {
|
||||
nonSuppressedIssues = append(nonSuppressedIssues, issue)
|
||||
|
|
|
@ -10,39 +10,40 @@ import (
|
|||
. "github.com/onsi/gomega"
|
||||
"github.com/securego/gosec/v2"
|
||||
"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/sonar"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
func createIssueWithFileWhat(file, what string) *gosec.Issue {
|
||||
issue := createIssue("i1", gosec.GetCweByRule("G101"))
|
||||
func createIssueWithFileWhat(file, what string) *issue.Issue {
|
||||
issue := createIssue("i1", issue.GetCweByRule("G101"))
|
||||
issue.File = file
|
||||
issue.What = what
|
||||
return &issue
|
||||
}
|
||||
|
||||
func createIssue(ruleID string, weakness *cwe.Weakness) gosec.Issue {
|
||||
return gosec.Issue{
|
||||
func createIssue(ruleID string, weakness *cwe.Weakness) issue.Issue {
|
||||
return issue.Issue{
|
||||
File: "/home/src/project/test.go",
|
||||
Line: "1",
|
||||
Col: "1",
|
||||
RuleID: ruleID,
|
||||
What: "test",
|
||||
Confidence: gosec.High,
|
||||
Severity: gosec.High,
|
||||
Confidence: issue.High,
|
||||
Severity: issue.High,
|
||||
Code: "1: testcode",
|
||||
Cwe: weakness,
|
||||
}
|
||||
}
|
||||
|
||||
func createReportInfo(rule string, weakness *cwe.Weakness) gosec.ReportInfo {
|
||||
issue := createIssue(rule, weakness)
|
||||
newissue := createIssue(rule, weakness)
|
||||
metrics := gosec.Metrics{}
|
||||
return gosec.ReportInfo{
|
||||
Errors: map[string][]gosec.Error{},
|
||||
Issues: []*gosec.Issue{
|
||||
&issue,
|
||||
Issues: []*issue.Issue{
|
||||
&newissue,
|
||||
},
|
||||
Stats: &metrics,
|
||||
}
|
||||
|
@ -62,7 +63,7 @@ var _ = Describe("Formatter", func() {
|
|||
It("it should parse the report info", func() {
|
||||
data := &gosec.ReportInfo{
|
||||
Errors: map[string][]gosec.Error{},
|
||||
Issues: []*gosec.Issue{
|
||||
Issues: []*issue.Issue{
|
||||
{
|
||||
Severity: 2,
|
||||
Confidence: 0,
|
||||
|
@ -110,7 +111,7 @@ var _ = Describe("Formatter", func() {
|
|||
It("it should parse the report info with files in subfolders", func() {
|
||||
data := &gosec.ReportInfo{
|
||||
Errors: map[string][]gosec.Error{},
|
||||
Issues: []*gosec.Issue{
|
||||
Issues: []*issue.Issue{
|
||||
{
|
||||
Severity: 2,
|
||||
Confidence: 0,
|
||||
|
@ -157,7 +158,7 @@ var _ = Describe("Formatter", func() {
|
|||
It("it should not parse the report info for files from other projects", func() {
|
||||
data := &gosec.ReportInfo{
|
||||
Errors: map[string][]gosec.Error{},
|
||||
Issues: []*gosec.Issue{
|
||||
Issues: []*issue.Issue{
|
||||
{
|
||||
Severity: 2,
|
||||
Confidence: 0,
|
||||
|
@ -189,7 +190,7 @@ var _ = Describe("Formatter", func() {
|
|||
It("it should parse the report info for multiple projects projects", func() {
|
||||
data := &gosec.ReportInfo{
|
||||
Errors: map[string][]gosec.Error{},
|
||||
Issues: []*gosec.Issue{
|
||||
Issues: []*issue.Issue{
|
||||
{
|
||||
Severity: 2,
|
||||
Confidence: 0,
|
||||
|
@ -261,7 +262,7 @@ var _ = Describe("Formatter", func() {
|
|||
|
||||
Context("When using junit", 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})
|
||||
|
||||
|
@ -285,12 +286,12 @@ var _ = Describe("Formatter", func() {
|
|||
|
||||
It("csv formatted report should contain the CWE mapping", func() {
|
||||
for _, rule := range grules {
|
||||
cwe := gosec.GetCweByRule(rule)
|
||||
issue := createIssue(rule, cwe)
|
||||
cwe := issue.GetCweByRule(rule)
|
||||
newissue := createIssue(rule, cwe)
|
||||
error := map[string][]gosec.Error{}
|
||||
|
||||
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)
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
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() {
|
||||
for _, rule := range grules {
|
||||
cwe := gosec.GetCweByRule(rule)
|
||||
issue := createIssue(rule, cwe)
|
||||
cwe := issue.GetCweByRule(rule)
|
||||
newissue := createIssue(rule, cwe)
|
||||
error := map[string][]gosec.Error{}
|
||||
|
||||
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)
|
||||
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"
|
||||
|
@ -315,8 +316,8 @@ var _ = Describe("Formatter", func() {
|
|||
})
|
||||
It("json formatted report should contain the CWE mapping", func() {
|
||||
for _, rule := range grules {
|
||||
cwe := gosec.GetCweByRule(rule)
|
||||
issue := createIssue(rule, cwe)
|
||||
cwe := issue.GetCweByRule(rule)
|
||||
newissue := createIssue(rule, cwe)
|
||||
error := map[string][]gosec.Error{}
|
||||
|
||||
data := createReportInfo(rule, cwe)
|
||||
|
@ -326,7 +327,7 @@ var _ = Describe("Formatter", func() {
|
|||
err := enc.Encode(data)
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
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)
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
result := stripString(buf.String())
|
||||
|
@ -336,8 +337,8 @@ var _ = Describe("Formatter", func() {
|
|||
})
|
||||
It("html formatted report should contain the CWE mapping", func() {
|
||||
for _, rule := range grules {
|
||||
cwe := gosec.GetCweByRule(rule)
|
||||
issue := createIssue(rule, cwe)
|
||||
cwe := issue.GetCweByRule(rule)
|
||||
newissue := createIssue(rule, cwe)
|
||||
error := map[string][]gosec.Error{}
|
||||
|
||||
data := createReportInfo(rule, cwe)
|
||||
|
@ -347,7 +348,7 @@ var _ = Describe("Formatter", func() {
|
|||
err := enc.Encode(data)
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
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)
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
result := stripString(buf.String())
|
||||
|
@ -357,8 +358,8 @@ var _ = Describe("Formatter", func() {
|
|||
})
|
||||
It("yaml formatted report should contain the CWE mapping", func() {
|
||||
for _, rule := range grules {
|
||||
cwe := gosec.GetCweByRule(rule)
|
||||
issue := createIssue(rule, cwe)
|
||||
cwe := issue.GetCweByRule(rule)
|
||||
newissue := createIssue(rule, cwe)
|
||||
error := map[string][]gosec.Error{}
|
||||
|
||||
data := createReportInfo(rule, cwe)
|
||||
|
@ -368,7 +369,7 @@ var _ = Describe("Formatter", func() {
|
|||
err := enc.Encode(data)
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
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)
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
result := stripString(buf.String())
|
||||
|
@ -378,8 +379,8 @@ var _ = Describe("Formatter", func() {
|
|||
})
|
||||
It("junit-xml formatted report should contain the CWE mapping", func() {
|
||||
for _, rule := range grules {
|
||||
cwe := gosec.GetCweByRule(rule)
|
||||
issue := createIssue(rule, cwe)
|
||||
cwe := issue.GetCweByRule(rule)
|
||||
newissue := createIssue(rule, cwe)
|
||||
error := map[string][]gosec.Error{}
|
||||
|
||||
data := createReportInfo(rule, cwe)
|
||||
|
@ -389,7 +390,7 @@ var _ = Describe("Formatter", func() {
|
|||
err := enc.Encode(data)
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
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)
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
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() {
|
||||
for _, rule := range grules {
|
||||
cwe := gosec.GetCweByRule(rule)
|
||||
issue := createIssue(rule, cwe)
|
||||
cwe := issue.GetCweByRule(rule)
|
||||
newissue := createIssue(rule, cwe)
|
||||
error := map[string][]gosec.Error{}
|
||||
|
||||
data := createReportInfo(rule, cwe)
|
||||
|
@ -410,7 +411,7 @@ var _ = Describe("Formatter", func() {
|
|||
err := enc.Encode(data)
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
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)
|
||||
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))
|
||||
|
@ -420,11 +421,11 @@ var _ = Describe("Formatter", func() {
|
|||
})
|
||||
It("sonarqube formatted report shouldn't contain the CWE mapping", func() {
|
||||
for _, rule := range grules {
|
||||
cwe := gosec.GetCweByRule(rule)
|
||||
issue := createIssue(rule, cwe)
|
||||
cwe := issue.GetCweByRule(rule)
|
||||
newissue := createIssue(rule, cwe)
|
||||
error := map[string][]gosec.Error{}
|
||||
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)
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
|
||||
|
@ -441,12 +442,12 @@ var _ = Describe("Formatter", func() {
|
|||
})
|
||||
It("golint formatted report should contain the CWE mapping", func() {
|
||||
for _, rule := range grules {
|
||||
cwe := gosec.GetCweByRule(rule)
|
||||
issue := createIssue(rule, cwe)
|
||||
cwe := issue.GetCweByRule(rule)
|
||||
newissue := createIssue(rule, cwe)
|
||||
error := map[string][]gosec.Error{}
|
||||
|
||||
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)
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
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() {
|
||||
for _, rule := range grules {
|
||||
cwe := gosec.GetCweByRule(rule)
|
||||
issue := createIssue(rule, cwe)
|
||||
cwe := issue.GetCweByRule(rule)
|
||||
newissue := createIssue(rule, cwe)
|
||||
error := map[string][]gosec.Error{}
|
||||
|
||||
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)
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
|
||||
|
@ -490,8 +491,8 @@ var _ = Describe("Formatter", func() {
|
|||
|
||||
Context("When converting suppressed issues", func() {
|
||||
ruleID := "G101"
|
||||
cwe := gosec.GetCweByRule(ruleID)
|
||||
suppressions := []gosec.SuppressionInfo{
|
||||
cwe := issue.GetCweByRule(ruleID)
|
||||
suppressions := []issue.SuppressionInfo{
|
||||
{
|
||||
Kind: "kind",
|
||||
Justification: "justification",
|
||||
|
@ -502,7 +503,7 @@ var _ = Describe("Formatter", func() {
|
|||
|
||||
It("text formatted report should contain the suppressed issues", func() {
|
||||
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)
|
||||
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() {
|
||||
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)
|
||||
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() {
|
||||
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)
|
||||
err := CreateReport(buf, "json", false, []string{}, reportInfo)
|
||||
|
|
|
@ -5,9 +5,10 @@ import (
|
|||
"strconv"
|
||||
|
||||
"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"
|
||||
if issue.Cwe != nil {
|
||||
cweID = issue.Cwe.ID
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"github.com/google/uuid"
|
||||
"github.com/securego/gosec/v2"
|
||||
"github.com/securego/gosec/v2/cwe"
|
||||
"github.com/securego/gosec/v2/issue"
|
||||
)
|
||||
|
||||
// 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
|
||||
func parseSarifRule(issue *gosec.Issue) *ReportingDescriptor {
|
||||
cwe := gosec.GetCweByRule(issue.RuleID)
|
||||
name := issue.RuleID
|
||||
func parseSarifRule(i *issue.Issue) *ReportingDescriptor {
|
||||
cwe := issue.GetCweByRule(i.RuleID)
|
||||
name := i.RuleID
|
||||
if cwe != nil {
|
||||
name = cwe.Name
|
||||
}
|
||||
return &ReportingDescriptor{
|
||||
ID: issue.RuleID,
|
||||
ID: i.RuleID,
|
||||
Name: name,
|
||||
ShortDescription: NewMultiformatMessageString(issue.What),
|
||||
FullDescription: NewMultiformatMessageString(issue.What),
|
||||
ShortDescription: NewMultiformatMessageString(i.What),
|
||||
FullDescription: NewMultiformatMessageString(i.What),
|
||||
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{
|
||||
"tags": []string{"security", issue.Severity.String()},
|
||||
"precision": strings.ToLower(issue.Confidence.String()),
|
||||
"tags": []string{"security", i.Severity.String()},
|
||||
"precision": strings.ToLower(i.Confidence.String()),
|
||||
},
|
||||
DefaultConfiguration: &ReportingConfiguration{
|
||||
Level: getSarifLevel(issue.Severity.String()),
|
||||
Level: getSarifLevel(i.Severity.String()),
|
||||
},
|
||||
Relationships: []*ReportingDescriptorRelationship{
|
||||
buildSarifReportingDescriptorRelationship(issue.Cwe),
|
||||
buildSarifReportingDescriptorRelationship(i.Cwe),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -157,27 +158,27 @@ func uuid3(value string) string {
|
|||
}
|
||||
|
||||
// parseSarifLocation return SARIF location struct
|
||||
func parseSarifLocation(issue *gosec.Issue, rootPaths []string) (*Location, error) {
|
||||
region, err := parseSarifRegion(issue)
|
||||
func parseSarifLocation(i *issue.Issue, rootPaths []string) (*Location, error) {
|
||||
region, err := parseSarifRegion(i)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
artifactLocation := parseSarifArtifactLocation(issue, rootPaths)
|
||||
artifactLocation := parseSarifArtifactLocation(i, rootPaths)
|
||||
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
|
||||
for _, rootPath := range rootPaths {
|
||||
if strings.HasPrefix(issue.File, rootPath) {
|
||||
filePath = strings.Replace(issue.File, rootPath+"/", "", 1)
|
||||
if strings.HasPrefix(i.File, rootPath) {
|
||||
filePath = strings.Replace(i.File, rootPath+"/", "", 1)
|
||||
}
|
||||
}
|
||||
return NewArtifactLocation(filePath)
|
||||
}
|
||||
|
||||
func parseSarifRegion(issue *gosec.Issue) (*Region, error) {
|
||||
lines := strings.Split(issue.Line, "-")
|
||||
func parseSarifRegion(i *issue.Issue) (*Region, error) {
|
||||
lines := strings.Split(i.Line, "-")
|
||||
startLine, err := strconv.Atoi(lines[0])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -189,13 +190,13 @@ func parseSarifRegion(issue *gosec.Issue) (*Region, error) {
|
|||
return nil, err
|
||||
}
|
||||
}
|
||||
col, err := strconv.Atoi(issue.Col)
|
||||
col, err := strconv.Atoi(i.Col)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var code string
|
||||
line := startLine
|
||||
codeLines := strings.Split(issue.Code, "\n")
|
||||
codeLines := strings.Split(i.Code, "\n")
|
||||
for _, codeLine := range codeLines {
|
||||
lineStart := fmt.Sprintf("%d:", line)
|
||||
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
|
||||
for _, s := range suppressions {
|
||||
sarifSuppressionList = append(sarifSuppressionList, NewSuppression(s.Kind, s.Justification))
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/securego/gosec/v2"
|
||||
"github.com/securego/gosec/v2/issue"
|
||||
"github.com/securego/gosec/v2/report/sarif"
|
||||
)
|
||||
|
||||
|
@ -16,7 +17,7 @@ var _ = Describe("Sarif Formatter", func() {
|
|||
Context("when converting to Sarif issues", func() {
|
||||
It("sarif formatted report should contain the result", func() {
|
||||
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{})
|
||||
result := buf.String()
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
|
@ -25,18 +26,18 @@ var _ = Describe("Sarif Formatter", func() {
|
|||
|
||||
It("sarif formatted report should contain the suppressed results", func() {
|
||||
ruleID := "G101"
|
||||
cwe := gosec.GetCweByRule(ruleID)
|
||||
suppressedIssue := gosec.Issue{
|
||||
cwe := issue.GetCweByRule(ruleID)
|
||||
suppressedIssue := issue.Issue{
|
||||
File: "/home/src/project/test.go",
|
||||
Line: "1",
|
||||
Col: "1",
|
||||
RuleID: ruleID,
|
||||
What: "test",
|
||||
Confidence: gosec.High,
|
||||
Severity: gosec.High,
|
||||
Confidence: issue.High,
|
||||
Severity: issue.High,
|
||||
Code: "1: testcode",
|
||||
Cwe: cwe,
|
||||
Suppressions: []gosec.SuppressionInfo{
|
||||
Suppressions: []issue.SuppressionInfo{
|
||||
{
|
||||
Kind: "kind",
|
||||
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)
|
||||
err := sarif.WriteReport(buf, reportInfo, []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() {
|
||||
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"
|
||||
expectedCode := "var data = template.HTML(v.TmplFile)"
|
||||
issue := gosec.Issue{
|
||||
newissue := issue.Issue{
|
||||
File: "/home/src/project/test.go",
|
||||
Line: "69",
|
||||
Col: "14",
|
||||
RuleID: ruleID,
|
||||
What: "test",
|
||||
Confidence: gosec.High,
|
||||
Severity: gosec.High,
|
||||
Confidence: issue.High,
|
||||
Severity: issue.High,
|
||||
Code: code,
|
||||
Cwe: cwe,
|
||||
Suppressions: []gosec.SuppressionInfo{
|
||||
Suppressions: []issue.SuppressionInfo{
|
||||
{
|
||||
Kind: "kind",
|
||||
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)
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
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() {
|
||||
ruleID := "G101"
|
||||
cwe := gosec.GetCweByRule(ruleID)
|
||||
cwe := issue.GetCweByRule(ruleID)
|
||||
code := "68: }\n69: var data = template.HTML(v.TmplFile)\n70: isTmpl := true\n"
|
||||
expectedCode := "var data = template.HTML(v.TmplFile)\nisTmpl := true\n"
|
||||
issue := gosec.Issue{
|
||||
newissue := issue.Issue{
|
||||
File: "/home/src/project/test.go",
|
||||
Line: "69-70",
|
||||
Col: "14",
|
||||
RuleID: ruleID,
|
||||
What: "test",
|
||||
Confidence: gosec.High,
|
||||
Severity: gosec.High,
|
||||
Confidence: issue.High,
|
||||
Severity: issue.High,
|
||||
Code: code,
|
||||
Cwe: cwe,
|
||||
Suppressions: []gosec.SuppressionInfo{
|
||||
Suppressions: []issue.SuppressionInfo{
|
||||
{
|
||||
Kind: "kind",
|
||||
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)
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
Expect(sarifReport.Runs[0].Results[0].Locations[0].PhysicalLocation.Region.Snippet.Text).Should(Equal(expectedCode))
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/securego/gosec/v2"
|
||||
"github.com/securego/gosec/v2/issue"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -36,7 +37,7 @@ func GenerateReport(rootPaths []string, data *gosec.ReportInfo) (*Report, error)
|
|||
return si, nil
|
||||
}
|
||||
|
||||
func parseFilePath(issue *gosec.Issue, rootPaths []string) string {
|
||||
func parseFilePath(issue *issue.Issue, rootPaths []string) string {
|
||||
var sonarFilePath string
|
||||
for _, rootPath := range rootPaths {
|
||||
if strings.HasPrefix(issue.File, rootPath) {
|
||||
|
@ -46,7 +47,7 @@ func parseFilePath(issue *gosec.Issue, rootPaths []string) string {
|
|||
return sonarFilePath
|
||||
}
|
||||
|
||||
func parseTextRange(issue *gosec.Issue) (*TextRange, error) {
|
||||
func parseTextRange(issue *issue.Issue) (*TextRange, error) {
|
||||
lines := strings.Split(issue.Line, "-")
|
||||
startLine, err := strconv.Atoi(lines[0])
|
||||
if err != nil {
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/securego/gosec/v2"
|
||||
"github.com/securego/gosec/v2/issue"
|
||||
"github.com/securego/gosec/v2/report/sonar"
|
||||
)
|
||||
|
||||
|
@ -14,7 +15,7 @@ var _ = Describe("Sonar Formatter", func() {
|
|||
It("it should parse the report info", func() {
|
||||
data := &gosec.ReportInfo{
|
||||
Errors: map[string][]gosec.Error{},
|
||||
Issues: []*gosec.Issue{
|
||||
Issues: []*issue.Issue{
|
||||
{
|
||||
Severity: 2,
|
||||
Confidence: 0,
|
||||
|
@ -62,7 +63,7 @@ var _ = Describe("Sonar Formatter", func() {
|
|||
It("it should parse the report info with files in subfolders", func() {
|
||||
data := &gosec.ReportInfo{
|
||||
Errors: map[string][]gosec.Error{},
|
||||
Issues: []*gosec.Issue{
|
||||
Issues: []*issue.Issue{
|
||||
{
|
||||
Severity: 2,
|
||||
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() {
|
||||
data := &gosec.ReportInfo{
|
||||
Errors: map[string][]gosec.Error{},
|
||||
Issues: []*gosec.Issue{
|
||||
Issues: []*issue.Issue{
|
||||
{
|
||||
Severity: 2,
|
||||
Confidence: 0,
|
||||
|
@ -141,7 +142,7 @@ var _ = Describe("Sonar Formatter", func() {
|
|||
It("it should parse the report info for multiple projects projects", func() {
|
||||
data := &gosec.ReportInfo{
|
||||
Errors: map[string][]gosec.Error{},
|
||||
Issues: []*gosec.Issue{
|
||||
Issues: []*issue.Issue{
|
||||
{
|
||||
Severity: 2,
|
||||
Confidence: 0,
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
|
||||
"github.com/gookit/color"
|
||||
"github.com/securego/gosec/v2"
|
||||
"github.com/securego/gosec/v2/issue"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -49,7 +50,7 @@ func plainTextFuncMap(enableColor bool) template.FuncMap {
|
|||
|
||||
// by default those functions return the given content untouched
|
||||
return template.FuncMap{
|
||||
"highlight": func(t string, s gosec.Score, ignored bool) string {
|
||||
"highlight": func(t string, s issue.Score, ignored bool) string {
|
||||
return t
|
||||
},
|
||||
"danger": fmt.Sprint,
|
||||
|
@ -60,14 +61,14 @@ func plainTextFuncMap(enableColor bool) template.FuncMap {
|
|||
}
|
||||
|
||||
// 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 {
|
||||
return defaultTheme.Sprint(t)
|
||||
}
|
||||
switch s {
|
||||
case gosec.High:
|
||||
case issue.High:
|
||||
return errorTheme.Sprint(t)
|
||||
case gosec.Medium:
|
||||
case issue.Medium:
|
||||
return warningTheme.Sprint(t)
|
||||
default:
|
||||
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
|
||||
func printCodeSnippet(issue *gosec.Issue) string {
|
||||
func printCodeSnippet(issue *issue.Issue) string {
|
||||
start, end := parseLine(issue.Line)
|
||||
scanner := bufio.NewScanner(strings.NewReader(issue.Code))
|
||||
var buf bytes.Buffer
|
||||
|
|
4
rule.go
4
rule.go
|
@ -15,12 +15,14 @@ package gosec
|
|||
import (
|
||||
"go/ast"
|
||||
"reflect"
|
||||
|
||||
"github.com/securego/gosec/v2/issue"
|
||||
)
|
||||
|
||||
// The Rule interface used by all rules supported by gosec.
|
||||
type Rule interface {
|
||||
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
|
||||
|
|
11
rule_test.go
11
rule_test.go
|
@ -7,10 +7,11 @@ import (
|
|||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/securego/gosec/v2"
|
||||
"github.com/securego/gosec/v2/issue"
|
||||
)
|
||||
|
||||
type mockrule struct {
|
||||
issue *gosec.Issue
|
||||
issue *issue.Issue
|
||||
err error
|
||||
callback func(n ast.Node, ctx *gosec.Context) bool
|
||||
}
|
||||
|
@ -19,7 +20,7 @@ func (m *mockrule) ID() string {
|
|||
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) {
|
||||
return m.issue, nil
|
||||
}
|
||||
|
@ -42,9 +43,9 @@ var _ = Describe("Rule", func() {
|
|||
callback: func(n ast.Node, ctx *gosec.Context) bool { return false },
|
||||
}
|
||||
dummyIssueRule = &mockrule{
|
||||
issue: &gosec.Issue{
|
||||
Severity: gosec.High,
|
||||
Confidence: gosec.High,
|
||||
issue: &issue.Issue{
|
||||
Severity: issue.High,
|
||||
Confidence: issue.High,
|
||||
What: `Some explanation of the thing`,
|
||||
File: "main.go",
|
||||
Code: `#include <stdio.h> int main(){ puts("hello world"); }`,
|
||||
|
|
|
@ -5,10 +5,11 @@ import (
|
|||
"go/types"
|
||||
|
||||
"github.com/securego/gosec/v2"
|
||||
"github.com/securego/gosec/v2/issue"
|
||||
)
|
||||
|
||||
type archive struct {
|
||||
gosec.MetaData
|
||||
issue.MetaData
|
||||
calls gosec.CallList
|
||||
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
|
||||
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 {
|
||||
for _, arg := range node.Args {
|
||||
var argType types.Type
|
||||
|
@ -38,7 +39,7 @@ func (a *archive) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
|
|||
if argType != nil {
|
||||
for _, t := range a.argTypes {
|
||||
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{
|
||||
calls: calls,
|
||||
argTypes: []string{"*archive/zip.File", "*archive/tar.Header"},
|
||||
MetaData: gosec.MetaData{
|
||||
MetaData: issue.MetaData{
|
||||
ID: id,
|
||||
Severity: gosec.Medium,
|
||||
Confidence: gosec.High,
|
||||
Severity: issue.Medium,
|
||||
Confidence: issue.High,
|
||||
What: "File traversal when extracting zip/tar archive",
|
||||
},
|
||||
}, []ast.Node{(*ast.CallExpr)(nil)}
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/securego/gosec/v2"
|
||||
"github.com/securego/gosec/v2/issue"
|
||||
)
|
||||
|
||||
type deferType struct {
|
||||
|
@ -14,7 +15,7 @@ type deferType struct {
|
|||
}
|
||||
|
||||
type badDefer struct {
|
||||
gosec.MetaData
|
||||
issue.MetaData
|
||||
types []deferType
|
||||
}
|
||||
|
||||
|
@ -35,12 +36,12 @@ func contains(methods []string, method string) bool {
|
|||
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 {
|
||||
for _, deferTyp := range r.types {
|
||||
if typ, method, err := gosec.GetCallInfo(deferStmt.Call, c); err == nil {
|
||||
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"},
|
||||
},
|
||||
},
|
||||
MetaData: gosec.MetaData{
|
||||
MetaData: issue.MetaData{
|
||||
ID: id,
|
||||
Severity: gosec.Medium,
|
||||
Confidence: gosec.High,
|
||||
Severity: issue.Medium,
|
||||
Confidence: issue.High,
|
||||
What: "Deferring unsafe method %q on type %q",
|
||||
},
|
||||
}, []ast.Node{(*ast.DeferStmt)(nil)}
|
||||
|
|
|
@ -19,11 +19,12 @@ import (
|
|||
"regexp"
|
||||
|
||||
"github.com/securego/gosec/v2"
|
||||
"github.com/securego/gosec/v2/issue"
|
||||
)
|
||||
|
||||
// Looks for net.Listen("0.0.0.0") or net.Listen(":8080")
|
||||
type bindsToAllNetworkInterfaces struct {
|
||||
gosec.MetaData
|
||||
issue.MetaData
|
||||
calls gosec.CallList
|
||||
pattern *regexp.Regexp
|
||||
}
|
||||
|
@ -32,7 +33,7 @@ func (r *bindsToAllNetworkInterfaces) ID() string {
|
|||
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)
|
||||
if callExpr == 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 arg, err := gosec.GetString(bl); err == nil {
|
||||
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 {
|
||||
values := gosec.GetIdentStringValues(ident)
|
||||
for _, value := range values {
|
||||
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)
|
||||
for _, value := range values {
|
||||
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{
|
||||
calls: calls,
|
||||
pattern: regexp.MustCompile(`^(0.0.0.0|:).*$`),
|
||||
MetaData: gosec.MetaData{
|
||||
MetaData: issue.MetaData{
|
||||
ID: id,
|
||||
Severity: gosec.Medium,
|
||||
Confidence: gosec.High,
|
||||
Severity: issue.Medium,
|
||||
Confidence: issue.High,
|
||||
What: "Binds to all network interfaces",
|
||||
},
|
||||
}, []ast.Node{(*ast.CallExpr)(nil)}
|
||||
|
|
|
@ -19,10 +19,11 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/securego/gosec/v2"
|
||||
"github.com/securego/gosec/v2/issue"
|
||||
)
|
||||
|
||||
type blocklistedImport struct {
|
||||
gosec.MetaData
|
||||
issue.MetaData
|
||||
Blocklisted map[string]string
|
||||
}
|
||||
|
||||
|
@ -36,10 +37,10 @@ func (r *blocklistedImport) ID() string {
|
|||
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 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
|
||||
|
@ -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.
|
||||
func NewBlocklistedImports(id string, conf gosec.Config, blocklist map[string]string) (gosec.Rule, []ast.Node) {
|
||||
return &blocklistedImport{
|
||||
MetaData: gosec.MetaData{
|
||||
MetaData: issue.MetaData{
|
||||
ID: id,
|
||||
Severity: gosec.Medium,
|
||||
Confidence: gosec.High,
|
||||
Severity: issue.Medium,
|
||||
Confidence: issue.High,
|
||||
},
|
||||
Blocklisted: blocklist,
|
||||
}, []ast.Node{(*ast.ImportSpec)(nil)}
|
||||
|
|
|
@ -19,10 +19,11 @@ import (
|
|||
"go/ast"
|
||||
|
||||
"github.com/securego/gosec/v2"
|
||||
"github.com/securego/gosec/v2/issue"
|
||||
)
|
||||
|
||||
type decompressionBombCheck struct {
|
||||
gosec.MetaData
|
||||
issue.MetaData
|
||||
readerCalls 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)
|
||||
}
|
||||
|
||||
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{}
|
||||
|
||||
// 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 _, ok := readerVarObj[idt.Obj]; ok {
|
||||
// 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")
|
||||
|
||||
return &decompressionBombCheck{
|
||||
MetaData: gosec.MetaData{
|
||||
MetaData: issue.MetaData{
|
||||
ID: id,
|
||||
Severity: gosec.Medium,
|
||||
Confidence: gosec.Medium,
|
||||
Severity: issue.Medium,
|
||||
Confidence: issue.Medium,
|
||||
What: "Potential DoS vulnerability via decompression bomb",
|
||||
},
|
||||
readerCalls: readerCalls,
|
||||
|
|
|
@ -5,18 +5,19 @@ import (
|
|||
"regexp"
|
||||
|
||||
"github.com/securego/gosec/v2"
|
||||
"github.com/securego/gosec/v2/issue"
|
||||
)
|
||||
|
||||
type traversal struct {
|
||||
pattern *regexp.Regexp
|
||||
gosec.MetaData
|
||||
issue.MetaData
|
||||
}
|
||||
|
||||
func (r *traversal) ID() string {
|
||||
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) {
|
||||
case *ast.CallExpr:
|
||||
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
|
||||
}
|
||||
|
||||
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 {
|
||||
if basiclit, ok1 := i.(*ast.BasicLit); ok1 {
|
||||
if fun, ok2 := assign.Fun.(*ast.SelectorExpr); ok2 {
|
||||
if x, ok3 := fun.X.(*ast.Ident); ok3 {
|
||||
string := x.Name + "." + fun.Sel.Name + "(" + basiclit.Value + ")"
|
||||
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{
|
||||
pattern: regexp.MustCompile(pattern),
|
||||
MetaData: gosec.MetaData{
|
||||
MetaData: issue.MetaData{
|
||||
ID: id,
|
||||
What: "Potential directory traversal",
|
||||
Confidence: gosec.Medium,
|
||||
Severity: gosec.Medium,
|
||||
Confidence: issue.Medium,
|
||||
Severity: issue.Medium,
|
||||
},
|
||||
}, []ast.Node{(*ast.CallExpr)(nil)}
|
||||
}
|
||||
|
|
|
@ -19,10 +19,11 @@ import (
|
|||
"go/types"
|
||||
|
||||
"github.com/securego/gosec/v2"
|
||||
"github.com/securego/gosec/v2/issue"
|
||||
)
|
||||
|
||||
type noErrorCheck struct {
|
||||
gosec.MetaData
|
||||
issue.MetaData
|
||||
whitelist gosec.CallList
|
||||
}
|
||||
|
||||
|
@ -49,7 +50,7 @@ func returnsError(callExpr *ast.CallExpr, ctx *gosec.Context) int {
|
|||
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) {
|
||||
case *ast.AssignStmt:
|
||||
cfg := ctx.Config
|
||||
|
@ -61,7 +62,7 @@ func (r *noErrorCheck) Match(n ast.Node, ctx *gosec.Context) (*gosec.Issue, erro
|
|||
return nil, nil
|
||||
}
|
||||
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 {
|
||||
pos := returnsError(callExpr, ctx)
|
||||
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{
|
||||
MetaData: gosec.MetaData{
|
||||
MetaData: issue.MetaData{
|
||||
ID: id,
|
||||
Severity: gosec.Low,
|
||||
Confidence: gosec.High,
|
||||
Severity: issue.Low,
|
||||
Confidence: issue.High,
|
||||
What: "Errors unhandled.",
|
||||
},
|
||||
whitelist: whitelist,
|
||||
|
|
|
@ -20,10 +20,11 @@ import (
|
|||
"strconv"
|
||||
|
||||
"github.com/securego/gosec/v2"
|
||||
"github.com/securego/gosec/v2/issue"
|
||||
)
|
||||
|
||||
type filePermissions struct {
|
||||
gosec.MetaData
|
||||
issue.MetaData
|
||||
mode int64
|
||||
pkgs []string
|
||||
calls []string
|
||||
|
@ -54,12 +55,12 @@ func modeIsSubset(subset int64, superset int64) bool {
|
|||
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 {
|
||||
if callexpr, matched := gosec.MatchCallByPackage(n, c, pkg, r.calls...); matched {
|
||||
modeArg := callexpr.Args[len(callexpr.Args)-1]
|
||||
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,
|
||||
pkgs: []string{"io/ioutil", "os"},
|
||||
calls: []string{"WriteFile"},
|
||||
MetaData: gosec.MetaData{
|
||||
MetaData: issue.MetaData{
|
||||
ID: id,
|
||||
Severity: gosec.Medium,
|
||||
Confidence: gosec.High,
|
||||
Severity: issue.Medium,
|
||||
Confidence: issue.High,
|
||||
What: fmt.Sprintf("Expect WriteFile permissions to be %#o or less", mode),
|
||||
},
|
||||
}, []ast.Node{(*ast.CallExpr)(nil)}
|
||||
|
@ -90,10 +91,10 @@ func NewFilePerms(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
|
|||
mode: mode,
|
||||
pkgs: []string{"os"},
|
||||
calls: []string{"OpenFile", "Chmod"},
|
||||
MetaData: gosec.MetaData{
|
||||
MetaData: issue.MetaData{
|
||||
ID: id,
|
||||
Severity: gosec.Medium,
|
||||
Confidence: gosec.High,
|
||||
Severity: issue.Medium,
|
||||
Confidence: issue.High,
|
||||
What: fmt.Sprintf("Expect file permissions to be %#o or less", mode),
|
||||
},
|
||||
}, []ast.Node{(*ast.CallExpr)(nil)}
|
||||
|
@ -107,10 +108,10 @@ func NewMkdirPerms(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
|
|||
mode: mode,
|
||||
pkgs: []string{"os"},
|
||||
calls: []string{"Mkdir", "MkdirAll"},
|
||||
MetaData: gosec.MetaData{
|
||||
MetaData: issue.MetaData{
|
||||
ID: id,
|
||||
Severity: gosec.Medium,
|
||||
Confidence: gosec.High,
|
||||
Severity: issue.Medium,
|
||||
Confidence: issue.High,
|
||||
What: fmt.Sprintf("Expect directory permissions to be %#o or less", mode),
|
||||
},
|
||||
}, []ast.Node{(*ast.CallExpr)(nil)}
|
||||
|
|
|
@ -22,10 +22,11 @@ import (
|
|||
|
||||
zxcvbn "github.com/nbutton23/zxcvbn-go"
|
||||
"github.com/securego/gosec/v2"
|
||||
"github.com/securego/gosec/v2/issue"
|
||||
)
|
||||
|
||||
type credentials struct {
|
||||
gosec.MetaData
|
||||
issue.MetaData
|
||||
pattern *regexp.Regexp
|
||||
entropyThreshold float64
|
||||
perCharThreshold float64
|
||||
|
@ -53,7 +54,7 @@ func (r *credentials) isHighEntropyString(str string) bool {
|
|||
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) {
|
||||
case *ast.AssignStmt:
|
||||
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
|
||||
}
|
||||
|
||||
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 {
|
||||
if ident, ok := i.(*ast.Ident); ok {
|
||||
if r.pattern.MatchString(ident.Name) {
|
||||
for _, e := range assign.Rhs {
|
||||
if val, err := gosec.GetString(e); err == nil {
|
||||
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
|
||||
}
|
||||
|
||||
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 {
|
||||
if r.pattern.MatchString(ident.Name) && valueSpec.Values != nil {
|
||||
// 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 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
|
||||
}
|
||||
|
||||
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 {
|
||||
ident, ok := binaryExpr.X.(*ast.Ident)
|
||||
if !ok {
|
||||
|
@ -113,7 +114,7 @@ func (r *credentials) matchEqualityCheck(binaryExpr *ast.BinaryExpr, ctx *gosec.
|
|||
}
|
||||
if val, err := gosec.GetString(valueNode); err == nil {
|
||||
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,
|
||||
ignoreEntropy: ignoreEntropy,
|
||||
truncate: truncateString,
|
||||
MetaData: gosec.MetaData{
|
||||
MetaData: issue.MetaData{
|
||||
ID: id,
|
||||
What: "Potential hardcoded credentials",
|
||||
Confidence: gosec.Low,
|
||||
Severity: gosec.High,
|
||||
Confidence: issue.Low,
|
||||
Severity: issue.High,
|
||||
},
|
||||
}, []ast.Node{(*ast.AssignStmt)(nil), (*ast.ValueSpec)(nil), (*ast.BinaryExpr)(nil)}
|
||||
}
|
||||
|
|
|
@ -4,10 +4,11 @@ import (
|
|||
"go/ast"
|
||||
|
||||
"github.com/securego/gosec/v2"
|
||||
"github.com/securego/gosec/v2/issue"
|
||||
)
|
||||
|
||||
type httpServeWithoutTimeouts struct {
|
||||
gosec.MetaData
|
||||
issue.MetaData
|
||||
pkg string
|
||||
calls []string
|
||||
}
|
||||
|
@ -16,9 +17,9 @@ func (r *httpServeWithoutTimeouts) ID() string {
|
|||
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 {
|
||||
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
|
||||
}
|
||||
|
@ -28,11 +29,11 @@ func NewHTTPServeWithoutTimeouts(id string, conf gosec.Config) (gosec.Rule, []as
|
|||
return &httpServeWithoutTimeouts{
|
||||
pkg: "net/http",
|
||||
calls: []string{"ListenAndServe", "ListenAndServeTLS", "Serve", "ServeTLS"},
|
||||
MetaData: gosec.MetaData{
|
||||
MetaData: issue.MetaData{
|
||||
ID: id,
|
||||
What: "Use of net/http serve function that has no support for setting timeouts",
|
||||
Severity: gosec.Medium,
|
||||
Confidence: gosec.High,
|
||||
Severity: issue.Medium,
|
||||
Confidence: issue.High,
|
||||
},
|
||||
}, []ast.Node{(*ast.CallExpr)(nil)}
|
||||
}
|
||||
|
|
|
@ -5,10 +5,11 @@ import (
|
|||
"go/token"
|
||||
|
||||
"github.com/securego/gosec/v2"
|
||||
"github.com/securego/gosec/v2/issue"
|
||||
)
|
||||
|
||||
type implicitAliasing struct {
|
||||
gosec.MetaData
|
||||
issue.MetaData
|
||||
aliases map[*ast.Object]struct{}
|
||||
rightBrace token.Pos
|
||||
acceptableAlias []*ast.UnaryExpr
|
||||
|
@ -27,7 +28,7 @@ func containsUnary(exprs []*ast.UnaryExpr, expr *ast.UnaryExpr) bool {
|
|||
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) {
|
||||
case *ast.RangeStmt:
|
||||
// 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 ident, ok := node.X.(*ast.Ident); ok && node.Op.String() == "&" {
|
||||
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:
|
||||
|
@ -94,10 +95,10 @@ func NewImplicitAliasing(id string, conf gosec.Config) (gosec.Rule, []ast.Node)
|
|||
aliases: make(map[*ast.Object]struct{}),
|
||||
rightBrace: token.NoPos,
|
||||
acceptableAlias: make([]*ast.UnaryExpr, 0),
|
||||
MetaData: gosec.MetaData{
|
||||
MetaData: issue.MetaData{
|
||||
ID: id,
|
||||
Severity: gosec.Medium,
|
||||
Confidence: gosec.Medium,
|
||||
Severity: issue.Medium,
|
||||
Confidence: issue.Medium,
|
||||
What: "Implicit memory aliasing in for loop.",
|
||||
},
|
||||
}, []ast.Node{(*ast.RangeStmt)(nil), (*ast.UnaryExpr)(nil), (*ast.ReturnStmt)(nil)}
|
||||
|
|
|
@ -19,10 +19,11 @@ import (
|
|||
"go/ast"
|
||||
|
||||
"github.com/securego/gosec/v2"
|
||||
"github.com/securego/gosec/v2/issue"
|
||||
)
|
||||
|
||||
type integerOverflowCheck struct {
|
||||
gosec.MetaData
|
||||
issue.MetaData
|
||||
calls gosec.CallList
|
||||
}
|
||||
|
||||
|
@ -30,7 +31,7 @@ func (i *integerOverflowCheck) ID() string {
|
|||
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
|
||||
|
||||
// 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 _, ok := atoiVarObj[idt.Obj]; ok {
|
||||
// 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.Add("strconv", "Atoi")
|
||||
return &integerOverflowCheck{
|
||||
MetaData: gosec.MetaData{
|
||||
MetaData: issue.MetaData{
|
||||
ID: id,
|
||||
Severity: gosec.High,
|
||||
Confidence: gosec.Medium,
|
||||
Severity: issue.High,
|
||||
Confidence: issue.Medium,
|
||||
What: "Potential Integer overflow made by strconv.Atoi result conversion to int16/32",
|
||||
},
|
||||
calls: calls,
|
||||
|
|
|
@ -4,10 +4,11 @@ import (
|
|||
"go/ast"
|
||||
|
||||
"github.com/securego/gosec/v2"
|
||||
"github.com/securego/gosec/v2/issue"
|
||||
)
|
||||
|
||||
type usingOldMathBig struct {
|
||||
gosec.MetaData
|
||||
issue.MetaData
|
||||
calls gosec.CallList
|
||||
}
|
||||
|
||||
|
@ -15,18 +16,18 @@ func (r *usingOldMathBig) ID() string {
|
|||
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 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
confidence := gosec.Low
|
||||
confidence := issue.Low
|
||||
major, minor, build := gosec.GoVersion()
|
||||
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.
|
||||
|
@ -35,10 +36,10 @@ func NewUsingOldMathBig(id string, _ gosec.Config) (gosec.Rule, []ast.Node) {
|
|||
calls.Add("math/big.Rat", "SetString")
|
||||
return &usingOldMathBig{
|
||||
calls: calls,
|
||||
MetaData: gosec.MetaData{
|
||||
MetaData: issue.MetaData{
|
||||
ID: id,
|
||||
What: "Potential uncontrolled memory consumption in Rat.SetString (CVE-2022-23772)",
|
||||
Severity: gosec.High,
|
||||
Severity: issue.High,
|
||||
},
|
||||
}, []ast.Node{(*ast.CallExpr)(nil)}
|
||||
}
|
||||
|
|
|
@ -4,10 +4,11 @@ import (
|
|||
"go/ast"
|
||||
|
||||
"github.com/securego/gosec/v2"
|
||||
"github.com/securego/gosec/v2/issue"
|
||||
)
|
||||
|
||||
type pprofCheck struct {
|
||||
gosec.MetaData
|
||||
issue.MetaData
|
||||
importPath string
|
||||
importName string
|
||||
}
|
||||
|
@ -18,10 +19,10 @@ func (p *pprofCheck) ID() string {
|
|||
}
|
||||
|
||||
// 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 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
|
||||
|
@ -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
|
||||
func NewPprofCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
|
||||
return &pprofCheck{
|
||||
MetaData: gosec.MetaData{
|
||||
MetaData: issue.MetaData{
|
||||
ID: id,
|
||||
Severity: gosec.High,
|
||||
Confidence: gosec.High,
|
||||
Severity: issue.High,
|
||||
Confidence: issue.High,
|
||||
What: "Profiling endpoint is automatically exposed on /debug/pprof",
|
||||
},
|
||||
importPath: "net/http/pprof",
|
||||
|
|
|
@ -18,10 +18,11 @@ import (
|
|||
"go/ast"
|
||||
|
||||
"github.com/securego/gosec/v2"
|
||||
"github.com/securego/gosec/v2/issue"
|
||||
)
|
||||
|
||||
type weakRand struct {
|
||||
gosec.MetaData
|
||||
issue.MetaData
|
||||
funcNames []string
|
||||
packagePath string
|
||||
}
|
||||
|
@ -30,10 +31,10 @@ func (w *weakRand) ID() string {
|
|||
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 {
|
||||
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",
|
||||
},
|
||||
packagePath: "math/rand",
|
||||
MetaData: gosec.MetaData{
|
||||
MetaData: issue.MetaData{
|
||||
ID: id,
|
||||
Severity: gosec.High,
|
||||
Confidence: gosec.Medium,
|
||||
Severity: issue.High,
|
||||
Confidence: issue.Medium,
|
||||
What: "Use of weak random number generator (math/rand instead of crypto/rand)",
|
||||
},
|
||||
}, []ast.Node{(*ast.CallExpr)(nil)}
|
||||
|
|
|
@ -19,10 +19,11 @@ import (
|
|||
"go/types"
|
||||
|
||||
"github.com/securego/gosec/v2"
|
||||
"github.com/securego/gosec/v2/issue"
|
||||
)
|
||||
|
||||
type readfile struct {
|
||||
gosec.MetaData
|
||||
issue.MetaData
|
||||
gosec.CallList
|
||||
pathJoin 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`
|
||||
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 {
|
||||
r.trackFilepathClean(n)
|
||||
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))
|
||||
if callExpr, ok := arg.(*ast.CallExpr); ok {
|
||||
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")
|
||||
if binExp, ok := arg.(*ast.BinaryExpr); ok {
|
||||
// resolve all found identities from the BinaryExpr
|
||||
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 &&
|
||||
!gosec.TryResolve(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(),
|
||||
clean: gosec.NewCallList(),
|
||||
CallList: gosec.NewCallList(),
|
||||
MetaData: gosec.MetaData{
|
||||
MetaData: issue.MetaData{
|
||||
ID: id,
|
||||
What: "Potential file inclusion via variable",
|
||||
Severity: gosec.Medium,
|
||||
Confidence: gosec.High,
|
||||
Severity: issue.Medium,
|
||||
Confidence: issue.High,
|
||||
},
|
||||
cleanedVar: map[any]ast.Node{},
|
||||
}
|
||||
|
|
13
rules/rsa.go
13
rules/rsa.go
|
@ -19,10 +19,11 @@ import (
|
|||
"go/ast"
|
||||
|
||||
"github.com/securego/gosec/v2"
|
||||
"github.com/securego/gosec/v2/issue"
|
||||
)
|
||||
|
||||
type weakKeyStrength struct {
|
||||
gosec.MetaData
|
||||
issue.MetaData
|
||||
calls gosec.CallList
|
||||
bits int
|
||||
}
|
||||
|
@ -31,10 +32,10 @@ func (w *weakKeyStrength) ID() string {
|
|||
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 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
|
||||
|
@ -48,10 +49,10 @@ func NewWeakKeyStrength(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
|
|||
return &weakKeyStrength{
|
||||
calls: calls,
|
||||
bits: bits,
|
||||
MetaData: gosec.MetaData{
|
||||
MetaData: issue.MetaData{
|
||||
ID: id,
|
||||
Severity: gosec.Medium,
|
||||
Confidence: gosec.High,
|
||||
Severity: issue.Medium,
|
||||
Confidence: issue.High,
|
||||
What: fmt.Sprintf("RSA keys should be at least %d bits", bits),
|
||||
},
|
||||
}, []ast.Node{(*ast.CallExpr)(nil)}
|
||||
|
|
|
@ -18,10 +18,11 @@ import (
|
|||
"go/ast"
|
||||
|
||||
"github.com/securego/gosec/v2"
|
||||
"github.com/securego/gosec/v2/issue"
|
||||
)
|
||||
|
||||
type slowloris struct {
|
||||
gosec.MetaData
|
||||
issue.MetaData
|
||||
}
|
||||
|
||||
func (r *slowloris) ID() string {
|
||||
|
@ -44,13 +45,13 @@ func containsReadHeaderTimeout(node *ast.CompositeLit) bool {
|
|||
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) {
|
||||
case *ast.CompositeLit:
|
||||
actualType := ctx.Info.TypeOf(node.Type)
|
||||
if actualType != nil && actualType.String() == "net/http.Server" {
|
||||
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.
|
||||
func NewSlowloris(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
|
||||
return &slowloris{
|
||||
MetaData: gosec.MetaData{
|
||||
MetaData: issue.MetaData{
|
||||
ID: id,
|
||||
What: "Potential Slowloris Attack because ReadHeaderTimeout is not configured in the http.Server",
|
||||
Confidence: gosec.Low,
|
||||
Severity: gosec.Medium,
|
||||
Confidence: issue.Low,
|
||||
Severity: issue.Medium,
|
||||
},
|
||||
}, []ast.Node{(*ast.CompositeLit)(nil)}
|
||||
}
|
||||
|
|
29
rules/sql.go
29
rules/sql.go
|
@ -20,10 +20,11 @@ import (
|
|||
"regexp"
|
||||
|
||||
"github.com/securego/gosec/v2"
|
||||
"github.com/securego/gosec/v2/issue"
|
||||
)
|
||||
|
||||
type sqlStatement struct {
|
||||
gosec.MetaData
|
||||
issue.MetaData
|
||||
gosec.CallList
|
||||
|
||||
// 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
|
||||
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)
|
||||
if err != nil {
|
||||
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) {
|
||||
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"
|
||||
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) {
|
||||
case *ast.AssignStmt:
|
||||
for _, expr := range stmt.Rhs {
|
||||
|
@ -166,10 +167,10 @@ func NewSQLStrConcat(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
|
|||
patterns: []*regexp.Regexp{
|
||||
regexp.MustCompile(`(?i)(SELECT|DELETE|INSERT|UPDATE|INTO|FROM|WHERE) `),
|
||||
},
|
||||
MetaData: gosec.MetaData{
|
||||
MetaData: issue.MetaData{
|
||||
ID: id,
|
||||
Severity: gosec.Medium,
|
||||
Confidence: gosec.High,
|
||||
Severity: issue.Medium,
|
||||
Confidence: issue.High,
|
||||
What: "SQL string concatenation",
|
||||
},
|
||||
CallList: gosec.NewCallList(),
|
||||
|
@ -212,7 +213,7 @@ func (s *sqlStrFormat) constObject(e ast.Expr, c *gosec.Context) bool {
|
|||
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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -233,7 +234,7 @@ func (s *sqlStrFormat) checkQuery(call *ast.CallExpr, ctx *gosec.Context) (*gose
|
|||
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 := 0
|
||||
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) {
|
||||
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
|
||||
}
|
||||
|
||||
// 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) {
|
||||
case *ast.AssignStmt:
|
||||
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("%[^bdoxXfFp]"),
|
||||
},
|
||||
MetaData: gosec.MetaData{
|
||||
MetaData: issue.MetaData{
|
||||
ID: id,
|
||||
Severity: gosec.Medium,
|
||||
Confidence: gosec.High,
|
||||
Severity: issue.Medium,
|
||||
Confidence: issue.High,
|
||||
What: "SQL string formatting",
|
||||
},
|
||||
},
|
||||
|
|
13
rules/ssh.go
13
rules/ssh.go
|
@ -4,10 +4,11 @@ import (
|
|||
"go/ast"
|
||||
|
||||
"github.com/securego/gosec/v2"
|
||||
"github.com/securego/gosec/v2/issue"
|
||||
)
|
||||
|
||||
type sshHostKey struct {
|
||||
gosec.MetaData
|
||||
issue.MetaData
|
||||
pkg string
|
||||
calls []string
|
||||
}
|
||||
|
@ -16,9 +17,9 @@ func (r *sshHostKey) ID() string {
|
|||
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 {
|
||||
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
|
||||
}
|
||||
|
@ -28,11 +29,11 @@ func NewSSHHostKey(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
|
|||
return &sshHostKey{
|
||||
pkg: "golang.org/x/crypto/ssh",
|
||||
calls: []string{"InsecureIgnoreHostKey"},
|
||||
MetaData: gosec.MetaData{
|
||||
MetaData: issue.MetaData{
|
||||
ID: id,
|
||||
What: "Use of ssh InsecureIgnoreHostKey should be audited",
|
||||
Severity: gosec.Medium,
|
||||
Confidence: gosec.High,
|
||||
Severity: issue.Medium,
|
||||
Confidence: issue.High,
|
||||
},
|
||||
}, []ast.Node{(*ast.CallExpr)(nil)}
|
||||
}
|
||||
|
|
|
@ -5,10 +5,11 @@ import (
|
|||
"go/types"
|
||||
|
||||
"github.com/securego/gosec/v2"
|
||||
"github.com/securego/gosec/v2/issue"
|
||||
)
|
||||
|
||||
type ssrf struct {
|
||||
gosec.MetaData
|
||||
issue.MetaData
|
||||
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
|
||||
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
|
||||
if node := r.ContainsPkgCallExpr(n, c, false); node != nil {
|
||||
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
|
||||
|
@ -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) {
|
||||
rule := &ssrf{
|
||||
CallList: gosec.NewCallList(),
|
||||
MetaData: gosec.MetaData{
|
||||
MetaData: issue.MetaData{
|
||||
ID: id,
|
||||
What: "Potential HTTP request made with variable url",
|
||||
Severity: gosec.Medium,
|
||||
Confidence: gosec.Medium,
|
||||
Severity: issue.Medium,
|
||||
Confidence: issue.Medium,
|
||||
},
|
||||
}
|
||||
rule.AddAll("net/http", "Do", "Get", "Head", "Post", "PostForm", "RoundTrip")
|
||||
|
|
|
@ -19,10 +19,11 @@ import (
|
|||
"go/types"
|
||||
|
||||
"github.com/securego/gosec/v2"
|
||||
"github.com/securego/gosec/v2/issue"
|
||||
)
|
||||
|
||||
type subprocess struct {
|
||||
gosec.MetaData
|
||||
issue.MetaData
|
||||
gosec.CallList
|
||||
}
|
||||
|
||||
|
@ -39,7 +40,7 @@ func (r *subprocess) ID() string {
|
|||
// is unsafe. For example:
|
||||
//
|
||||
// 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 {
|
||||
args := node.Args
|
||||
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)
|
||||
if variable && assignment {
|
||||
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:
|
||||
|
@ -74,21 +75,21 @@ func (r *subprocess) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
|
|||
vv, vvok := obj.(*types.Var)
|
||||
|
||||
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:
|
||||
_, valueSpec := ident.Obj.Decl.(*ast.ValueSpec)
|
||||
if variable && valueSpec {
|
||||
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) {
|
||||
// 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
|
||||
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", "CommandContext")
|
||||
rule.Add("syscall", "Exec")
|
||||
|
|
|
@ -19,10 +19,11 @@ import (
|
|||
"regexp"
|
||||
|
||||
"github.com/securego/gosec/v2"
|
||||
"github.com/securego/gosec/v2/issue"
|
||||
)
|
||||
|
||||
type badTempFile struct {
|
||||
gosec.MetaData
|
||||
issue.MetaData
|
||||
calls gosec.CallList
|
||||
args *regexp.Regexp
|
||||
argCalls gosec.CallList
|
||||
|
@ -33,15 +34,15 @@ func (t *badTempFile) ID() string {
|
|||
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 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
|
||||
}
|
||||
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 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
|
||||
}
|
||||
|
||||
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 {
|
||||
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(/.*)?$`),
|
||||
argCalls: argCalls,
|
||||
nestedCalls: nestedCalls,
|
||||
MetaData: gosec.MetaData{
|
||||
MetaData: issue.MetaData{
|
||||
ID: id,
|
||||
Severity: gosec.Medium,
|
||||
Confidence: gosec.High,
|
||||
Severity: issue.Medium,
|
||||
Confidence: issue.High,
|
||||
What: "File creation in shared tmp directory without using ioutil.Tempfile",
|
||||
},
|
||||
}, []ast.Node{(*ast.CallExpr)(nil)}
|
||||
|
|
|
@ -18,10 +18,11 @@ import (
|
|||
"go/ast"
|
||||
|
||||
"github.com/securego/gosec/v2"
|
||||
"github.com/securego/gosec/v2/issue"
|
||||
)
|
||||
|
||||
type templateCheck struct {
|
||||
gosec.MetaData
|
||||
issue.MetaData
|
||||
calls gosec.CallList
|
||||
}
|
||||
|
||||
|
@ -29,11 +30,11 @@ func (t *templateCheck) ID() string {
|
|||
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 {
|
||||
for _, arg := range node.Args {
|
||||
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")
|
||||
return &templateCheck{
|
||||
calls: calls,
|
||||
MetaData: gosec.MetaData{
|
||||
MetaData: issue.MetaData{
|
||||
ID: id,
|
||||
Severity: gosec.Medium,
|
||||
Confidence: gosec.Low,
|
||||
Severity: issue.Medium,
|
||||
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.",
|
||||
},
|
||||
}, []ast.Node{(*ast.CallExpr)(nil)}
|
||||
|
|
27
rules/tls.go
27
rules/tls.go
|
@ -24,10 +24,11 @@ import (
|
|||
"strconv"
|
||||
|
||||
"github.com/securego/gosec/v2"
|
||||
"github.com/securego/gosec/v2/issue"
|
||||
)
|
||||
|
||||
type insecureConfigTLS struct {
|
||||
gosec.MetaData
|
||||
issue.MetaData
|
||||
MinVersion int64
|
||||
MaxVersion int64
|
||||
requiredType string
|
||||
|
@ -49,13 +50,13 @@ func stringInSlice(a string, list []string) bool {
|
|||
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 {
|
||||
for _, cipher := range ciphers.Elts {
|
||||
if ident, ok := cipher.(*ast.SelectorExpr); ok {
|
||||
if !stringInSlice(ident.Sel.Name, t.goodCiphers) {
|
||||
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
|
||||
}
|
||||
|
||||
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 {
|
||||
issue := t.processTLSConfVal(kve.Key, kve.Value, c)
|
||||
if issue != nil {
|
||||
|
@ -83,27 +84,27 @@ func (t *insecureConfigTLS) processTLSConf(n ast.Node, c *gosec.Context) *gosec.
|
|||
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 {
|
||||
switch ident.Name {
|
||||
case "InsecureSkipVerify":
|
||||
if node, ok := value.(*ast.Ident); ok {
|
||||
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 {
|
||||
// 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":
|
||||
if node, ok := value.(*ast.Ident); ok {
|
||||
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 {
|
||||
// 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":
|
||||
|
@ -188,16 +189,16 @@ func (t *insecureConfigTLS) mapVersion(version string) int64 {
|
|||
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 {
|
||||
// no warning is generated since the min version is greater than the secure min version
|
||||
return nil
|
||||
}
|
||||
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 {
|
||||
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
|
||||
}
|
||||
|
@ -207,7 +208,7 @@ func (t *insecureConfigTLS) resetVersion() {
|
|||
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 {
|
||||
actualType := c.Info.TypeOf(complit.Type)
|
||||
if actualType != nil && actualType.String() == t.requiredType {
|
||||
|
|
|
@ -4,13 +4,14 @@ import (
|
|||
"go/ast"
|
||||
|
||||
"github.com/securego/gosec/v2"
|
||||
"github.com/securego/gosec/v2/issue"
|
||||
)
|
||||
|
||||
// NewModernTLSCheck creates a check for Modern TLS ciphers
|
||||
// DO NOT EDIT - generated by tlsconfig tool
|
||||
func NewModernTLSCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
|
||||
return &insecureConfigTLS{
|
||||
MetaData: gosec.MetaData{ID: id},
|
||||
MetaData: issue.MetaData{ID: id},
|
||||
requiredType: "crypto/tls.Config",
|
||||
MinVersion: 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
|
||||
func NewIntermediateTLSCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
|
||||
return &insecureConfigTLS{
|
||||
MetaData: gosec.MetaData{ID: id},
|
||||
MetaData: issue.MetaData{ID: id},
|
||||
requiredType: "crypto/tls.Config",
|
||||
MinVersion: 0x0303,
|
||||
MaxVersion: 0x0304,
|
||||
|
@ -52,7 +53,7 @@ func NewIntermediateTLSCheck(id string, conf gosec.Config) (gosec.Rule, []ast.No
|
|||
// DO NOT EDIT - generated by tlsconfig tool
|
||||
func NewOldTLSCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
|
||||
return &insecureConfigTLS{
|
||||
MetaData: gosec.MetaData{ID: id},
|
||||
MetaData: issue.MetaData{ID: id},
|
||||
requiredType: "crypto/tls.Config",
|
||||
MinVersion: 0x0301,
|
||||
MaxVersion: 0x0304,
|
||||
|
|
|
@ -18,10 +18,11 @@ import (
|
|||
"go/ast"
|
||||
|
||||
"github.com/securego/gosec/v2"
|
||||
"github.com/securego/gosec/v2/issue"
|
||||
)
|
||||
|
||||
type usingUnsafe struct {
|
||||
gosec.MetaData
|
||||
issue.MetaData
|
||||
pkg string
|
||||
calls []string
|
||||
}
|
||||
|
@ -30,9 +31,9 @@ func (r *usingUnsafe) ID() string {
|
|||
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 {
|
||||
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
|
||||
}
|
||||
|
@ -43,11 +44,11 @@ func NewUsingUnsafe(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
|
|||
return &usingUnsafe{
|
||||
pkg: "unsafe",
|
||||
calls: []string{"Alignof", "Offsetof", "Sizeof", "Pointer"},
|
||||
MetaData: gosec.MetaData{
|
||||
MetaData: issue.MetaData{
|
||||
ID: id,
|
||||
What: "Use of unsafe calls should be audited",
|
||||
Severity: gosec.Low,
|
||||
Confidence: gosec.High,
|
||||
Severity: issue.Low,
|
||||
Confidence: issue.High,
|
||||
},
|
||||
}, []ast.Node{(*ast.CallExpr)(nil)}
|
||||
}
|
||||
|
|
|
@ -18,10 +18,11 @@ import (
|
|||
"go/ast"
|
||||
|
||||
"github.com/securego/gosec/v2"
|
||||
"github.com/securego/gosec/v2/issue"
|
||||
)
|
||||
|
||||
type usesWeakCryptography struct {
|
||||
gosec.MetaData
|
||||
issue.MetaData
|
||||
blocklist map[string][]string
|
||||
}
|
||||
|
||||
|
@ -29,10 +30,10 @@ func (r *usesWeakCryptography) ID() string {
|
|||
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 {
|
||||
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
|
||||
|
@ -47,10 +48,10 @@ func NewUsesWeakCryptography(id string, conf gosec.Config) (gosec.Rule, []ast.No
|
|||
calls["crypto/rc4"] = []string{"NewCipher"}
|
||||
rule := &usesWeakCryptography{
|
||||
blocklist: calls,
|
||||
MetaData: gosec.MetaData{
|
||||
MetaData: issue.MetaData{
|
||||
ID: id,
|
||||
Severity: gosec.Medium,
|
||||
Confidence: gosec.High,
|
||||
Severity: issue.Medium,
|
||||
Confidence: issue.High,
|
||||
What: "Use of weak cryptographic primitive",
|
||||
},
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue