Use the gosec issue in the go analysers

This commit is contained in:
Cosmin Cojocar 2023-02-15 21:50:02 +01:00 committed by Cosmin Cojocar
parent b1fd94881e
commit f850069114
4 changed files with 42 additions and 52 deletions

View file

@ -377,8 +377,8 @@ func (gosec *Analyzer) CheckAnalyzers(pkg *packages.Package) {
continue continue
} }
if result != nil { if result != nil {
if aissue, ok := result.(*analyzers.Issue); ok { if aissue, ok := result.(*issue.Issue); ok {
gosec.updateIssues(toGosecIssue(aissue), false, []issue.SuppressionInfo{}) gosec.updateIssues(aissue, false, []issue.SuppressionInfo{})
} }
} }
} }
@ -596,18 +596,6 @@ func (gosec *Analyzer) updateIssues(issue *issue.Issue, ignored bool, suppressio
} }
} }
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 // Report returns the current issues discovered and the metrics about the scan
func (gosec *Analyzer) Report() ([]*issue.Issue, *Metrics, map[string][]Error) { func (gosec *Analyzer) Report() ([]*issue.Issue, *Metrics, map[string][]Error) {
return gosec.issues, gosec.stats, gosec.errors return gosec.issues, gosec.stats, gosec.errors

View file

@ -15,6 +15,7 @@
package analyzers package analyzers
import ( import (
"github.com/securego/gosec/v2/issue"
"golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/buildssa" "golang.org/x/tools/go/analysis/passes/buildssa"
"golang.org/x/tools/go/ssa" "golang.org/x/tools/go/ssa"
@ -45,7 +46,7 @@ func runSSRF(pass *analysis.Pass) (interface{}, error) {
ssaResult.Logger.Printf("callee: %s\n", callee) ssaResult.Logger.Printf("callee: %s\n", callee)
return newIssue(pass.Analyzer.Name, return newIssue(pass.Analyzer.Name,
"not implemeted", "not implemeted",
pass.Fset, instr.Call.Pos(), Low, High), nil pass.Fset, instr.Call.Pos(), issue.Low, issue.High), nil
} }
} }
} }

View file

@ -18,8 +18,10 @@ import (
"fmt" "fmt"
"go/token" "go/token"
"log" "log"
"os"
"strconv" "strconv"
"github.com/securego/gosec/v2/issue"
"golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/buildssa" "golang.org/x/tools/go/analysis/passes/buildssa"
) )
@ -32,32 +34,6 @@ type SSAAnalyzerResult struct {
SSA *buildssa.SSA SSA *buildssa.SSA
} }
// Score type used by severity and confidence values
// TODO: remove this duplicated type
type Score int
const (
// Low severity or confidence
Low Score = iota
// Medium severity or confidence
Medium
// High severity or confidence
High
)
// Issue is returned by a gosec rule if it discovers an issue with the scanned code.
// TODO: remove this duplicated type
type Issue struct {
Severity Score `json:"severity"` // issue severity (how problematic it is)
Confidence Score `json:"confidence"` // issue confidence (how sure we are we found it)
AnalyzerID string `json:"analyzer_id"` // Human readable explanation
What string `json:"details"` // Human readable explanation
File string `json:"file"` // File name we found it in
Code string `json:"code"` // Impacted code line
Line string `json:"line"` // Line number in file
Col string `json:"column"` // Column number in line
}
// BuildDefaultAnalyzers returns the default list of analyzers // BuildDefaultAnalyzers returns the default list of analyzers
func BuildDefaultAnalyzers() []*analysis.Analyzer { func BuildDefaultAnalyzers() []*analysis.Analyzer {
return []*analysis.Analyzer{ return []*analysis.Analyzer{
@ -78,18 +54,43 @@ func getSSAResult(pass *analysis.Pass) (*SSAAnalyzerResult, error) {
return ssaResult, nil return ssaResult, nil
} }
func newIssue(analyzerID string, desc string, fileSet *token.FileSet, pos token.Pos, severity Score, confidence Score) *Issue { // newIssue creates a new gosec issue
func newIssue(analyzerID string, desc string, fileSet *token.FileSet,
pos token.Pos, severity, confidence issue.Score) *issue.Issue {
file := fileSet.File(pos) file := fileSet.File(pos)
line := file.Line(pos) line := file.Line(pos)
col := file.Position(pos).Column col := file.Position(pos).Column
// TODO: extract the code snippet and map the CWE
return &Issue{ return &issue.Issue{
RuleID: analyzerID,
File: file.Name(), File: file.Name(),
Line: strconv.Itoa(line), Line: strconv.Itoa(line),
Col: strconv.Itoa(col), Col: strconv.Itoa(col),
Severity: severity, Severity: severity,
Confidence: confidence, Confidence: confidence,
AnalyzerID: analyzerID,
What: desc, What: desc,
Cwe: issue.GetCweByRule(analyzerID),
Code: issueCodeSnippet(fileSet, pos),
} }
} }
func issueCodeSnippet(fileSet *token.FileSet, pos token.Pos) string {
file := fileSet.File(pos)
start := (int64)(file.Line(pos))
if start-issue.SnippetOffset > 0 {
start = start - issue.SnippetOffset
}
end := (int64)(file.Line(pos))
end = end + issue.SnippetOffset
var code string
if file, err := os.Open(file.Name()); err == nil {
defer file.Close() // #nosec
code, err = issue.CodeSnippet(file, start, end)
if err != nil {
return err.Error()
}
}
return code
}

View file

@ -144,11 +144,8 @@ func (c Score) String() string {
return "UNDEFINED" return "UNDEFINED"
} }
// codeSnippet extracts a code snippet based on the ast reference // CodeSnippet extracts a code snippet based on the ast reference
func codeSnippet(file *os.File, start int64, end int64, n ast.Node) (string, error) { func CodeSnippet(file *os.File, start int64, end int64) (string, error) {
if n == nil {
return "", fmt.Errorf("invalid AST node provided")
}
var pos int64 var pos int64
var buf bytes.Buffer var buf bytes.Buffer
scanner := bufio.NewScanner(file) scanner := bufio.NewScanner(file)
@ -189,11 +186,14 @@ func New(fobj *token.File, node ast.Node, ruleID, desc string, severity, confide
col := strconv.Itoa(fobj.Position(node.Pos()).Column) col := strconv.Itoa(fobj.Position(node.Pos()).Column)
var code string var code string
if file, err := os.Open(fobj.Name()); err == nil { if node == nil {
code = "invalid AST node provided"
}
if file, err := os.Open(fobj.Name()); err == nil && node != nil {
defer file.Close() // #nosec defer file.Close() // #nosec
s := codeSnippetStartLine(node, fobj) s := codeSnippetStartLine(node, fobj)
e := codeSnippetEndLine(node, fobj) e := codeSnippetEndLine(node, fobj)
code, err = codeSnippet(file, s, e, node) code, err = CodeSnippet(file, s, e)
if err != nil { if err != nil {
code = err.Error() code = err.Error()
} }