Skip to content

Commit de2c6a3

Browse files
committed
Extract the issue in its own package
1 parent 31e6327 commit de2c6a3

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+439
-378
lines changed

Makefile

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,4 +87,7 @@ image-push: image
8787
docker push $(IMAGE_REPO)/$(BIN):$(GIT_TAG)
8888
docker push $(IMAGE_REPO)/$(BIN):latest
8989

90-
.PHONY: test build clean release image image-push
90+
tlsconfig:
91+
go generate ./...
92+
93+
.PHONY: test build clean release image image-push tlsconfig

analyzer.go

Lines changed: 37 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import (
3232
"sync"
3333

3434
"github.com/securego/gosec/v2/analyzers"
35+
"github.com/securego/gosec/v2/issue"
3536
"golang.org/x/tools/go/analysis"
3637
"golang.org/x/tools/go/analysis/passes/buildssa"
3738
"golang.org/x/tools/go/packages"
@@ -68,10 +69,21 @@ type Context struct {
6869
Root *ast.File
6970
Imports *ImportTracker
7071
Config Config
71-
Ignores []map[string][]SuppressionInfo
72+
Ignores []map[string][]issue.SuppressionInfo
7273
PassedValues map[string]interface{}
7374
}
7475

76+
// getFileAtNodePos returns the file at the node position in the file set available in the context.
77+
func (ctx *Context) GetFileAtNodePos(node ast.Node) *token.File {
78+
return ctx.FileSet.File(node.Pos())
79+
}
80+
81+
// NewIssue creates a new issue
82+
func (ctx *Context) NewIssue(node ast.Node, ruleID, desc string,
83+
severity, confidence issue.Score) *issue.Issue {
84+
return issue.New(ctx.GetFileAtNodePos(node), node, ruleID, desc, severity, confidence)
85+
}
86+
7587
// Metrics used when reporting information about a scanning run.
7688
type Metrics struct {
7789
NumFiles int `json:"files"`
@@ -88,7 +100,7 @@ type Analyzer struct {
88100
context *Context
89101
config Config
90102
logger *log.Logger
91-
issues []*Issue
103+
issues []*issue.Issue
92104
stats *Metrics
93105
errors map[string][]Error // keys are file paths; values are the golang errors in those files
94106
tests bool
@@ -99,13 +111,6 @@ type Analyzer struct {
99111
analyzerList []*analysis.Analyzer
100112
}
101113

102-
// SuppressionInfo object is to record the kind and the justification that used
103-
// to suppress violations.
104-
type SuppressionInfo struct {
105-
Kind string `json:"kind"`
106-
Justification string `json:"justification"`
107-
}
108-
109114
// NewAnalyzer builds a new analyzer.
110115
func NewAnalyzer(conf Config, tests bool, excludeGenerated bool, trackSuppressions bool, concurrency int, logger *log.Logger) *Analyzer {
111116
ignoreNoSec := false
@@ -126,7 +131,7 @@ func NewAnalyzer(conf Config, tests bool, excludeGenerated bool, trackSuppressio
126131
context: &Context{},
127132
config: conf,
128133
logger: logger,
129-
issues: make([]*Issue, 0, 16),
134+
issues: make([]*issue.Issue, 0, 16),
130135
stats: &Metrics{},
131136
errors: make(map[string][]Error),
132137
tests: tests,
@@ -371,8 +376,8 @@ func (gosec *Analyzer) CheckAnalyzers(pkg *packages.Package) {
371376
continue
372377
}
373378
if result != nil {
374-
if issue, ok := result.(*analyzers.Issue); ok {
375-
gosec.updateIssues(toGosecIssue(issue), false, []SuppressionInfo{})
379+
if aissue, ok := result.(*analyzers.Issue); ok {
380+
gosec.updateIssues(toGosecIssue(aissue), false, []issue.SuppressionInfo{})
376381
}
377382
}
378383
}
@@ -439,7 +444,7 @@ func (gosec *Analyzer) AppendError(file string, err error) {
439444
}
440445

441446
// ignore a node (and sub-tree) if it is tagged with a nosec tag comment
442-
func (gosec *Analyzer) ignore(n ast.Node) map[string]SuppressionInfo {
447+
func (gosec *Analyzer) ignore(n ast.Node) map[string]issue.SuppressionInfo {
443448
if groups, ok := gosec.context.Comments[n]; ok && !gosec.ignoreNosec {
444449

445450
// 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 {
476481
re := regexp.MustCompile(`(G\d{3})`)
477482
matches := re.FindAllStringSubmatch(directive, -1)
478483

479-
suppression := SuppressionInfo{
484+
suppression := issue.SuppressionInfo{
480485
Kind: "inSource",
481486
Justification: justification,
482487
}
483488

484489
// Find the rule IDs to ignore.
485-
ignores := make(map[string]SuppressionInfo)
490+
ignores := make(map[string]issue.SuppressionInfo)
486491
for _, v := range matches {
487492
ignores[v[1]] = suppression
488493
}
@@ -525,7 +530,7 @@ func (gosec *Analyzer) Visit(n ast.Node) ast.Visitor {
525530
return gosec
526531
}
527532

528-
func (gosec *Analyzer) updateIgnoredRules(n ast.Node) (map[string][]SuppressionInfo, bool) {
533+
func (gosec *Analyzer) updateIgnoredRules(n ast.Node) (map[string][]issue.SuppressionInfo, bool) {
529534
if n == nil {
530535
if len(gosec.context.Ignores) > 0 {
531536
gosec.context.Ignores = gosec.context.Ignores[1:]
@@ -536,7 +541,7 @@ func (gosec *Analyzer) updateIgnoredRules(n ast.Node) (map[string][]SuppressionI
536541
ignoredRules := gosec.ignore(n)
537542

538543
// Now create the union of exclusions.
539-
ignores := map[string][]SuppressionInfo{}
544+
ignores := map[string][]issue.SuppressionInfo{}
540545
if len(gosec.context.Ignores) > 0 {
541546
for k, v := range gosec.context.Ignores[0] {
542547
ignores[k] = v
@@ -548,12 +553,12 @@ func (gosec *Analyzer) updateIgnoredRules(n ast.Node) (map[string][]SuppressionI
548553
}
549554

550555
// Push the new set onto the stack.
551-
gosec.context.Ignores = append([]map[string][]SuppressionInfo{ignores}, gosec.context.Ignores...)
556+
gosec.context.Ignores = append([]map[string][]issue.SuppressionInfo{ignores}, gosec.context.Ignores...)
552557

553558
return ignores, true
554559
}
555560

556-
func (gosec *Analyzer) updateSuppressions(id string, ignores map[string][]SuppressionInfo) ([]SuppressionInfo, bool) {
561+
func (gosec *Analyzer) updateSuppressions(id string, ignores map[string][]issue.SuppressionInfo) ([]issue.SuppressionInfo, bool) {
557562
// Check if all rules are ignored.
558563
generalSuppressions, generalIgnored := ignores[aliasOfAllRules]
559564
// Check if the specific rule is ignored
@@ -565,15 +570,15 @@ func (gosec *Analyzer) updateSuppressions(id string, ignores map[string][]Suppre
565570
// Track external suppressions.
566571
if gosec.ruleset.IsRuleSuppressed(id) {
567572
ignored = true
568-
suppressions = append(suppressions, SuppressionInfo{
573+
suppressions = append(suppressions, issue.SuppressionInfo{
569574
Kind: "external",
570575
Justification: externalSuppressionJustification,
571576
})
572577
}
573578
return suppressions, ignored
574579
}
575580

576-
func (gosec *Analyzer) updateIssues(issue *Issue, ignored bool, suppressions []SuppressionInfo) {
581+
func (gosec *Analyzer) updateIssues(issue *issue.Issue, ignored bool, suppressions []issue.SuppressionInfo) {
577582
if issue != nil {
578583
if gosec.showIgnored {
579584
issue.NoSec = ignored
@@ -590,27 +595,27 @@ func (gosec *Analyzer) updateIssues(issue *Issue, ignored bool, suppressions []S
590595
}
591596
}
592597

593-
func toGosecIssue(issue *analyzers.Issue) *Issue {
594-
return &Issue{
595-
File: issue.File,
596-
Line: issue.Line,
597-
Col: issue.Col,
598-
RuleID: issue.AnalyzerID,
599-
What: issue.What,
600-
Confidence: Score(issue.Confidence),
601-
Severity: Score(issue.Severity),
598+
func toGosecIssue(aissue *analyzers.Issue) *issue.Issue {
599+
return &issue.Issue{
600+
File: aissue.File,
601+
Line: aissue.Line,
602+
Col: aissue.Col,
603+
RuleID: aissue.AnalyzerID,
604+
What: aissue.What,
605+
Confidence: issue.Score(aissue.Confidence),
606+
Severity: issue.Score(aissue.Severity),
602607
}
603608
}
604609

605610
// Report returns the current issues discovered and the metrics about the scan
606-
func (gosec *Analyzer) Report() ([]*Issue, *Metrics, map[string][]Error) {
611+
func (gosec *Analyzer) Report() ([]*issue.Issue, *Metrics, map[string][]Error) {
607612
return gosec.issues, gosec.stats, gosec.errors
608613
}
609614

610615
// Reset clears state such as context, issues and metrics from the configured analyzer
611616
func (gosec *Analyzer) Reset() {
612617
gosec.context = &Context{}
613-
gosec.issues = make([]*Issue, 0, 16)
618+
gosec.issues = make([]*issue.Issue, 0, 16)
614619
gosec.stats = &Metrics{}
615620
gosec.ruleset = NewRuleSet()
616621
}

cmd/gosec/main.go

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626

2727
"github.com/securego/gosec/v2"
2828
"github.com/securego/gosec/v2/cmd/vflag"
29+
"github.com/securego/gosec/v2/issue"
2930
"github.com/securego/gosec/v2/report"
3031
"github.com/securego/gosec/v2/rules"
3132
)
@@ -265,22 +266,22 @@ func saveReport(filename, format string, rootPaths []string, reportInfo *gosec.R
265266
return nil
266267
}
267268

268-
func convertToScore(value string) (gosec.Score, error) {
269+
func convertToScore(value string) (issue.Score, error) {
269270
value = strings.ToLower(value)
270271
switch value {
271272
case "low":
272-
return gosec.Low, nil
273+
return issue.Low, nil
273274
case "medium":
274-
return gosec.Medium, nil
275+
return issue.Medium, nil
275276
case "high":
276-
return gosec.High, nil
277+
return issue.High, nil
277278
default:
278-
return gosec.Low, fmt.Errorf("provided value '%s' not valid. Valid options: low, medium, high", value)
279+
return issue.Low, fmt.Errorf("provided value '%s' not valid. Valid options: low, medium, high", value)
279280
}
280281
}
281282

282-
func filterIssues(issues []*gosec.Issue, severity gosec.Score, confidence gosec.Score) ([]*gosec.Issue, int) {
283-
result := make([]*gosec.Issue, 0)
283+
func filterIssues(issues []*issue.Issue, severity issue.Score, confidence issue.Score) ([]*issue.Issue, int) {
284+
result := make([]*issue.Issue, 0)
284285
trueIssues := 0
285286
for _, issue := range issues {
286287
if issue.Severity >= severity && issue.Confidence >= confidence {
@@ -293,7 +294,7 @@ func filterIssues(issues []*gosec.Issue, severity gosec.Score, confidence gosec.
293294
return result, trueIssues
294295
}
295296

296-
func exit(issues []*gosec.Issue, errors map[string][]gosec.Error, noFail bool) {
297+
func exit(issues []*issue.Issue, errors map[string][]gosec.Error, noFail bool) {
297298
nsi := 0
298299
for _, issue := range issues {
299300
if len(issue.Suppressions) == 0 {

cmd/gosec/sort_issues.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import (
55
"strconv"
66
"strings"
77

8-
"github.com/securego/gosec/v2"
8+
"github.com/securego/gosec/v2/issue"
99
)
1010

1111
// handle ranges
@@ -14,7 +14,7 @@ func extractLineNumber(s string) int {
1414
return lineNumber
1515
}
1616

17-
type sortBySeverity []*gosec.Issue
17+
type sortBySeverity []*issue.Issue
1818

1919
func (s sortBySeverity) Len() int { return len(s) }
2020

@@ -34,6 +34,6 @@ func (s sortBySeverity) Less(i, j int) bool {
3434
func (s sortBySeverity) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
3535

3636
// sortIssues sorts the issues by severity in descending order
37-
func sortIssues(issues []*gosec.Issue) {
37+
func sortIssues(issues []*issue.Issue) {
3838
sort.Sort(sortBySeverity(issues))
3939
}

cmd/gosec/sort_issues_test.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,22 @@ import (
55

66
. "github.com/onsi/ginkgo/v2"
77
. "github.com/onsi/gomega"
8-
"github.com/securego/gosec/v2"
8+
"github.com/securego/gosec/v2/issue"
99
)
1010

11-
var defaultIssue = gosec.Issue{
11+
var defaultIssue = issue.Issue{
1212
File: "/home/src/project/test.go",
1313
Line: "1",
1414
Col: "1",
1515
RuleID: "ruleID",
1616
What: "test",
17-
Confidence: gosec.High,
18-
Severity: gosec.High,
17+
Confidence: issue.High,
18+
Severity: issue.High,
1919
Code: "1: testcode",
20-
Cwe: gosec.GetCweByRule("G101"),
20+
Cwe: issue.GetCweByRule("G101"),
2121
}
2222

23-
func createIssue() gosec.Issue {
23+
func createIssue() issue.Issue {
2424
return defaultIssue
2525
}
2626

@@ -29,8 +29,8 @@ func TestRules(t *testing.T) {
2929
RunSpecs(t, "Sort issues Suite")
3030
}
3131

32-
func firstIsGreater(less, greater *gosec.Issue) {
33-
slice := []*gosec.Issue{less, greater}
32+
func firstIsGreater(less, greater *issue.Issue) {
33+
slice := []*issue.Issue{less, greater}
3434

3535
sortIssues(slice)
3636

@@ -40,9 +40,9 @@ func firstIsGreater(less, greater *gosec.Issue) {
4040
var _ = Describe("Sorting by Severity", func() {
4141
It("sorts by severity", func() {
4242
less := createIssue()
43-
less.Severity = gosec.Low
43+
less.Severity = issue.Low
4444
greater := createIssue()
45-
less.Severity = gosec.High
45+
less.Severity = issue.High
4646
firstIsGreater(&less, &greater)
4747
})
4848

cmd/tlsconfig/header_template.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,6 @@ import (
99
"go/ast"
1010
1111
"github.com/securego/gosec/v2"
12+
"github.com/securego/gosec/v2/issue"
1213
)
1314
`))

cmd/tlsconfig/rule_template.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ var generatedRuleTmpl = template.Must(template.New("generated").Parse(`
77
// DO NOT EDIT - generated by tlsconfig tool
88
func New{{.Name}}TLSCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
99
return &insecureConfigTLS{
10-
MetaData: gosec.MetaData{ID: id},
10+
MetaData: issue.MetaData{ID: id},
1111
requiredType: "crypto/tls.Config",
1212
MinVersion: {{ .MinVersion }},
1313
MaxVersion: {{ .MaxVersion }},

issue.go renamed to issue/issue.go

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
package gosec
15+
package issue
1616

1717
import (
1818
"bufio"
@@ -105,8 +105,15 @@ type Issue struct {
105105
Suppressions []SuppressionInfo `json:"suppressions"` // Suppression info of the issue
106106
}
107107

108+
// SuppressionInfo object is to record the kind and the justification that used
109+
// to suppress violations.
110+
type SuppressionInfo struct {
111+
Kind string `json:"kind"`
112+
Justification string `json:"justification"`
113+
}
114+
108115
// FileLocation point out the file path and line number in file
109-
func (i Issue) FileLocation() string {
116+
func (i *Issue) FileLocation() string {
110117
return fmt.Sprintf("%s:%s", i.File, i.Line)
111118
}
112119

@@ -171,9 +178,8 @@ func codeSnippetEndLine(node ast.Node, fobj *token.File) int64 {
171178
return e + SnippetOffset
172179
}
173180

174-
// NewIssue creates a new Issue
175-
func NewIssue(ctx *Context, node ast.Node, ruleID, desc string, severity Score, confidence Score) *Issue {
176-
fobj := ctx.FileSet.File(node.Pos())
181+
// New creates a new Issue
182+
func New(fobj *token.File, node ast.Node, ruleID, desc string, severity, confidence Score) *Issue {
177183
name := fobj.Name()
178184
start, end := fobj.Line(node.Pos()), fobj.Line(node.End())
179185
line := strconv.Itoa(start)

0 commit comments

Comments
 (0)