mirror of
https://github.com/securego/gosec.git
synced 2024-11-05 19:45:51 +00:00
Allow excluding generated files
This commit is contained in:
parent
521e69ef66
commit
62db81342e
5 changed files with 104 additions and 27 deletions
14
README.md
14
README.md
|
@ -236,7 +236,6 @@ gosec will ignore test files across all packages and any dependencies in your ve
|
|||
The scanning of test files can be enabled with the following flag:
|
||||
|
||||
```bash
|
||||
|
||||
gosec -tests ./...
|
||||
```
|
||||
|
||||
|
@ -246,6 +245,19 @@ Also additional folders can be excluded as follows:
|
|||
gosec -exclude-dir=rules -exclude-dir=cmd ./...
|
||||
```
|
||||
|
||||
### Excluding generated files
|
||||
|
||||
gosec can ignore generated go files with default generated code comment.
|
||||
|
||||
```
|
||||
// Code generated by some generator DO NOT EDIT.
|
||||
```
|
||||
|
||||
```bash
|
||||
gosec -exclude-generated ./...
|
||||
```
|
||||
|
||||
|
||||
### Annotating code
|
||||
|
||||
As with all automated detection tools, there will be cases of false positives. In cases where gosec reports a failure that has been manually verified as being safe,
|
||||
|
|
58
analyzer.go
58
analyzer.go
|
@ -43,6 +43,8 @@ const LoadMode = packages.NeedName |
|
|||
packages.NeedTypesInfo |
|
||||
packages.NeedSyntax
|
||||
|
||||
var generatedCodePattern = regexp.MustCompile(`^// Code generated .* DO NOT EDIT\.$`)
|
||||
|
||||
// The Context is populated with data parsed from the source code as it is scanned.
|
||||
// It is passed through to all rule functions as they are called. Rules may use
|
||||
// this data in conjunction withe the encountered AST node.
|
||||
|
@ -70,19 +72,20 @@ type Metrics struct {
|
|||
// Analyzer object is the main object of gosec. It has methods traverse an AST
|
||||
// and invoke the correct checking rules as on each node as required.
|
||||
type Analyzer struct {
|
||||
ignoreNosec bool
|
||||
ruleset RuleSet
|
||||
context *Context
|
||||
config Config
|
||||
logger *log.Logger
|
||||
issues []*Issue
|
||||
stats *Metrics
|
||||
errors map[string][]Error // keys are file paths; values are the golang errors in those files
|
||||
tests bool
|
||||
ignoreNosec bool
|
||||
ruleset RuleSet
|
||||
context *Context
|
||||
config Config
|
||||
logger *log.Logger
|
||||
issues []*Issue
|
||||
stats *Metrics
|
||||
errors map[string][]Error // keys are file paths; values are the golang errors in those files
|
||||
tests bool
|
||||
excludeGenerated bool
|
||||
}
|
||||
|
||||
// NewAnalyzer builds a new analyzer.
|
||||
func NewAnalyzer(conf Config, tests bool, logger *log.Logger) *Analyzer {
|
||||
func NewAnalyzer(conf Config, tests bool, excludeGenerated bool, logger *log.Logger) *Analyzer {
|
||||
ignoreNoSec := false
|
||||
if enabled, err := conf.IsGlobalEnabled(Nosec); err == nil {
|
||||
ignoreNoSec = enabled
|
||||
|
@ -91,15 +94,16 @@ func NewAnalyzer(conf Config, tests bool, logger *log.Logger) *Analyzer {
|
|||
logger = log.New(os.Stderr, "[gosec]", log.LstdFlags)
|
||||
}
|
||||
return &Analyzer{
|
||||
ignoreNosec: ignoreNoSec,
|
||||
ruleset: make(RuleSet),
|
||||
context: &Context{},
|
||||
config: conf,
|
||||
logger: logger,
|
||||
issues: make([]*Issue, 0, 16),
|
||||
stats: &Metrics{},
|
||||
errors: make(map[string][]Error),
|
||||
tests: tests,
|
||||
ignoreNosec: ignoreNoSec,
|
||||
ruleset: make(RuleSet),
|
||||
context: &Context{},
|
||||
config: conf,
|
||||
logger: logger,
|
||||
issues: make([]*Issue, 0, 16),
|
||||
stats: &Metrics{},
|
||||
errors: make(map[string][]Error),
|
||||
tests: tests,
|
||||
excludeGenerated: excludeGenerated,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -202,6 +206,11 @@ func (gosec *Analyzer) Check(pkg *packages.Package) {
|
|||
if filepath.Ext(checkedFile) != ".go" {
|
||||
continue
|
||||
}
|
||||
if gosec.excludeGenerated && isGeneratedFile(file) {
|
||||
gosec.logger.Println("Ignoring generated file:", checkedFile)
|
||||
continue
|
||||
}
|
||||
|
||||
gosec.logger.Println("Checking file:", checkedFile)
|
||||
gosec.context.FileSet = pkg.Fset
|
||||
gosec.context.Config = gosec.config
|
||||
|
@ -219,6 +228,17 @@ func (gosec *Analyzer) Check(pkg *packages.Package) {
|
|||
}
|
||||
}
|
||||
|
||||
func isGeneratedFile(file *ast.File) bool {
|
||||
for _, comment := range file.Comments {
|
||||
for _, row := range comment.List {
|
||||
if generatedCodePattern.MatchString(row.Text) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// ParseErrors parses the errors from given package
|
||||
func (gosec *Analyzer) ParseErrors(pkg *packages.Package) error {
|
||||
if len(pkg.Errors) == 0 {
|
||||
|
|
|
@ -25,7 +25,7 @@ var _ = Describe("Analyzer", func() {
|
|||
)
|
||||
BeforeEach(func() {
|
||||
logger, _ = testutils.NewLogger()
|
||||
analyzer = gosec.NewAnalyzer(nil, tests, logger)
|
||||
analyzer = gosec.NewAnalyzer(nil, tests, false, logger)
|
||||
})
|
||||
|
||||
Context("when processing a package", func() {
|
||||
|
@ -246,7 +246,7 @@ var _ = Describe("Analyzer", func() {
|
|||
// overwrite nosec option
|
||||
nosecIgnoreConfig := gosec.NewConfig()
|
||||
nosecIgnoreConfig.SetGlobal(gosec.Nosec, "true")
|
||||
customAnalyzer := gosec.NewAnalyzer(nosecIgnoreConfig, tests, logger)
|
||||
customAnalyzer := gosec.NewAnalyzer(nosecIgnoreConfig, tests, false, logger)
|
||||
customAnalyzer.LoadRules(rules.Generate(rules.NewRuleFilter(false, "G401")).Builders())
|
||||
|
||||
nosecPackage := testutils.NewTestPackage()
|
||||
|
@ -269,7 +269,7 @@ var _ = Describe("Analyzer", func() {
|
|||
// overwrite nosec option
|
||||
nosecIgnoreConfig := gosec.NewConfig()
|
||||
nosecIgnoreConfig.SetGlobal(gosec.NoSecAlternative, "#falsePositive")
|
||||
customAnalyzer := gosec.NewAnalyzer(nosecIgnoreConfig, tests, logger)
|
||||
customAnalyzer := gosec.NewAnalyzer(nosecIgnoreConfig, tests, false, logger)
|
||||
customAnalyzer.LoadRules(rules.Generate(rules.NewRuleFilter(false, "G401")).Builders())
|
||||
|
||||
nosecPackage := testutils.NewTestPackage()
|
||||
|
@ -292,7 +292,7 @@ var _ = Describe("Analyzer", func() {
|
|||
// overwrite nosec option
|
||||
nosecIgnoreConfig := gosec.NewConfig()
|
||||
nosecIgnoreConfig.SetGlobal(gosec.NoSecAlternative, "#falsePositive")
|
||||
customAnalyzer := gosec.NewAnalyzer(nosecIgnoreConfig, tests, logger)
|
||||
customAnalyzer := gosec.NewAnalyzer(nosecIgnoreConfig, tests, false, logger)
|
||||
customAnalyzer.LoadRules(rules.Generate(rules.NewRuleFilter(false, "G401")).Builders())
|
||||
|
||||
nosecPackage := testutils.NewTestPackage()
|
||||
|
@ -308,7 +308,7 @@ var _ = Describe("Analyzer", func() {
|
|||
})
|
||||
|
||||
It("should be able to analyze Go test package", func() {
|
||||
customAnalyzer := gosec.NewAnalyzer(nil, true, logger)
|
||||
customAnalyzer := gosec.NewAnalyzer(nil, true, false, logger)
|
||||
customAnalyzer.LoadRules(rules.Generate().Builders())
|
||||
pkg := testutils.NewTestPackage()
|
||||
defer pkg.Close()
|
||||
|
@ -332,6 +332,48 @@ var _ = Describe("Analyzer", func() {
|
|||
issues, _, _ := customAnalyzer.Report()
|
||||
Expect(issues).Should(HaveLen(1))
|
||||
})
|
||||
It("should be able to scan generated files if NOT excluded", func() {
|
||||
customAnalyzer := gosec.NewAnalyzer(nil, true, false, logger)
|
||||
customAnalyzer.LoadRules(rules.Generate().Builders())
|
||||
pkg := testutils.NewTestPackage()
|
||||
defer pkg.Close()
|
||||
pkg.AddFile("foo.go", `
|
||||
package foo
|
||||
// Code generated some-generator DO NOT EDIT.
|
||||
func test() error {
|
||||
return nil
|
||||
}
|
||||
func TestFoo(t *testing.T){
|
||||
test()
|
||||
}`)
|
||||
err := pkg.Build()
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
err = customAnalyzer.Process(buildTags, pkg.Path)
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
issues, _, _ := customAnalyzer.Report()
|
||||
Expect(issues).Should(HaveLen(1))
|
||||
})
|
||||
It("should be able to skip generated files if excluded", func() {
|
||||
customAnalyzer := gosec.NewAnalyzer(nil, true, true, logger)
|
||||
customAnalyzer.LoadRules(rules.Generate().Builders())
|
||||
pkg := testutils.NewTestPackage()
|
||||
defer pkg.Close()
|
||||
pkg.AddFile("foo.go", `
|
||||
package foo
|
||||
// Code generated some-generator DO NOT EDIT.
|
||||
func test() error {
|
||||
return nil
|
||||
}
|
||||
func TestFoo(t *testing.T){
|
||||
test()
|
||||
}`)
|
||||
err := pkg.Build()
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
err = customAnalyzer.Process(buildTags, pkg.Path)
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
issues, _, _ := customAnalyzer.Report()
|
||||
Expect(issues).Should(HaveLen(0))
|
||||
})
|
||||
})
|
||||
It("should be able to analyze Cgo files", func() {
|
||||
analyzer.LoadRules(rules.Generate().Builders())
|
||||
|
|
|
@ -93,6 +93,9 @@ var (
|
|||
// rules to explicitly exclude
|
||||
flagRulesExclude = flag.String("exclude", "", "Comma separated list of rules IDs to exclude. (see rule list)")
|
||||
|
||||
// rules to explicitly exclude
|
||||
flagExcludeGenerated = flag.Bool("exclude-generated", false, "Exclude generated files")
|
||||
|
||||
// log to file or stderr
|
||||
flagLogfile = flag.String("log", "", "Log messages to file rather than stderr")
|
||||
|
||||
|
@ -335,7 +338,7 @@ func main() {
|
|||
}
|
||||
|
||||
// Create the analyzer
|
||||
analyzer := gosec.NewAnalyzer(config, *flagScanTests, logger)
|
||||
analyzer := gosec.NewAnalyzer(config, *flagScanTests, *flagExcludeGenerated, logger)
|
||||
analyzer.LoadRules(ruleDefinitions.Builders())
|
||||
|
||||
excludedDirs := gosec.ExcludedDirsRegExp(flagDirsExclude)
|
||||
|
|
|
@ -25,7 +25,7 @@ var _ = Describe("gosec rules", func() {
|
|||
BeforeEach(func() {
|
||||
logger, _ = testutils.NewLogger()
|
||||
config = gosec.NewConfig()
|
||||
analyzer = gosec.NewAnalyzer(config, tests, logger)
|
||||
analyzer = gosec.NewAnalyzer(config, tests, false, logger)
|
||||
runner = func(rule string, samples []testutils.CodeSample) {
|
||||
for n, sample := range samples {
|
||||
analyzer.Reset()
|
||||
|
|
Loading…
Reference in a new issue