Add support to exclude arbitrary folders from scanning (#353)

Signed-off-by: Cosmin Cojocar <cosmin.cojocar@gmx.ch>
This commit is contained in:
Cosmin Cojocar 2019-09-09 14:01:36 +02:00 committed by Grant Murphy
parent 1c35be8eca
commit 7851918c4f
4 changed files with 79 additions and 15 deletions

View file

@ -137,13 +137,21 @@ of functions which will be skipped when auditing the not checked errors:
gosec will fetch automatically the dependencies of the code which is being analyzed when go modules are turned on (e.g.` GO111MODULE=on`). If this is not the case,
the dependencies need to be explicitly downloaded by running the `go get -d` command before the scan.
### Excluding test files and folders
### Excluding files
gosec will ignore test files across all packages and any dependencies in your vendor directory.
gosec will ignore tests files and any dependencies in your vendor directory. The scanning of these artifacts can be enabled with the following flags:
The scanning of test files can be enabled with the following flag:
```bash
gosec -tests -vendor ./...
gosec -tests ./...
```
Also additional folders can be excluded as follows:
```bash
gosec -exclude-dir=rules -exclude-dir=cmd ./...
```
### Annotating code

View file

@ -20,7 +20,6 @@ import (
"io/ioutil"
"log"
"os"
"regexp"
"sort"
"strings"
@ -58,6 +57,17 @@ USAGE:
`
)
type arrayFlags []string
func (a *arrayFlags) String() string {
return strings.Join(*a, " ")
}
func (a *arrayFlags) Set(value string) error {
*a = append(*a, value)
return nil
}
var (
// #nosec flag
flagIgnoreNoSec = flag.Bool("nosec", false, "Ignores #nosec comments when set")
@ -92,9 +102,6 @@ var (
// go build tags
flagBuildTags = flag.String("tags", "", "Comma separated list of build tags")
// scan the vendor folder
flagScanVendor = flag.Bool("vendor", false, "Scan the vendor folder")
// fail by severity
flagSeverity = flag.String("severity", "low", "Filter out the issues with a lower severity than the given value. Valid options are: low, medium, high")
@ -110,6 +117,9 @@ var (
// print version and quit with exit code 0
flagVersion = flag.Bool("version", false, "Print version and quit with exit code 0")
// exlude the folders from scan
flagDirsExclude arrayFlags
logger *log.Logger
)
@ -233,6 +243,13 @@ func main() {
// Setup usage description
flag.Usage = usage
// Setup the excluded folders from scan
flag.Var(&flagDirsExclude, "exclude-dir", "Exclude folder from scan (can be specified multiple times)")
err := flag.Set("exclude-dir", "vendor")
if err != nil {
fmt.Fprintf(os.Stderr, "\nError: failed to exclude the %q directory from scan", "vendor")
}
// Parse command line arguments
flag.Parse()
@ -291,13 +308,10 @@ func main() {
analyzer := gosec.NewAnalyzer(config, *flagScanTests, logger)
analyzer.LoadRules(ruleDefinitions.Builders())
var vendor *regexp.Regexp
if !*flagScanVendor {
vendor = regexp.MustCompile(`([\\/])?vendor([\\/])?`)
}
excludedDirs := gosec.ExcludedDirsRegExp(flagDirsExclude)
var packages []string
for _, path := range flag.Args() {
pcks, err := gosec.PackagePaths(path, vendor)
pcks, err := gosec.PackagePaths(path, excludedDirs)
if err != nil {
logger.Fatal(err)
}

View file

@ -360,7 +360,7 @@ func FindVarIdentities(n *ast.BinaryExpr, c *Context) ([]*ast.Ident, bool) {
}
// PackagePaths returns a slice with all packages path at given root directory
func PackagePaths(root string, exclude *regexp.Regexp) ([]string, error) {
func PackagePaths(root string, excludes []*regexp.Regexp) ([]string, error) {
if strings.HasSuffix(root, "...") {
root = root[0 : len(root)-3]
} else {
@ -370,7 +370,7 @@ func PackagePaths(root string, exclude *regexp.Regexp) ([]string, error) {
err := filepath.Walk(root, func(path string, f os.FileInfo, err error) error {
if filepath.Ext(path) == ".go" {
path = filepath.Dir(path)
if exclude != nil && exclude.MatchString(path) {
if isExcluded(path, excludes) {
return nil
}
paths[path] = true
@ -388,6 +388,30 @@ func PackagePaths(root string, exclude *regexp.Regexp) ([]string, error) {
return result, nil
}
// isExcluded checks if a string matches any of the exclusion regexps
func isExcluded(str string, excludes []*regexp.Regexp) bool {
if excludes == nil {
return false
}
for _, exclude := range excludes {
if exclude != nil && exclude.MatchString(str) {
return true
}
}
return false
}
// ExcludedDirsRegExp builds the regexps for a list of excluded dirs provided as strings
func ExcludedDirsRegExp(excludedDirs []string) []*regexp.Regexp {
var exps []*regexp.Regexp
for _, excludedDir := range excludedDirs {
str := fmt.Sprintf(`([\\/])?%s([\\/])?`, excludedDir)
r := regexp.MustCompile(str)
exps = append(exps, r)
}
return exps
}
// RootPath returns the absolute root path of a scan
func RootPath(root string) (string, error) {
if strings.HasSuffix(root, "...") {

View file

@ -43,7 +43,7 @@ var _ = Describe("Helpers", func() {
Expect(err).ShouldNot(HaveOccurred())
exclude, err := regexp.Compile(`([\\/])?vendor([\\/])?`)
Expect(err).ShouldNot(HaveOccurred())
paths, err := gosec.PackagePaths(dir+"/...", exclude)
paths, err := gosec.PackagePaths(dir+"/...", []*regexp.Regexp{exclude})
Expect(err).ShouldNot(HaveOccurred())
Expect(paths).Should(Equal([]string{dir}))
})
@ -73,4 +73,22 @@ var _ = Describe("Helpers", func() {
Expect(root).Should(Equal(filepath.Join(cwd, base)))
})
})
Context("when excluding the dirs", func() {
It("should create a proper regexp", func() {
r := gosec.ExcludedDirsRegExp([]string{"test"})
Expect(len(r)).Should(Equal(1))
match := r[0].MatchString("/home/go/src/project/test/pkg")
Expect(match).Should(BeTrue())
match = r[0].MatchString("/home/go/src/project/vendor/pkg")
Expect(match).Should(BeFalse())
})
It("should create no regexp when dir list is empty", func() {
r := gosec.ExcludedDirsRegExp(nil)
Expect(len(r)).Should(Equal(0))
r = gosec.ExcludedDirsRegExp([]string{})
Expect(len(r)).Should(Equal(0))
})
})
})