mirror of
https://github.com/securego/gosec.git
synced 2024-12-25 03:55:54 +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:
|
The scanning of test files can be enabled with the following flag:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|
||||||
gosec -tests ./...
|
gosec -tests ./...
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -246,6 +245,19 @@ Also additional folders can be excluded as follows:
|
||||||
gosec -exclude-dir=rules -exclude-dir=cmd ./...
|
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
|
### 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,
|
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.NeedTypesInfo |
|
||||||
packages.NeedSyntax
|
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.
|
// 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
|
// It is passed through to all rule functions as they are called. Rules may use
|
||||||
// this data in conjunction withe the encountered AST node.
|
// 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
|
// 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.
|
// and invoke the correct checking rules as on each node as required.
|
||||||
type Analyzer struct {
|
type Analyzer struct {
|
||||||
ignoreNosec bool
|
ignoreNosec bool
|
||||||
ruleset RuleSet
|
ruleset RuleSet
|
||||||
context *Context
|
context *Context
|
||||||
config Config
|
config Config
|
||||||
logger *log.Logger
|
logger *log.Logger
|
||||||
issues []*Issue
|
issues []*Issue
|
||||||
stats *Metrics
|
stats *Metrics
|
||||||
errors map[string][]Error // keys are file paths; values are the golang errors in those files
|
errors map[string][]Error // keys are file paths; values are the golang errors in those files
|
||||||
tests bool
|
tests bool
|
||||||
|
excludeGenerated bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewAnalyzer builds a new analyzer.
|
// 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
|
ignoreNoSec := false
|
||||||
if enabled, err := conf.IsGlobalEnabled(Nosec); err == nil {
|
if enabled, err := conf.IsGlobalEnabled(Nosec); err == nil {
|
||||||
ignoreNoSec = enabled
|
ignoreNoSec = enabled
|
||||||
|
@ -91,15 +94,16 @@ func NewAnalyzer(conf Config, tests bool, logger *log.Logger) *Analyzer {
|
||||||
logger = log.New(os.Stderr, "[gosec]", log.LstdFlags)
|
logger = log.New(os.Stderr, "[gosec]", log.LstdFlags)
|
||||||
}
|
}
|
||||||
return &Analyzer{
|
return &Analyzer{
|
||||||
ignoreNosec: ignoreNoSec,
|
ignoreNosec: ignoreNoSec,
|
||||||
ruleset: make(RuleSet),
|
ruleset: make(RuleSet),
|
||||||
context: &Context{},
|
context: &Context{},
|
||||||
config: conf,
|
config: conf,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
issues: make([]*Issue, 0, 16),
|
issues: make([]*Issue, 0, 16),
|
||||||
stats: &Metrics{},
|
stats: &Metrics{},
|
||||||
errors: make(map[string][]Error),
|
errors: make(map[string][]Error),
|
||||||
tests: tests,
|
tests: tests,
|
||||||
|
excludeGenerated: excludeGenerated,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,6 +206,11 @@ func (gosec *Analyzer) Check(pkg *packages.Package) {
|
||||||
if filepath.Ext(checkedFile) != ".go" {
|
if filepath.Ext(checkedFile) != ".go" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if gosec.excludeGenerated && isGeneratedFile(file) {
|
||||||
|
gosec.logger.Println("Ignoring generated file:", checkedFile)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
gosec.logger.Println("Checking file:", checkedFile)
|
gosec.logger.Println("Checking file:", checkedFile)
|
||||||
gosec.context.FileSet = pkg.Fset
|
gosec.context.FileSet = pkg.Fset
|
||||||
gosec.context.Config = gosec.config
|
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
|
// ParseErrors parses the errors from given package
|
||||||
func (gosec *Analyzer) ParseErrors(pkg *packages.Package) error {
|
func (gosec *Analyzer) ParseErrors(pkg *packages.Package) error {
|
||||||
if len(pkg.Errors) == 0 {
|
if len(pkg.Errors) == 0 {
|
||||||
|
|
|
@ -25,7 +25,7 @@ var _ = Describe("Analyzer", func() {
|
||||||
)
|
)
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
logger, _ = testutils.NewLogger()
|
logger, _ = testutils.NewLogger()
|
||||||
analyzer = gosec.NewAnalyzer(nil, tests, logger)
|
analyzer = gosec.NewAnalyzer(nil, tests, false, logger)
|
||||||
})
|
})
|
||||||
|
|
||||||
Context("when processing a package", func() {
|
Context("when processing a package", func() {
|
||||||
|
@ -246,7 +246,7 @@ var _ = Describe("Analyzer", func() {
|
||||||
// overwrite nosec option
|
// overwrite nosec option
|
||||||
nosecIgnoreConfig := gosec.NewConfig()
|
nosecIgnoreConfig := gosec.NewConfig()
|
||||||
nosecIgnoreConfig.SetGlobal(gosec.Nosec, "true")
|
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())
|
customAnalyzer.LoadRules(rules.Generate(rules.NewRuleFilter(false, "G401")).Builders())
|
||||||
|
|
||||||
nosecPackage := testutils.NewTestPackage()
|
nosecPackage := testutils.NewTestPackage()
|
||||||
|
@ -269,7 +269,7 @@ var _ = Describe("Analyzer", func() {
|
||||||
// overwrite nosec option
|
// overwrite nosec option
|
||||||
nosecIgnoreConfig := gosec.NewConfig()
|
nosecIgnoreConfig := gosec.NewConfig()
|
||||||
nosecIgnoreConfig.SetGlobal(gosec.NoSecAlternative, "#falsePositive")
|
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())
|
customAnalyzer.LoadRules(rules.Generate(rules.NewRuleFilter(false, "G401")).Builders())
|
||||||
|
|
||||||
nosecPackage := testutils.NewTestPackage()
|
nosecPackage := testutils.NewTestPackage()
|
||||||
|
@ -292,7 +292,7 @@ var _ = Describe("Analyzer", func() {
|
||||||
// overwrite nosec option
|
// overwrite nosec option
|
||||||
nosecIgnoreConfig := gosec.NewConfig()
|
nosecIgnoreConfig := gosec.NewConfig()
|
||||||
nosecIgnoreConfig.SetGlobal(gosec.NoSecAlternative, "#falsePositive")
|
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())
|
customAnalyzer.LoadRules(rules.Generate(rules.NewRuleFilter(false, "G401")).Builders())
|
||||||
|
|
||||||
nosecPackage := testutils.NewTestPackage()
|
nosecPackage := testutils.NewTestPackage()
|
||||||
|
@ -308,7 +308,7 @@ var _ = Describe("Analyzer", func() {
|
||||||
})
|
})
|
||||||
|
|
||||||
It("should be able to analyze Go test package", 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())
|
customAnalyzer.LoadRules(rules.Generate().Builders())
|
||||||
pkg := testutils.NewTestPackage()
|
pkg := testutils.NewTestPackage()
|
||||||
defer pkg.Close()
|
defer pkg.Close()
|
||||||
|
@ -332,6 +332,48 @@ var _ = Describe("Analyzer", func() {
|
||||||
issues, _, _ := customAnalyzer.Report()
|
issues, _, _ := customAnalyzer.Report()
|
||||||
Expect(issues).Should(HaveLen(1))
|
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() {
|
It("should be able to analyze Cgo files", func() {
|
||||||
analyzer.LoadRules(rules.Generate().Builders())
|
analyzer.LoadRules(rules.Generate().Builders())
|
||||||
|
|
|
@ -93,6 +93,9 @@ var (
|
||||||
// rules to explicitly exclude
|
// rules to explicitly exclude
|
||||||
flagRulesExclude = flag.String("exclude", "", "Comma separated list of rules IDs to exclude. (see rule list)")
|
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
|
// log to file or stderr
|
||||||
flagLogfile = flag.String("log", "", "Log messages to file rather than stderr")
|
flagLogfile = flag.String("log", "", "Log messages to file rather than stderr")
|
||||||
|
|
||||||
|
@ -335,7 +338,7 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the analyzer
|
// Create the analyzer
|
||||||
analyzer := gosec.NewAnalyzer(config, *flagScanTests, logger)
|
analyzer := gosec.NewAnalyzer(config, *flagScanTests, *flagExcludeGenerated, logger)
|
||||||
analyzer.LoadRules(ruleDefinitions.Builders())
|
analyzer.LoadRules(ruleDefinitions.Builders())
|
||||||
|
|
||||||
excludedDirs := gosec.ExcludedDirsRegExp(flagDirsExclude)
|
excludedDirs := gosec.ExcludedDirsRegExp(flagDirsExclude)
|
||||||
|
|
|
@ -25,7 +25,7 @@ var _ = Describe("gosec rules", func() {
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
logger, _ = testutils.NewLogger()
|
logger, _ = testutils.NewLogger()
|
||||||
config = gosec.NewConfig()
|
config = gosec.NewConfig()
|
||||||
analyzer = gosec.NewAnalyzer(config, tests, logger)
|
analyzer = gosec.NewAnalyzer(config, tests, false, logger)
|
||||||
runner = func(rule string, samples []testutils.CodeSample) {
|
runner = func(rule string, samples []testutils.CodeSample) {
|
||||||
for n, sample := range samples {
|
for n, sample := range samples {
|
||||||
analyzer.Reset()
|
analyzer.Reset()
|
||||||
|
|
Loading…
Reference in a new issue