mirror of
https://github.com/securego/gosec.git
synced 2025-11-23 22:15:04 +02:00
Allow excluding analyzers globally (#1180)
* This change does not exclude analyzers for inline comment * Changed the expected issues count for G103, G109 samples for test. Previously G115 has been included in the issue count * Show analyzers IDs(G115, G602) in gosec usage help * See #1175
This commit is contained in:
38
analyzers/analyzers_set.go
Normal file
38
analyzers/analyzers_set.go
Normal file
@@ -0,0 +1,38 @@
|
||||
// (c) Copyright gosec's authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package analyzers
|
||||
|
||||
import "golang.org/x/tools/go/analysis"
|
||||
|
||||
type AnalyzerSet struct {
|
||||
Analyzers []*analysis.Analyzer
|
||||
AnalyzerSuppressedMap map[string]bool
|
||||
}
|
||||
|
||||
// NewAnalyzerSet constructs a new AnalyzerSet
|
||||
func NewAnalyzerSet() *AnalyzerSet {
|
||||
return &AnalyzerSet{nil, make(map[string]bool)}
|
||||
}
|
||||
|
||||
// Register adds a trigger for the supplied analyzer
|
||||
func (a *AnalyzerSet) Register(analyzer *analysis.Analyzer, isSuppressed bool) {
|
||||
a.Analyzers = append(a.Analyzers, analyzer)
|
||||
a.AnalyzerSuppressedMap[analyzer.Name] = isSuppressed
|
||||
}
|
||||
|
||||
// IsSuppressed will return whether the Analyzer is suppressed.
|
||||
func (a *AnalyzerSet) IsSuppressed(ruleID string) bool {
|
||||
return a.AnalyzerSuppressedMap[ruleID]
|
||||
}
|
||||
62
analyzers/analyzers_test.go
Normal file
62
analyzers/analyzers_test.go
Normal file
@@ -0,0 +1,62 @@
|
||||
package analyzers_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
"github.com/securego/gosec/v2"
|
||||
"github.com/securego/gosec/v2/analyzers"
|
||||
"github.com/securego/gosec/v2/testutils"
|
||||
)
|
||||
|
||||
var _ = Describe("gosec analyzers", func() {
|
||||
var (
|
||||
logger *log.Logger
|
||||
config gosec.Config
|
||||
analyzer *gosec.Analyzer
|
||||
runner func(string, []testutils.CodeSample)
|
||||
buildTags []string
|
||||
tests bool
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
logger, _ = testutils.NewLogger()
|
||||
config = gosec.NewConfig()
|
||||
analyzer = gosec.NewAnalyzer(config, tests, false, false, 1, logger)
|
||||
runner = func(analyzerId string, samples []testutils.CodeSample) {
|
||||
for n, sample := range samples {
|
||||
analyzer.Reset()
|
||||
analyzer.SetConfig(sample.Config)
|
||||
analyzer.LoadAnalyzers(analyzers.Generate(false, analyzers.NewAnalyzerFilter(false, analyzerId)).AnalyzersInfo())
|
||||
pkg := testutils.NewTestPackage()
|
||||
defer pkg.Close()
|
||||
for i, code := range sample.Code {
|
||||
pkg.AddFile(fmt.Sprintf("sample_%d_%d.go", n, i), code)
|
||||
}
|
||||
err := pkg.Build()
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
Expect(pkg.PrintErrors()).Should(BeZero())
|
||||
err = analyzer.Process(buildTags, pkg.Path)
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
issues, _, _ := analyzer.Report()
|
||||
if len(issues) != sample.Errors {
|
||||
fmt.Println(sample.Code)
|
||||
}
|
||||
Expect(issues).Should(HaveLen(sample.Errors))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
Context("report correct errors for all samples", func() {
|
||||
It("should detect integer conversion overflow", func() {
|
||||
runner("G115", testutils.SampleCodeG115)
|
||||
})
|
||||
|
||||
It("should detect out of bounds slice access", func() {
|
||||
runner("G602", testutils.SampleCodeG602)
|
||||
})
|
||||
})
|
||||
})
|
||||
94
analyzers/analyzerslist.go
Normal file
94
analyzers/analyzerslist.go
Normal file
@@ -0,0 +1,94 @@
|
||||
// (c) Copyright gosec's authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package analyzers
|
||||
|
||||
import (
|
||||
"golang.org/x/tools/go/analysis"
|
||||
)
|
||||
|
||||
// AnalyzerDefinition contains the description of an analyzer and a mechanism to
|
||||
// create it.
|
||||
type AnalyzerDefinition struct {
|
||||
ID string
|
||||
Description string
|
||||
Create AnalyzerBuilder
|
||||
}
|
||||
|
||||
// AnalyzerBuilder is used to register an analyzer definition with the analyzer
|
||||
type AnalyzerBuilder func(id string, description string) *analysis.Analyzer
|
||||
|
||||
// AnalyzerList contains a mapping of analyzer ID's to analyzer definitions and a mapping
|
||||
// of analyzer ID's to whether analyzers are suppressed.
|
||||
type AnalyzerList struct {
|
||||
Analyzers map[string]AnalyzerDefinition
|
||||
AnalyzerSuppressed map[string]bool
|
||||
}
|
||||
|
||||
// AnalyzersInfo returns all the create methods and the analyzer suppressed map for a
|
||||
// given list
|
||||
func (al *AnalyzerList) AnalyzersInfo() (map[string]AnalyzerDefinition, map[string]bool) {
|
||||
builders := make(map[string]AnalyzerDefinition)
|
||||
for _, def := range al.Analyzers {
|
||||
builders[def.ID] = def
|
||||
}
|
||||
return builders, al.AnalyzerSuppressed
|
||||
}
|
||||
|
||||
// AnalyzerFilter can be used to include or exclude an analyzer depending on the return
|
||||
// value of the function
|
||||
type AnalyzerFilter func(string) bool
|
||||
|
||||
// NewAnalyzerFilter is a closure that will include/exclude the analyzer ID's based on
|
||||
// the supplied boolean value.
|
||||
func NewAnalyzerFilter(action bool, analyzerIDs ...string) AnalyzerFilter {
|
||||
analyzerlist := make(map[string]bool)
|
||||
for _, analyzer := range analyzerIDs {
|
||||
analyzerlist[analyzer] = true
|
||||
}
|
||||
return func(analyzer string) bool {
|
||||
if _, found := analyzerlist[analyzer]; found {
|
||||
return action
|
||||
}
|
||||
return !action
|
||||
}
|
||||
}
|
||||
|
||||
var defaultAnalyzers = []AnalyzerDefinition{
|
||||
{"G115", "Type conversion which leads to integer overflow", newConversionOverflowAnalyzer},
|
||||
{"G602", "Possible slice bounds out of range", newSliceBoundsAnalyzer},
|
||||
}
|
||||
|
||||
// Generate the list of analyzers to use
|
||||
func Generate(trackSuppressions bool, filters ...AnalyzerFilter) *AnalyzerList {
|
||||
analyzerMap := make(map[string]AnalyzerDefinition)
|
||||
analyzerSuppressedMap := make(map[string]bool)
|
||||
|
||||
for _, analyzer := range defaultAnalyzers {
|
||||
analyzerSuppressedMap[analyzer.ID] = false
|
||||
addToAnalyzerList := true
|
||||
for _, filter := range filters {
|
||||
if filter(analyzer.ID) {
|
||||
analyzerSuppressedMap[analyzer.ID] = true
|
||||
if !trackSuppressions {
|
||||
addToAnalyzerList = false
|
||||
}
|
||||
}
|
||||
}
|
||||
if addToAnalyzerList {
|
||||
analyzerMap[analyzer.ID] = analyzer
|
||||
}
|
||||
}
|
||||
return &AnalyzerList{Analyzers: analyzerMap, AnalyzerSuppressed: analyzerSuppressedMap}
|
||||
}
|
||||
13
analyzers/anaylzers_suite_test.go
Normal file
13
analyzers/anaylzers_suite_test.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package analyzers_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
func TestAnalyzers(t *testing.T) {
|
||||
RegisterFailHandler(Fail)
|
||||
RunSpecs(t, "Analyzers Suite")
|
||||
}
|
||||
@@ -35,14 +35,6 @@ type SSAAnalyzerResult struct {
|
||||
SSA *buildssa.SSA
|
||||
}
|
||||
|
||||
// BuildDefaultAnalyzers returns the default list of analyzers
|
||||
func BuildDefaultAnalyzers() []*analysis.Analyzer {
|
||||
return []*analysis.Analyzer{
|
||||
newConversionOverflowAnalyzer("G115", "Type conversion which leads to integer overflow"),
|
||||
newSliceBoundsAnalyzer("G602", "Possible slice bounds out of range"),
|
||||
}
|
||||
}
|
||||
|
||||
// getSSAResult retrieves the SSA result from analysis pass
|
||||
func getSSAResult(pass *analysis.Pass) (*SSAAnalyzerResult, error) {
|
||||
result, ok := pass.ResultOf[buildssa.Analyzer]
|
||||
|
||||
Reference in New Issue
Block a user