Skip to content

Commit

Permalink
Allow excluding generated files
Browse files Browse the repository at this point in the history
  • Loading branch information
bakito authored Aug 4, 2021
1 parent 521e69e commit 62db813
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 27 deletions.
14 changes: 13 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 ./...
```

Expand All @@ -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,
Expand Down
58 changes: 39 additions & 19 deletions analyzer.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand All @@ -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,
}
}

Expand Down Expand Up @@ -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
Expand All @@ -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 {
Expand Down
52 changes: 47 additions & 5 deletions analyzer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down Expand Up @@ -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()
Expand All @@ -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()
Expand All @@ -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()
Expand All @@ -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()
Expand All @@ -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())
Expand Down
5 changes: 4 additions & 1 deletion cmd/gosec/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")

Expand Down Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion rules/rules_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down

0 comments on commit 62db813

Please sign in to comment.