Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge experimental / refactor #146

Merged
merged 26 commits into from
Jan 5, 2018
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
9b08174
Process via packages instead of files
gcmurphy Apr 25, 2017
8df48f9
Fix to reporting to use output formats
gcmurphy Apr 26, 2017
cacf21f
Restructure to focus on lib rather than cli
gcmurphy Apr 26, 2017
bf78d02
Restructure and introduce a standalone config
gcmurphy Apr 28, 2017
50bbc53
Isolate import tracking functionality
gcmurphy May 10, 2017
5160048
Move rule definitions into own file
gcmurphy May 10, 2017
65b18da
Hack to address circular dependency in rulelist
gcmurphy May 10, 2017
026fe4c
Simplify analyzer and command line interface
gcmurphy May 10, 2017
f4b705a
Use glide to manage vendored dependencies
gcmurphy May 10, 2017
6943f9e
Major rework of codebase
gcmurphy Jul 19, 2017
3caf7c3
Add test cases
gcmurphy Sep 16, 2017
9c959ca
Issue.Line is already a string
lanzafame Oct 1, 2017
5a11336
remove commited binary
lanzafame Oct 1, 2017
27b2fd9
Merge pull request #136 from lanzafame/experimental
gcmurphy Oct 4, 2017
67dc432
use godep instead of glide
gcmurphy Dec 13, 2017
d4311c9
make it clear that these tests have not been implemented yet
gcmurphy Dec 13, 2017
02901b9
actually skip tests until implementation exists
gcmurphy Dec 13, 2017
e3b6fd9
update readme to provide info regarding package level scans
gcmurphy Dec 13, 2017
97cde35
update travis-ci to use ginkgo tests
gcmurphy Dec 13, 2017
cfa4327
fix hound-ci errors
gcmurphy Dec 13, 2017
af25ac1
fix golint errors picked up by hound-ci
gcmurphy Dec 13, 2017
25d74c6
address review comments
gcmurphy Dec 14, 2017
e925d3c
Migrated old test cases.
gcmurphy Dec 28, 2017
4c49716
move utils to separate executable
gcmurphy Dec 28, 2017
d452dcb
Fix ginko invocation
gcmurphy Jan 5, 2018
867d300
Fix lint issues
gcmurphy Jan 5, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Process via packages instead of files
Initial commit to change GAS to process packages rather than standalone
files. This is to address issues with type resolution for external
dependencies.

Uses golang.org/x/tools/go/loader to prepare analyzer input rather than
finding the individual files.
  • Loading branch information
gcmurphy committed Apr 25, 2017
commit 9b081744c97953c72719d054fdd0264f43278507
26 changes: 25 additions & 1 deletion core/analyzer.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ import (
"path"
"reflect"
"strings"

"golang.org/x/tools/go/loader"
)

// ImportInfo is used to track aliased and initialization only imports.
Expand Down Expand Up @@ -93,7 +95,7 @@ func NewAnalyzer(conf map[string]interface{}, logger *log.Logger) Analyzer {
a := Analyzer{
ignoreNosec: conf["ignoreNosec"].(bool),
ruleset: make(RuleSet),
context: &Context{nil, nil, nil, nil, nil, nil, nil},
context: &Context{},
logger: logger,
Issues: make([]*Issue, 0, 16),
Stats: &Metrics{0, 0, 0, 0},
Expand Down Expand Up @@ -166,6 +168,28 @@ func (gas *Analyzer) Process(filename string) error {
return err
}

func (gas *Analyzer) ProcessPackage(prog *loader.Program, pkg *loader.PackageInfo, file *ast.File) error {

gas.context.FileSet = prog.Fset
gas.context.Comments = ast.NewCommentMap(gas.context.FileSet, file, file.Comments)
gas.context.Root = file
gas.context.Info = &pkg.Info
gas.context.Pkg = pkg.Pkg
gas.context.Imports = NewImportInfo()
for _, imported := range gas.context.Pkg.Imports() {
gas.context.Imports.Imported[imported.Path()] = imported.Name()
}
ast.Walk(gas, file)
gas.Stats.NumFiles++

count := func(f *token.File) bool {
gas.Stats.NumLines += f.LineCount()
return true
}
prog.Fset.Iterate(count)
return nil
}

// ProcessSource will convert a source code string into an AST and traverse it.
// Rule methods added with AddRule will be invoked as necessary. The string is
// identified by the filename given but no file IO will be done.
Expand Down
174 changes: 85 additions & 89 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,17 @@ import (
"encoding/json"
"flag"
"fmt"
"go/build"
"io/ioutil"
"log"
"os"
"path"
"path/filepath"
"sort"
"strings"

gas "github.com/GoASTScanner/gas/core"
"github.com/GoASTScanner/gas/output"
"golang.org/x/tools/go/loader"
)

type recursion bool
Expand Down Expand Up @@ -60,10 +62,10 @@ can lead to security problems.

USAGE:

# Check a single Go file
$ gas example.go
# Check a single package
$ gas $GOPATH/src/github.com/example/project

# Check all files under the current directory and save results in
# Check all packages under the current directory and save results in
# json format.
$ gas -fmt=json -out=results.json ./...

Expand Down Expand Up @@ -148,6 +150,38 @@ func usage() {
fmt.Fprint(os.Stderr, "\n")
}

// TODO(gm) This needs to be refactored (potentially included in Analyzer)
func analyzePackage(packageDirectory string, config map[string]interface{}, logger *log.Logger) ([]*gas.Issue, error) {

basePackage, err := build.Default.ImportDir(packageDirectory, build.ImportComment)
if err != nil {
return nil, err
}

packageConfig := loader.Config{Build: &build.Default}
packageFiles := make([]string, 0)
for _, filename := range basePackage.GoFiles {
packageFiles = append(packageFiles, path.Join(packageDirectory, filename))
}

packageConfig.CreateFromFilenames(basePackage.Name, packageFiles...)
builtPackage, err := packageConfig.Load()
if err != nil {
return nil, err
}
issues := make([]*gas.Issue, 0)

for _, pkg := range builtPackage.Created {
analyzer := gas.NewAnalyzer(config, logger)
AddRules(&analyzer, config)
for _, file := range pkg.Files {
analyzer.ProcessPackage(builtPackage, pkg, file)
}
issues = append(issues, analyzer.Issues...)
}
return issues, nil
}

func main() {

// Setup usage description
Expand Down Expand Up @@ -187,107 +221,69 @@ func main() {
os.Exit(0)
}

// Setup analyzer
config := buildConfig(incRules, excRules)
analyzer := gas.NewAnalyzer(config, logger)
AddRules(&analyzer, config)

toAnalyze := getFilesToAnalyze(flag.Args(), excluded)
issues := make([]*gas.Issue, 0)
for _, arg := range flag.Args() {
if arg == "./..." {
baseDirectory, err := os.Getwd()
if err != nil {
log.Fatal(err)
}

for _, file := range toAnalyze {
logger.Printf(`Processing "%s"...`, file)
if err := analyzer.Process(file); err != nil {
logger.Printf(`Failed to process: "%s"`, file)
logger.Println(err)
logger.Fatalf(`Halting execution.`)
filepath.Walk(baseDirectory, func(path string, finfo os.FileInfo, e error) error {
dir := filepath.Base(path)
if finfo.IsDir() {
// TODO(gm) - This...
if strings.HasPrefix(dir, ".") || dir == "vendor" || dir == "GoDeps" {
log.Printf("Skipping %s\n", path)
return filepath.SkipDir
}
newIssues, err := analyzePackage(path, config, logger)
if err != nil {
log.Println(err)
} else {
issues = append(issues, newIssues...)
}
}
return nil
})
} else {
newIssues, err := analyzePackage(arg, config, logger)
if err != nil {
log.Fatal(err)
}
issues = newIssues
}
}

issuesFound := len(analyzer.Issues) > 0
issuesFound := len(issues) > 0
// Exit quietly if nothing was found
if !issuesFound && *flagQuiet {
os.Exit(0)
}

// Create output report
if *flagOutput != "" {
outfile, err := os.Create(*flagOutput)
if err != nil {
logger.Fatalf("Couldn't open: %s for writing. Reason - %s", *flagOutput, err)
// TODO(gm) - Report output is borken...
/*
for _, issue := range issues {
log.Println(issue)
}
defer outfile.Close()
output.CreateReport(outfile, *flagFormat, &analyzer)
} else {
output.CreateReport(os.Stdout, *flagFormat, &analyzer)
}

// Do we have an issue? If so exit 1
if issuesFound {
os.Exit(1)
}
}

// getFilesToAnalyze lists all files
func getFilesToAnalyze(paths []string, excluded *fileList) []string {
//log.Println("getFilesToAnalyze: start")
var toAnalyze []string
for _, relativePath := range paths {
//log.Printf("getFilesToAnalyze: processing \"%s\"\n", path)
// get the absolute path before doing anything else
path, err := filepath.Abs(relativePath)
if err != nil {
log.Fatal(err)
}
if filepath.Base(relativePath) == "..." {
toAnalyze = append(
toAnalyze,
listFiles(filepath.Dir(path), recurse, excluded)...,
)
} else {
var (
finfo os.FileInfo
err error
)
if finfo, err = os.Stat(path); err != nil {
logger.Fatal(err)
}
if !finfo.IsDir() {
if shouldInclude(path, excluded) {
toAnalyze = append(toAnalyze, path)
// Create output report
if *flagOutput != "" {
outfile, err := os.Create(*flagOutput)
if err != nil {
logger.Fatalf("Couldn't open: %s for writing. Reason - %s", *flagOutput, err)
}
defer outfile.Close()
output.CreateReport(outfile, *flagFormat, &analyzer)
} else {
toAnalyze = listFiles(path, noRecurse, excluded)
output.CreateReport(os.Stdout, *flagFormat, &analyzer)
}
}
}
//log.Println("getFilesToAnalyze: end")
return toAnalyze
}

// listFiles returns a list of all files found that pass the shouldInclude check.
// If doRecursiveWalk it true, it will walk the tree rooted at absPath, otherwise it
// will only include files directly within the dir referenced by absPath.
func listFiles(absPath string, doRecursiveWalk recursion, excluded *fileList) []string {
var files []string
*/

walk := func(path string, info os.FileInfo, err error) error {
if info.IsDir() && doRecursiveWalk == noRecurse {
return filepath.SkipDir
}
if shouldInclude(path, excluded) {
files = append(files, path)
}
return nil
}

if err := filepath.Walk(absPath, walk); err != nil {
log.Fatal(err)
// Do we have an issue? If so exit 1
if issuesFound {
os.Exit(1)
}
return files
}

// shouldInclude checks if a specific path which is expected to reference
// a regular file should be included
func shouldInclude(path string, excluded *fileList) bool {
return filepath.Ext(path) == ".go" && !excluded.Contains(path)
}
2 changes: 1 addition & 1 deletion vendor.conf
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# package
github.com/GoAstScanner/gas
github.com/GoASTScanner/gas

# import
github.com/GoASTScanner/gas cc52ef5
Expand Down