mirror of
https://github.com/securego/gosec.git
synced 2024-12-26 04:25:52 +00:00
Cache loaded packages in analyzer.
Avoid reloading any packages that have already been loaded as a side-effect.
This commit is contained in:
parent
085e0f65af
commit
c39757b63e
2 changed files with 93 additions and 21 deletions
88
analyzer.go
88
analyzer.go
|
@ -54,13 +54,19 @@ type Metrics struct {
|
||||||
// Analyzer object is the main object of GAS. It has methods traverse an AST
|
// Analyzer object is the main object of GAS. 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
|
||||||
|
builtPkgCache map[string]*buildPackageCacheEntry
|
||||||
|
}
|
||||||
|
|
||||||
|
type buildPackageCacheEntry struct {
|
||||||
|
info *loader.PackageInfo
|
||||||
|
fset *token.FileSet
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewAnalyzer builds a new anaylzer.
|
// NewAnalyzer builds a new anaylzer.
|
||||||
|
@ -73,13 +79,14 @@ func NewAnalyzer(conf Config, logger *log.Logger) *Analyzer {
|
||||||
logger = log.New(os.Stderr, "[gas]", log.LstdFlags)
|
logger = log.New(os.Stderr, "[gas]", 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{},
|
||||||
|
builtPkgCache: make(map[string]*buildPackageCacheEntry),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,6 +101,8 @@ func (gas *Analyzer) LoadRules(ruleDefinitions ...RuleBuilder) {
|
||||||
|
|
||||||
// Process kicks off the analysis process for a given package
|
// Process kicks off the analysis process for a given package
|
||||||
func (gas *Analyzer) Process(packagePath string) error {
|
func (gas *Analyzer) Process(packagePath string) error {
|
||||||
|
var packages []*loader.PackageInfo
|
||||||
|
var fset *token.FileSet
|
||||||
|
|
||||||
basePackage, err := build.Default.ImportDir(packagePath, build.ImportComment)
|
basePackage, err := build.Default.ImportDir(packagePath, build.ImportComment)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -107,16 +116,53 @@ func (gas *Analyzer) Process(packagePath string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
packageConfig.CreateFromFilenames(basePackage.Name, packageFiles...)
|
packageConfig.CreateFromFilenames(basePackage.Name, packageFiles...)
|
||||||
builtPackage, err := packageConfig.Load()
|
|
||||||
if err != nil {
|
pkgCachePath := packagePath
|
||||||
return err
|
// Calculate an absolute import path because the cache is keyed by the absolute import path
|
||||||
|
if build.IsLocalImport(pkgCachePath) {
|
||||||
|
wd, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
pkg, err := build.Default.Import(packagePath, wd, build.ImportComment)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
pkgCachePath = pkg.ImportPath
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, pkg := range builtPackage.Created {
|
if gas.builtPkgCache[pkgCachePath] != nil {
|
||||||
|
entry := gas.builtPkgCache[pkgCachePath]
|
||||||
|
packages = append(packages, entry.info)
|
||||||
|
fset = entry.fset
|
||||||
|
} else {
|
||||||
|
builtPackage, err := packageConfig.Load()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
packages = builtPackage.Created
|
||||||
|
fset = builtPackage.Fset
|
||||||
|
|
||||||
|
// Cache built packages
|
||||||
|
for details, pkg := range builtPackage.AllPackages {
|
||||||
|
if !details.Complete() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
entry := buildPackageCacheEntry{
|
||||||
|
info: pkg,
|
||||||
|
fset: builtPackage.Fset,
|
||||||
|
}
|
||||||
|
gas.builtPkgCache[pkg.Pkg.Path()] = &entry
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, pkg := range packages {
|
||||||
gas.logger.Println("Checking package:", pkg.String())
|
gas.logger.Println("Checking package:", pkg.String())
|
||||||
for _, file := range pkg.Files {
|
for _, file := range pkg.Files {
|
||||||
gas.logger.Println("Checking file:", builtPackage.Fset.File(file.Pos()).Name())
|
gas.logger.Println("Checking file:", fset.File(file.Pos()).Name())
|
||||||
gas.context.FileSet = builtPackage.Fset
|
gas.context.FileSet = fset
|
||||||
gas.context.Config = gas.config
|
gas.context.Config = gas.config
|
||||||
gas.context.Comments = ast.NewCommentMap(gas.context.FileSet, file, file.Comments)
|
gas.context.Comments = ast.NewCommentMap(gas.context.FileSet, file, file.Comments)
|
||||||
gas.context.Root = file
|
gas.context.Root = file
|
||||||
|
@ -126,7 +172,7 @@ func (gas *Analyzer) Process(packagePath string) error {
|
||||||
gas.context.Imports.TrackPackages(gas.context.Pkg.Imports()...)
|
gas.context.Imports.TrackPackages(gas.context.Pkg.Imports()...)
|
||||||
ast.Walk(gas, file)
|
ast.Walk(gas, file)
|
||||||
gas.stats.NumFiles++
|
gas.stats.NumFiles++
|
||||||
gas.stats.NumLines += builtPackage.Fset.File(file.Pos()).LineCount()
|
gas.stats.NumLines += fset.File(file.Pos()).LineCount()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -73,6 +73,32 @@ var _ = Describe("Analyzer", func() {
|
||||||
Expect(metrics.NumFiles).To(Equal(2))
|
Expect(metrics.NumFiles).To(Equal(2))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
It("should return report double the lines even when a package is processed twice (despite caching)", func() {
|
||||||
|
analyzer.LoadRules(rules.Generate().Builders()...)
|
||||||
|
pkg := testutils.NewTestPackage()
|
||||||
|
defer pkg.Close()
|
||||||
|
pkg.AddFile("foo.go", `
|
||||||
|
package main
|
||||||
|
func main(){
|
||||||
|
bar()
|
||||||
|
}`)
|
||||||
|
pkg.AddFile("bar.go", `
|
||||||
|
package main
|
||||||
|
func bar(){
|
||||||
|
println("package has two files!")
|
||||||
|
}`)
|
||||||
|
pkg.Build()
|
||||||
|
err := analyzer.Process(pkg.Path)
|
||||||
|
Expect(err).ShouldNot(HaveOccurred())
|
||||||
|
_, metrics := analyzer.Report()
|
||||||
|
Expect(metrics.NumFiles).To(Equal(2))
|
||||||
|
|
||||||
|
err = analyzer.Process(pkg.Path)
|
||||||
|
Expect(err).ShouldNot(HaveOccurred())
|
||||||
|
_, metrics = analyzer.Report()
|
||||||
|
Expect(metrics.NumFiles).To(Equal(4))
|
||||||
|
})
|
||||||
|
|
||||||
It("should find errors when nosec is not in use", func() {
|
It("should find errors when nosec is not in use", func() {
|
||||||
|
|
||||||
// Rule for MD5 weak crypto usage
|
// Rule for MD5 weak crypto usage
|
||||||
|
|
Loading…
Reference in a new issue