You've already forked postgres_exporter
mirror of
https://github.com/prometheus-community/postgres_exporter.git
synced 2025-08-06 17:22:43 +03:00
Refactor repository layout and convert build system to Mage.
This commit implements a massive refactor of the repository, and moves the build system over to use Mage (magefile.org) which should allow seamless building across multiple platforms.
This commit is contained in:
39
tools/vendor/github.com/GoASTScanner/gas/README.md
generated
vendored
39
tools/vendor/github.com/GoASTScanner/gas/README.md
generated
vendored
@@ -18,6 +18,10 @@ You may obtain a copy of the License [here](http://www.apache.org/licenses/LICEN
|
||||
Gas is still in alpha and accepting feedback from early adopters. We do
|
||||
not consider it production ready at this time.
|
||||
|
||||
### Install
|
||||
|
||||
`$ go get github.com/GoASTScanner/gas/cmd/gas/...`
|
||||
|
||||
### Usage
|
||||
|
||||
Gas can be configured to only run a subset of rules, to exclude certain file
|
||||
@@ -37,6 +41,7 @@ or to specify a set of rules to explicitly exclude using the '-exclude=' flag.
|
||||
- G103: Audit the use of unsafe block
|
||||
- G104: Audit errors not checked
|
||||
- G105: Audit the use of math/big.Int.Exp
|
||||
- G106: Audit the use of ssh.InsecureIgnoreHostKey
|
||||
- G201: SQL query construction using format string
|
||||
- G202: SQL query construction using string concatenation
|
||||
- G203: Use of unescaped data in HTML templates
|
||||
@@ -64,12 +69,8 @@ $ gas -exclude=G303 ./...
|
||||
|
||||
#### Excluding files:
|
||||
|
||||
Gas can be told to \ignore paths that match a supplied pattern using the 'skip' command line option. This is
|
||||
accomplished via [go-glob](github.com/ryanuber/go-glob). Multiple patterns can be specified as follows:
|
||||
|
||||
```
|
||||
$ gas -skip=tests* -skip=*_example.go ./...
|
||||
```
|
||||
Gas will ignore dependencies in your vendor directory any files
|
||||
that are not considered build artifacts by the compiler (so test files).
|
||||
|
||||
#### Annotating code
|
||||
|
||||
@@ -104,7 +105,7 @@ $ gas -nosec=true ./...
|
||||
|
||||
### Output formats
|
||||
|
||||
Gas currently supports text, json and csv output formats. By default
|
||||
Gas currently supports text, json, yaml, csv and JUnit XML output formats. By default
|
||||
results will be reported to stdout, but can also be written to an output
|
||||
file. The output format is controlled by the '-fmt' flag, and the output file is controlled by the '-out' flag as follows:
|
||||
|
||||
@@ -113,19 +114,21 @@ file. The output format is controlled by the '-fmt' flag, and the output file is
|
||||
$ gas -fmt=json -out=results.json *.go
|
||||
```
|
||||
|
||||
### Docker container
|
||||
### Generate TLS rule
|
||||
|
||||
A Dockerfile is included with the Gas source code to provide a container that
|
||||
allows users to easily run Gas on their code. It builds Gas, then runs it on
|
||||
all Go files in your current directory. Use the following commands to build
|
||||
and run locally:
|
||||
The configuration of TLS rule can be generated from [Mozilla's TLS ciphers recommendation](https://statics.tls.security.mozilla.org/server-side-tls-conf.json).
|
||||
|
||||
To build: (run command in cloned Gas source code directory)
|
||||
docker build --build-arg http_proxy --build-arg https_proxy
|
||||
--build-arg no_proxy -t goastscanner/gas:latest .
|
||||
|
||||
To run: (run command in desired directory with Go files)
|
||||
docker run -v $PWD:$PWD --workdir $PWD goastscanner/gas:latest
|
||||
First you need to install the generator tool:
|
||||
|
||||
Note: Docker version 17.05 or later is required (to permit multistage build).
|
||||
```
|
||||
go get github.com/GoASTScanner/gas/cmd/tlsconfig/...
|
||||
```
|
||||
|
||||
You can invoke now the `go generate` in the root of the project:
|
||||
|
||||
```
|
||||
go generate ./...
|
||||
```
|
||||
|
||||
This will generate the `rules/tls_config.go` file with will contain the current ciphers recommendation from Mozilla.
|
||||
|
197
tools/vendor/github.com/GoASTScanner/gas/analyzer.go
generated
vendored
Normal file
197
tools/vendor/github.com/GoASTScanner/gas/analyzer.go
generated
vendored
Normal file
@@ -0,0 +1,197 @@
|
||||
// (c) Copyright 2016 Hewlett Packard Enterprise Development LP
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package gas holds the central scanning logic used by GAS
|
||||
package gas
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"go/build"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"go/types"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"path/filepath"
|
||||
|
||||
"golang.org/x/tools/go/loader"
|
||||
)
|
||||
|
||||
// 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 encoutered AST node.
|
||||
type Context struct {
|
||||
FileSet *token.FileSet
|
||||
Comments ast.CommentMap
|
||||
Info *types.Info
|
||||
Pkg *types.Package
|
||||
Root *ast.File
|
||||
Config map[string]interface{}
|
||||
Imports *ImportTracker
|
||||
}
|
||||
|
||||
// Metrics used when reporting information about a scanning run.
|
||||
type Metrics struct {
|
||||
NumFiles int `json:"files"`
|
||||
NumLines int `json:"lines"`
|
||||
NumNosec int `json:"nosec"`
|
||||
NumFound int `json:"found"`
|
||||
}
|
||||
|
||||
// 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.
|
||||
type Analyzer struct {
|
||||
ignoreNosec bool
|
||||
ruleset RuleSet
|
||||
context *Context
|
||||
config Config
|
||||
logger *log.Logger
|
||||
issues []*Issue
|
||||
stats *Metrics
|
||||
}
|
||||
|
||||
// NewAnalyzer builds a new anaylzer.
|
||||
func NewAnalyzer(conf Config, logger *log.Logger) *Analyzer {
|
||||
ignoreNoSec := false
|
||||
if setting, err := conf.GetGlobal("nosec"); err == nil {
|
||||
ignoreNoSec = setting == "true" || setting == "enabled"
|
||||
}
|
||||
if logger == nil {
|
||||
logger = log.New(os.Stderr, "[gas]", log.LstdFlags)
|
||||
}
|
||||
return &Analyzer{
|
||||
ignoreNosec: ignoreNoSec,
|
||||
ruleset: make(RuleSet),
|
||||
context: &Context{},
|
||||
config: conf,
|
||||
logger: logger,
|
||||
issues: make([]*Issue, 0, 16),
|
||||
stats: &Metrics{},
|
||||
}
|
||||
}
|
||||
|
||||
// LoadRules instantiates all the rules to be used when analyzing source
|
||||
// packages
|
||||
func (gas *Analyzer) LoadRules(ruleDefinitions ...RuleBuilder) {
|
||||
for _, builder := range ruleDefinitions {
|
||||
r, nodes := builder(gas.config)
|
||||
gas.ruleset.Register(r, nodes...)
|
||||
}
|
||||
}
|
||||
|
||||
// Process kicks off the analysis process for a given package
|
||||
func (gas *Analyzer) Process(packagePaths ...string) error {
|
||||
packageConfig := loader.Config{
|
||||
Build: &build.Default,
|
||||
ParserMode: parser.ParseComments,
|
||||
AllowErrors: true,
|
||||
}
|
||||
for _, packagePath := range packagePaths {
|
||||
abspath, err := filepath.Abs(packagePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
gas.logger.Println("Searching directory:", abspath)
|
||||
|
||||
basePackage, err := build.Default.ImportDir(packagePath, build.ImportComment)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var packageFiles []string
|
||||
for _, filename := range basePackage.GoFiles {
|
||||
packageFiles = append(packageFiles, path.Join(packagePath, filename))
|
||||
}
|
||||
|
||||
packageConfig.CreateFromFilenames(basePackage.Name, packageFiles...)
|
||||
}
|
||||
|
||||
builtPackage, err := packageConfig.Load()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, pkg := range builtPackage.Created {
|
||||
gas.logger.Println("Checking package:", pkg.String())
|
||||
for _, file := range pkg.Files {
|
||||
gas.logger.Println("Checking file:", builtPackage.Fset.File(file.Pos()).Name())
|
||||
gas.context.FileSet = builtPackage.Fset
|
||||
gas.context.Config = gas.config
|
||||
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 = NewImportTracker()
|
||||
gas.context.Imports.TrackPackages(gas.context.Pkg.Imports()...)
|
||||
ast.Walk(gas, file)
|
||||
gas.stats.NumFiles++
|
||||
gas.stats.NumLines += builtPackage.Fset.File(file.Pos()).LineCount()
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ignore a node (and sub-tree) if it is tagged with a "#nosec" comment
|
||||
func (gas *Analyzer) ignore(n ast.Node) bool {
|
||||
if groups, ok := gas.context.Comments[n]; ok && !gas.ignoreNosec {
|
||||
for _, group := range groups {
|
||||
if strings.Contains(group.Text(), "#nosec") {
|
||||
gas.stats.NumNosec++
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Visit runs the GAS visitor logic over an AST created by parsing go code.
|
||||
// Rule methods added with AddRule will be invoked as necessary.
|
||||
func (gas *Analyzer) Visit(n ast.Node) ast.Visitor {
|
||||
if !gas.ignore(n) {
|
||||
|
||||
// Track aliased and initialization imports
|
||||
gas.context.Imports.TrackImport(n)
|
||||
|
||||
for _, rule := range gas.ruleset.RegisteredFor(n) {
|
||||
issue, err := rule.Match(n, gas.context)
|
||||
if err != nil {
|
||||
file, line := GetLocation(n, gas.context)
|
||||
file = path.Base(file)
|
||||
gas.logger.Printf("Rule error: %v => %s (%s:%d)\n", reflect.TypeOf(rule), err, file, line)
|
||||
}
|
||||
if issue != nil {
|
||||
gas.issues = append(gas.issues, issue)
|
||||
gas.stats.NumFound++
|
||||
}
|
||||
}
|
||||
return gas
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Report returns the current issues discovered and the metrics about the scan
|
||||
func (gas *Analyzer) Report() ([]*Issue, *Metrics) {
|
||||
return gas.issues, gas.stats
|
||||
}
|
||||
|
||||
// Reset clears state such as context, issues and metrics from the configured analyzer
|
||||
func (gas *Analyzer) Reset() {
|
||||
gas.context = &Context{}
|
||||
gas.issues = make([]*Issue, 0, 16)
|
||||
gas.stats = &Metrics{}
|
||||
}
|
@@ -11,7 +11,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package core
|
||||
package gas
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
@@ -19,23 +19,23 @@ import (
|
||||
|
||||
type set map[string]bool
|
||||
|
||||
/// CallList is used to check for usage of specific packages
|
||||
/// and functions.
|
||||
// CallList is used to check for usage of specific packages
|
||||
// and functions.
|
||||
type CallList map[string]set
|
||||
|
||||
/// NewCallList creates a new empty CallList
|
||||
// NewCallList creates a new empty CallList
|
||||
func NewCallList() CallList {
|
||||
return make(CallList)
|
||||
}
|
||||
|
||||
/// AddAll will add several calls to the call list at once
|
||||
// AddAll will add several calls to the call list at once
|
||||
func (c CallList) AddAll(selector string, idents ...string) {
|
||||
for _, ident := range idents {
|
||||
c.Add(selector, ident)
|
||||
}
|
||||
}
|
||||
|
||||
/// Add a selector and call to the call list
|
||||
// Add a selector and call to the call list
|
||||
func (c CallList) Add(selector, ident string) {
|
||||
if _, ok := c[selector]; !ok {
|
||||
c[selector] = make(set)
|
||||
@@ -43,7 +43,7 @@ func (c CallList) Add(selector, ident string) {
|
||||
c[selector][ident] = true
|
||||
}
|
||||
|
||||
/// Contains returns true if the package and function are
|
||||
// Contains returns true if the package and function are
|
||||
/// members of this call list.
|
||||
func (c CallList) Contains(selector, ident string) bool {
|
||||
if idents, ok := c[selector]; ok {
|
||||
@@ -53,21 +53,26 @@ func (c CallList) Contains(selector, ident string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
/// ContainsCallExpr resolves the call expression name and type
|
||||
// ContainsCallExpr resolves the call expression name and type
|
||||
/// or package and determines if it exists within the CallList
|
||||
func (c CallList) ContainsCallExpr(n ast.Node, ctx *Context) bool {
|
||||
func (c CallList) ContainsCallExpr(n ast.Node, ctx *Context) *ast.CallExpr {
|
||||
selector, ident, err := GetCallInfo(n, ctx)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
// Try direct resolution
|
||||
if c.Contains(selector, ident) {
|
||||
return true
|
||||
return nil
|
||||
}
|
||||
|
||||
// Also support explicit path
|
||||
if path, ok := GetImportPath(selector, ctx); ok {
|
||||
return c.Contains(path, ident)
|
||||
// Use only explicit path to reduce conflicts
|
||||
if path, ok := GetImportPath(selector, ctx); ok && c.Contains(path, ident) {
|
||||
return n.(*ast.CallExpr)
|
||||
}
|
||||
return false
|
||||
|
||||
/*
|
||||
// Try direct resolution
|
||||
if c.Contains(selector, ident) {
|
||||
log.Printf("c.Contains == true, %s, %s.", selector, ident)
|
||||
return n.(*ast.CallExpr)
|
||||
}
|
||||
*/
|
||||
|
||||
return nil
|
||||
}
|
254
tools/vendor/github.com/GoASTScanner/gas/cmd/gas/main.go
generated
vendored
Normal file
254
tools/vendor/github.com/GoASTScanner/gas/cmd/gas/main.go
generated
vendored
Normal file
@@ -0,0 +1,254 @@
|
||||
// (c) Copyright 2016 Hewlett Packard Enterprise Development LP
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/GoASTScanner/gas"
|
||||
"github.com/GoASTScanner/gas/output"
|
||||
"github.com/GoASTScanner/gas/rules"
|
||||
"github.com/kisielk/gotool"
|
||||
)
|
||||
|
||||
const (
|
||||
usageText = `
|
||||
GAS - Go AST Scanner
|
||||
|
||||
Gas analyzes Go source code to look for common programming mistakes that
|
||||
can lead to security problems.
|
||||
|
||||
USAGE:
|
||||
|
||||
# Check a single package
|
||||
$ gas $GOPATH/src/github.com/example/project
|
||||
|
||||
# Check all packages under the current directory and save results in
|
||||
# json format.
|
||||
$ gas -fmt=json -out=results.json ./...
|
||||
|
||||
# Run a specific set of rules (by default all rules will be run):
|
||||
$ gas -include=G101,G203,G401 ./...
|
||||
|
||||
# Run all rules except the provided
|
||||
$ gas -exclude=G101 $GOPATH/src/github.com/example/project/...
|
||||
|
||||
`
|
||||
)
|
||||
|
||||
var (
|
||||
// #nosec flag
|
||||
flagIgnoreNoSec = flag.Bool("nosec", false, "Ignores #nosec comments when set")
|
||||
|
||||
// format output
|
||||
flagFormat = flag.String("fmt", "text", "Set output format. Valid options are: json, yaml, csv, junit-xml, html, or text")
|
||||
|
||||
// output file
|
||||
flagOutput = flag.String("out", "", "Set output file for results")
|
||||
|
||||
// config file
|
||||
flagConfig = flag.String("conf", "", "Path to optional config file")
|
||||
|
||||
// quiet
|
||||
flagQuiet = flag.Bool("quiet", false, "Only show output when errors are found")
|
||||
|
||||
// rules to explicitly include
|
||||
flagRulesInclude = flag.String("include", "", "Comma separated list of rules IDs to include. (see rule list)")
|
||||
|
||||
// rules to explicitly exclude
|
||||
flagRulesExclude = flag.String("exclude", "", "Comma separated list of rules IDs to exclude. (see rule list)")
|
||||
|
||||
// log to file or stderr
|
||||
flagLogfile = flag.String("log", "", "Log messages to file rather than stderr")
|
||||
|
||||
// sort the issues by severity
|
||||
flagSortIssues = flag.Bool("sort", true, "Sort issues by severity")
|
||||
|
||||
logger *log.Logger
|
||||
)
|
||||
|
||||
// #nosec
|
||||
func usage() {
|
||||
|
||||
fmt.Fprintln(os.Stderr, usageText)
|
||||
fmt.Fprint(os.Stderr, "OPTIONS:\n\n")
|
||||
flag.PrintDefaults()
|
||||
fmt.Fprint(os.Stderr, "\n\nRULES:\n\n")
|
||||
|
||||
// sorted rule list for ease of reading
|
||||
rl := rules.Generate()
|
||||
keys := make([]string, 0, len(rl))
|
||||
for key := range rl {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
for _, k := range keys {
|
||||
v := rl[k]
|
||||
fmt.Fprintf(os.Stderr, "\t%s: %s\n", k, v.Description)
|
||||
}
|
||||
fmt.Fprint(os.Stderr, "\n")
|
||||
}
|
||||
|
||||
func loadConfig(configFile string) (gas.Config, error) {
|
||||
config := gas.NewConfig()
|
||||
if configFile != "" {
|
||||
file, err := os.Open(configFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer file.Close()
|
||||
if _, err := config.ReadFrom(file); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if *flagIgnoreNoSec {
|
||||
config.SetGlobal("nosec", "true")
|
||||
}
|
||||
return config, nil
|
||||
}
|
||||
|
||||
func loadRules(include, exclude string) rules.RuleList {
|
||||
var filters []rules.RuleFilter
|
||||
if include != "" {
|
||||
logger.Printf("including rules: %s", include)
|
||||
including := strings.Split(include, ",")
|
||||
filters = append(filters, rules.NewRuleFilter(false, including...))
|
||||
} else {
|
||||
logger.Println("including rules: default")
|
||||
}
|
||||
|
||||
if exclude != "" {
|
||||
logger.Printf("excluding rules: %s", exclude)
|
||||
excluding := strings.Split(exclude, ",")
|
||||
filters = append(filters, rules.NewRuleFilter(true, excluding...))
|
||||
} else {
|
||||
logger.Println("excluding rules: default")
|
||||
}
|
||||
return rules.Generate(filters...)
|
||||
}
|
||||
|
||||
func saveOutput(filename, format string, issues []*gas.Issue, metrics *gas.Metrics) error {
|
||||
if filename != "" {
|
||||
outfile, err := os.Create(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer outfile.Close()
|
||||
err = output.CreateReport(outfile, format, issues, metrics)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
err := output.CreateReport(os.Stdout, format, issues, metrics)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
// Setup usage description
|
||||
flag.Usage = usage
|
||||
|
||||
// Parse command line arguments
|
||||
flag.Parse()
|
||||
|
||||
// Ensure at least one file was specified
|
||||
if flag.NArg() == 0 {
|
||||
fmt.Fprintf(os.Stderr, "\nError: FILE [FILE...] or './...' expected\n") // #nosec
|
||||
flag.Usage()
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Setup logging
|
||||
logWriter := os.Stderr
|
||||
if *flagLogfile != "" {
|
||||
var e error
|
||||
logWriter, e = os.Create(*flagLogfile)
|
||||
if e != nil {
|
||||
flag.Usage()
|
||||
log.Fatal(e)
|
||||
}
|
||||
}
|
||||
logger = log.New(logWriter, "[gas] ", log.LstdFlags)
|
||||
|
||||
// Load config
|
||||
config, err := loadConfig(*flagConfig)
|
||||
if err != nil {
|
||||
logger.Fatal(err)
|
||||
}
|
||||
|
||||
// Load enabled rule definitions
|
||||
ruleDefinitions := loadRules(*flagRulesInclude, *flagRulesExclude)
|
||||
if len(ruleDefinitions) <= 0 {
|
||||
logger.Fatal("cannot continue: no rules are configured.")
|
||||
}
|
||||
|
||||
// Create the analyzer
|
||||
analyzer := gas.NewAnalyzer(config, logger)
|
||||
analyzer.LoadRules(ruleDefinitions.Builders()...)
|
||||
|
||||
vendor := regexp.MustCompile(`[\\/]vendor([\\/]|$)`)
|
||||
|
||||
var packages []string
|
||||
// Iterate over packages on the import paths
|
||||
for _, pkg := range gotool.ImportPaths(flag.Args()) {
|
||||
|
||||
// Skip vendor directory
|
||||
if vendor.MatchString(pkg) {
|
||||
continue
|
||||
}
|
||||
packages = append(packages, pkg)
|
||||
}
|
||||
|
||||
if err := analyzer.Process(packages...); err != nil {
|
||||
logger.Fatal(err)
|
||||
}
|
||||
|
||||
// Collect the results
|
||||
issues, metrics := analyzer.Report()
|
||||
|
||||
issuesFound := len(issues) > 0
|
||||
// Exit quietly if nothing was found
|
||||
if !issuesFound && *flagQuiet {
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
// Sort the issue by severity
|
||||
if *flagSortIssues {
|
||||
sortIssues(issues)
|
||||
}
|
||||
|
||||
// Create output report
|
||||
if err := saveOutput(*flagOutput, *flagFormat, issues, metrics); err != nil {
|
||||
logger.Fatal(err)
|
||||
}
|
||||
|
||||
// Finialize logging
|
||||
logWriter.Close() // #nosec
|
||||
|
||||
// Do we have an issue? If so exit 1
|
||||
if issuesFound {
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
20
tools/vendor/github.com/GoASTScanner/gas/cmd/gas/sort_issues.go
generated
vendored
Normal file
20
tools/vendor/github.com/GoASTScanner/gas/cmd/gas/sort_issues.go
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"sort"
|
||||
|
||||
"github.com/GoASTScanner/gas"
|
||||
)
|
||||
|
||||
type sortBySeverity []*gas.Issue
|
||||
|
||||
func (s sortBySeverity) Len() int { return len(s) }
|
||||
|
||||
func (s sortBySeverity) Less(i, j int) bool { return s[i].Severity > s[i].Severity }
|
||||
|
||||
func (s sortBySeverity) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||
|
||||
// sortIssues sorts the issues by severity in descending order
|
||||
func sortIssues(issues []*gas.Issue) {
|
||||
sort.Sort(sortBySeverity(issues))
|
||||
}
|
88
tools/vendor/github.com/GoASTScanner/gas/config.go
generated
vendored
Normal file
88
tools/vendor/github.com/GoASTScanner/gas/config.go
generated
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
package gas
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
const (
|
||||
// Globals are applicable to all rules and used for general
|
||||
// configuration settings for gas.
|
||||
Globals = "global"
|
||||
)
|
||||
|
||||
// Config is used to provide configuration and customization to each of the rules.
|
||||
type Config map[string]interface{}
|
||||
|
||||
// NewConfig initializes a new configuration instance. The configuration data then
|
||||
// needs to be loaded via c.ReadFrom(strings.NewReader("config data"))
|
||||
// or from a *os.File.
|
||||
func NewConfig() Config {
|
||||
cfg := make(Config)
|
||||
cfg[Globals] = make(map[string]string)
|
||||
return cfg
|
||||
}
|
||||
|
||||
// ReadFrom implements the io.ReaderFrom interface. This
|
||||
// should be used with io.Reader to load configuration from
|
||||
//file or from string etc.
|
||||
func (c Config) ReadFrom(r io.Reader) (int64, error) {
|
||||
data, err := ioutil.ReadAll(r)
|
||||
if err != nil {
|
||||
return int64(len(data)), err
|
||||
}
|
||||
if err = json.Unmarshal(data, &c); err != nil {
|
||||
return int64(len(data)), err
|
||||
}
|
||||
return int64(len(data)), nil
|
||||
}
|
||||
|
||||
// WriteTo implements the io.WriteTo interface. This should
|
||||
// be used to save or print out the configuration information.
|
||||
func (c Config) WriteTo(w io.Writer) (int64, error) {
|
||||
data, err := json.Marshal(c)
|
||||
if err != nil {
|
||||
return int64(len(data)), err
|
||||
}
|
||||
return io.Copy(w, bytes.NewReader(data))
|
||||
}
|
||||
|
||||
// Get returns the configuration section for the supplied key
|
||||
func (c Config) Get(section string) (interface{}, error) {
|
||||
settings, found := c[section]
|
||||
if !found {
|
||||
return nil, fmt.Errorf("Section %s not in configuration", section)
|
||||
}
|
||||
return settings, nil
|
||||
}
|
||||
|
||||
// Set section in the configuration to specified value
|
||||
func (c Config) Set(section string, value interface{}) {
|
||||
c[section] = value
|
||||
}
|
||||
|
||||
// GetGlobal returns value associated with global configuration option
|
||||
func (c Config) GetGlobal(option string) (string, error) {
|
||||
if globals, ok := c[Globals]; ok {
|
||||
if settings, ok := globals.(map[string]string); ok {
|
||||
if value, ok := settings[option]; ok {
|
||||
return value, nil
|
||||
}
|
||||
return "", fmt.Errorf("global setting for %s not found", option)
|
||||
}
|
||||
}
|
||||
return "", fmt.Errorf("no global config options found")
|
||||
|
||||
}
|
||||
|
||||
// SetGlobal associates a value with a global configuration ooption
|
||||
func (c Config) SetGlobal(option, value string) {
|
||||
if globals, ok := c[Globals]; ok {
|
||||
if settings, ok := globals.(map[string]string); ok {
|
||||
settings[option] = value
|
||||
}
|
||||
}
|
||||
}
|
235
tools/vendor/github.com/GoASTScanner/gas/core/analyzer.go
generated
vendored
235
tools/vendor/github.com/GoASTScanner/gas/core/analyzer.go
generated
vendored
@@ -1,235 +0,0 @@
|
||||
// (c) Copyright 2016 Hewlett Packard Enterprise Development LP
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package core holds the central scanning logic used by GAS
|
||||
package core
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"go/importer"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"go/types"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ImportInfo is used to track aliased and initialization only imports.
|
||||
type ImportInfo struct {
|
||||
Imported map[string]string
|
||||
Aliased map[string]string
|
||||
InitOnly map[string]bool
|
||||
}
|
||||
|
||||
func NewImportInfo() *ImportInfo {
|
||||
return &ImportInfo{
|
||||
make(map[string]string),
|
||||
make(map[string]string),
|
||||
make(map[string]bool),
|
||||
}
|
||||
}
|
||||
|
||||
// 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 encoutered AST node.
|
||||
type Context struct {
|
||||
FileSet *token.FileSet
|
||||
Comments ast.CommentMap
|
||||
Info *types.Info
|
||||
Pkg *types.Package
|
||||
Root *ast.File
|
||||
Config map[string]interface{}
|
||||
Imports *ImportInfo
|
||||
}
|
||||
|
||||
// The Rule interface used by all rules supported by GAS.
|
||||
type Rule interface {
|
||||
Match(ast.Node, *Context) (*Issue, error)
|
||||
}
|
||||
|
||||
// A RuleSet maps lists of rules to the type of AST node they should be run on.
|
||||
// The anaylzer will only invoke rules contained in the list associated with the
|
||||
// type of AST node it is currently visiting.
|
||||
type RuleSet map[reflect.Type][]Rule
|
||||
|
||||
// Metrics used when reporting information about a scanning run.
|
||||
type Metrics struct {
|
||||
NumFiles int `json:"files"`
|
||||
NumLines int `json:"lines"`
|
||||
NumNosec int `json:"nosec"`
|
||||
NumFound int `json:"found"`
|
||||
}
|
||||
|
||||
// The 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.
|
||||
type Analyzer struct {
|
||||
ignoreNosec bool
|
||||
ruleset RuleSet
|
||||
context *Context
|
||||
logger *log.Logger
|
||||
Issues []*Issue `json:"issues"`
|
||||
Stats *Metrics `json:"metrics"`
|
||||
}
|
||||
|
||||
// NewAnalyzer builds a new anaylzer.
|
||||
func NewAnalyzer(conf map[string]interface{}, logger *log.Logger) Analyzer {
|
||||
if logger == nil {
|
||||
logger = log.New(os.Stdout, "[gas]", 0)
|
||||
}
|
||||
a := Analyzer{
|
||||
ignoreNosec: conf["ignoreNosec"].(bool),
|
||||
ruleset: make(RuleSet),
|
||||
context: &Context{nil, nil, nil, nil, nil, nil, nil},
|
||||
logger: logger,
|
||||
Issues: make([]*Issue, 0, 16),
|
||||
Stats: &Metrics{0, 0, 0, 0},
|
||||
}
|
||||
|
||||
// TODO(tkelsey): use the inc/exc lists
|
||||
|
||||
return a
|
||||
}
|
||||
|
||||
func (gas *Analyzer) process(filename string, source interface{}) error {
|
||||
mode := parser.ParseComments
|
||||
gas.context.FileSet = token.NewFileSet()
|
||||
root, err := parser.ParseFile(gas.context.FileSet, filename, source, mode)
|
||||
if err == nil {
|
||||
gas.context.Comments = ast.NewCommentMap(gas.context.FileSet, root, root.Comments)
|
||||
gas.context.Root = root
|
||||
|
||||
// here we get type info
|
||||
gas.context.Info = &types.Info{
|
||||
Types: make(map[ast.Expr]types.TypeAndValue),
|
||||
Defs: make(map[*ast.Ident]types.Object),
|
||||
Uses: make(map[*ast.Ident]types.Object),
|
||||
Selections: make(map[*ast.SelectorExpr]*types.Selection),
|
||||
Scopes: make(map[ast.Node]*types.Scope),
|
||||
Implicits: make(map[ast.Node]types.Object),
|
||||
}
|
||||
|
||||
conf := types.Config{Importer: importer.Default()}
|
||||
gas.context.Pkg, err = conf.Check("pkg", gas.context.FileSet, []*ast.File{root}, gas.context.Info)
|
||||
if err != nil {
|
||||
// TODO(gm) Type checker not currently considering all files within a package
|
||||
// see: issue #113
|
||||
gas.logger.Printf(`Error during type checking: "%s"`, err)
|
||||
err = nil
|
||||
}
|
||||
|
||||
gas.context.Imports = NewImportInfo()
|
||||
for _, pkg := range gas.context.Pkg.Imports() {
|
||||
gas.context.Imports.Imported[pkg.Path()] = pkg.Name()
|
||||
}
|
||||
ast.Walk(gas, root)
|
||||
gas.Stats.NumFiles++
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// AddRule adds a rule into a rule set list mapped to the given AST node's type.
|
||||
// The node is only needed for its type and is not otherwise used.
|
||||
func (gas *Analyzer) AddRule(r Rule, nodes []ast.Node) {
|
||||
for _, n := range nodes {
|
||||
t := reflect.TypeOf(n)
|
||||
if val, ok := gas.ruleset[t]; ok {
|
||||
gas.ruleset[t] = append(val, r)
|
||||
} else {
|
||||
gas.ruleset[t] = []Rule{r}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Process reads in a source file, convert it to an AST and traverse it.
|
||||
// Rule methods added with AddRule will be invoked as necessary.
|
||||
func (gas *Analyzer) Process(filename string) error {
|
||||
err := gas.process(filename, nil)
|
||||
fun := func(f *token.File) bool {
|
||||
gas.Stats.NumLines += f.LineCount()
|
||||
return true
|
||||
}
|
||||
gas.context.FileSet.Iterate(fun)
|
||||
return err
|
||||
}
|
||||
|
||||
// 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.
|
||||
func (gas *Analyzer) ProcessSource(filename string, source string) error {
|
||||
err := gas.process(filename, source)
|
||||
fun := func(f *token.File) bool {
|
||||
gas.Stats.NumLines += f.LineCount()
|
||||
return true
|
||||
}
|
||||
gas.context.FileSet.Iterate(fun)
|
||||
return err
|
||||
}
|
||||
|
||||
// ignore a node (and sub-tree) if it is tagged with a "#nosec" comment
|
||||
func (gas *Analyzer) ignore(n ast.Node) bool {
|
||||
if groups, ok := gas.context.Comments[n]; ok && !gas.ignoreNosec {
|
||||
for _, group := range groups {
|
||||
if strings.Contains(group.Text(), "#nosec") {
|
||||
gas.Stats.NumNosec++
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Visit runs the GAS visitor logic over an AST created by parsing go code.
|
||||
// Rule methods added with AddRule will be invoked as necessary.
|
||||
func (gas *Analyzer) Visit(n ast.Node) ast.Visitor {
|
||||
if !gas.ignore(n) {
|
||||
|
||||
// Track aliased and initialization imports
|
||||
if imported, ok := n.(*ast.ImportSpec); ok {
|
||||
path := strings.Trim(imported.Path.Value, `"`)
|
||||
if imported.Name != nil {
|
||||
if imported.Name.Name == "_" {
|
||||
// Initialization import
|
||||
gas.context.Imports.InitOnly[path] = true
|
||||
} else {
|
||||
// Aliased import
|
||||
gas.context.Imports.Aliased[path] = imported.Name.Name
|
||||
}
|
||||
}
|
||||
// unsafe is not included in Package.Imports()
|
||||
if path == "unsafe" {
|
||||
gas.context.Imports.Imported[path] = path
|
||||
}
|
||||
}
|
||||
|
||||
if val, ok := gas.ruleset[reflect.TypeOf(n)]; ok {
|
||||
for _, rule := range val {
|
||||
ret, err := rule.Match(n, gas.context)
|
||||
if err != nil {
|
||||
file, line := GetLocation(n, gas.context)
|
||||
file = path.Base(file)
|
||||
gas.logger.Printf("Rule error: %v => %s (%s:%d)\n", reflect.TypeOf(rule), err, file, line)
|
||||
}
|
||||
if ret != nil {
|
||||
gas.Issues = append(gas.Issues, ret)
|
||||
gas.Stats.NumFound++
|
||||
}
|
||||
}
|
||||
}
|
||||
return gas
|
||||
}
|
||||
return nil
|
||||
}
|
404
tools/vendor/github.com/GoASTScanner/gas/core/select.go
generated
vendored
404
tools/vendor/github.com/GoASTScanner/gas/core/select.go
generated
vendored
@@ -1,404 +0,0 @@
|
||||
// (c) Copyright 2016 Hewlett Packard Enterprise Development LP
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package core
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// SelectFunc is like an AST visitor, but has a richer interface. It
|
||||
// is called with the current ast.Node being visitied and that nodes depth in
|
||||
// the tree. The function can return true to continue traversing the tree, or
|
||||
// false to end traversal here.
|
||||
type SelectFunc func(ast.Node, int) bool
|
||||
|
||||
func walkIdentList(list []*ast.Ident, depth int, fun SelectFunc) {
|
||||
for _, x := range list {
|
||||
depthWalk(x, depth, fun)
|
||||
}
|
||||
}
|
||||
|
||||
func walkExprList(list []ast.Expr, depth int, fun SelectFunc) {
|
||||
for _, x := range list {
|
||||
depthWalk(x, depth, fun)
|
||||
}
|
||||
}
|
||||
|
||||
func walkStmtList(list []ast.Stmt, depth int, fun SelectFunc) {
|
||||
for _, x := range list {
|
||||
depthWalk(x, depth, fun)
|
||||
}
|
||||
}
|
||||
|
||||
func walkDeclList(list []ast.Decl, depth int, fun SelectFunc) {
|
||||
for _, x := range list {
|
||||
depthWalk(x, depth, fun)
|
||||
}
|
||||
}
|
||||
|
||||
func depthWalk(node ast.Node, depth int, fun SelectFunc) {
|
||||
if !fun(node, depth) {
|
||||
return
|
||||
}
|
||||
|
||||
switch n := node.(type) {
|
||||
// Comments and fields
|
||||
case *ast.Comment:
|
||||
|
||||
case *ast.CommentGroup:
|
||||
for _, c := range n.List {
|
||||
depthWalk(c, depth+1, fun)
|
||||
}
|
||||
|
||||
case *ast.Field:
|
||||
if n.Doc != nil {
|
||||
depthWalk(n.Doc, depth+1, fun)
|
||||
}
|
||||
walkIdentList(n.Names, depth+1, fun)
|
||||
depthWalk(n.Type, depth+1, fun)
|
||||
if n.Tag != nil {
|
||||
depthWalk(n.Tag, depth+1, fun)
|
||||
}
|
||||
if n.Comment != nil {
|
||||
depthWalk(n.Comment, depth+1, fun)
|
||||
}
|
||||
|
||||
case *ast.FieldList:
|
||||
for _, f := range n.List {
|
||||
depthWalk(f, depth+1, fun)
|
||||
}
|
||||
|
||||
// Expressions
|
||||
case *ast.BadExpr, *ast.Ident, *ast.BasicLit:
|
||||
|
||||
case *ast.Ellipsis:
|
||||
if n.Elt != nil {
|
||||
depthWalk(n.Elt, depth+1, fun)
|
||||
}
|
||||
|
||||
case *ast.FuncLit:
|
||||
depthWalk(n.Type, depth+1, fun)
|
||||
depthWalk(n.Body, depth+1, fun)
|
||||
|
||||
case *ast.CompositeLit:
|
||||
if n.Type != nil {
|
||||
depthWalk(n.Type, depth+1, fun)
|
||||
}
|
||||
walkExprList(n.Elts, depth+1, fun)
|
||||
|
||||
case *ast.ParenExpr:
|
||||
depthWalk(n.X, depth+1, fun)
|
||||
|
||||
case *ast.SelectorExpr:
|
||||
depthWalk(n.X, depth+1, fun)
|
||||
depthWalk(n.Sel, depth+1, fun)
|
||||
|
||||
case *ast.IndexExpr:
|
||||
depthWalk(n.X, depth+1, fun)
|
||||
depthWalk(n.Index, depth+1, fun)
|
||||
|
||||
case *ast.SliceExpr:
|
||||
depthWalk(n.X, depth+1, fun)
|
||||
if n.Low != nil {
|
||||
depthWalk(n.Low, depth+1, fun)
|
||||
}
|
||||
if n.High != nil {
|
||||
depthWalk(n.High, depth+1, fun)
|
||||
}
|
||||
if n.Max != nil {
|
||||
depthWalk(n.Max, depth+1, fun)
|
||||
}
|
||||
|
||||
case *ast.TypeAssertExpr:
|
||||
depthWalk(n.X, depth+1, fun)
|
||||
if n.Type != nil {
|
||||
depthWalk(n.Type, depth+1, fun)
|
||||
}
|
||||
|
||||
case *ast.CallExpr:
|
||||
depthWalk(n.Fun, depth+1, fun)
|
||||
walkExprList(n.Args, depth+1, fun)
|
||||
|
||||
case *ast.StarExpr:
|
||||
depthWalk(n.X, depth+1, fun)
|
||||
|
||||
case *ast.UnaryExpr:
|
||||
depthWalk(n.X, depth+1, fun)
|
||||
|
||||
case *ast.BinaryExpr:
|
||||
depthWalk(n.X, depth+1, fun)
|
||||
depthWalk(n.Y, depth+1, fun)
|
||||
|
||||
case *ast.KeyValueExpr:
|
||||
depthWalk(n.Key, depth+1, fun)
|
||||
depthWalk(n.Value, depth+1, fun)
|
||||
|
||||
// Types
|
||||
case *ast.ArrayType:
|
||||
if n.Len != nil {
|
||||
depthWalk(n.Len, depth+1, fun)
|
||||
}
|
||||
depthWalk(n.Elt, depth+1, fun)
|
||||
|
||||
case *ast.StructType:
|
||||
depthWalk(n.Fields, depth+1, fun)
|
||||
|
||||
case *ast.FuncType:
|
||||
if n.Params != nil {
|
||||
depthWalk(n.Params, depth+1, fun)
|
||||
}
|
||||
if n.Results != nil {
|
||||
depthWalk(n.Results, depth+1, fun)
|
||||
}
|
||||
|
||||
case *ast.InterfaceType:
|
||||
depthWalk(n.Methods, depth+1, fun)
|
||||
|
||||
case *ast.MapType:
|
||||
depthWalk(n.Key, depth+1, fun)
|
||||
depthWalk(n.Value, depth+1, fun)
|
||||
|
||||
case *ast.ChanType:
|
||||
depthWalk(n.Value, depth+1, fun)
|
||||
|
||||
// Statements
|
||||
case *ast.BadStmt:
|
||||
|
||||
case *ast.DeclStmt:
|
||||
depthWalk(n.Decl, depth+1, fun)
|
||||
|
||||
case *ast.EmptyStmt:
|
||||
|
||||
case *ast.LabeledStmt:
|
||||
depthWalk(n.Label, depth+1, fun)
|
||||
depthWalk(n.Stmt, depth+1, fun)
|
||||
|
||||
case *ast.ExprStmt:
|
||||
depthWalk(n.X, depth+1, fun)
|
||||
|
||||
case *ast.SendStmt:
|
||||
depthWalk(n.Chan, depth+1, fun)
|
||||
depthWalk(n.Value, depth+1, fun)
|
||||
|
||||
case *ast.IncDecStmt:
|
||||
depthWalk(n.X, depth+1, fun)
|
||||
|
||||
case *ast.AssignStmt:
|
||||
walkExprList(n.Lhs, depth+1, fun)
|
||||
walkExprList(n.Rhs, depth+1, fun)
|
||||
|
||||
case *ast.GoStmt:
|
||||
depthWalk(n.Call, depth+1, fun)
|
||||
|
||||
case *ast.DeferStmt:
|
||||
depthWalk(n.Call, depth+1, fun)
|
||||
|
||||
case *ast.ReturnStmt:
|
||||
walkExprList(n.Results, depth+1, fun)
|
||||
|
||||
case *ast.BranchStmt:
|
||||
if n.Label != nil {
|
||||
depthWalk(n.Label, depth+1, fun)
|
||||
}
|
||||
|
||||
case *ast.BlockStmt:
|
||||
walkStmtList(n.List, depth+1, fun)
|
||||
|
||||
case *ast.IfStmt:
|
||||
if n.Init != nil {
|
||||
depthWalk(n.Init, depth+1, fun)
|
||||
}
|
||||
depthWalk(n.Cond, depth+1, fun)
|
||||
depthWalk(n.Body, depth+1, fun)
|
||||
if n.Else != nil {
|
||||
depthWalk(n.Else, depth+1, fun)
|
||||
}
|
||||
|
||||
case *ast.CaseClause:
|
||||
walkExprList(n.List, depth+1, fun)
|
||||
walkStmtList(n.Body, depth+1, fun)
|
||||
|
||||
case *ast.SwitchStmt:
|
||||
if n.Init != nil {
|
||||
depthWalk(n.Init, depth+1, fun)
|
||||
}
|
||||
if n.Tag != nil {
|
||||
depthWalk(n.Tag, depth+1, fun)
|
||||
}
|
||||
depthWalk(n.Body, depth+1, fun)
|
||||
|
||||
case *ast.TypeSwitchStmt:
|
||||
if n.Init != nil {
|
||||
depthWalk(n.Init, depth+1, fun)
|
||||
}
|
||||
depthWalk(n.Assign, depth+1, fun)
|
||||
depthWalk(n.Body, depth+1, fun)
|
||||
|
||||
case *ast.CommClause:
|
||||
if n.Comm != nil {
|
||||
depthWalk(n.Comm, depth+1, fun)
|
||||
}
|
||||
walkStmtList(n.Body, depth+1, fun)
|
||||
|
||||
case *ast.SelectStmt:
|
||||
depthWalk(n.Body, depth+1, fun)
|
||||
|
||||
case *ast.ForStmt:
|
||||
if n.Init != nil {
|
||||
depthWalk(n.Init, depth+1, fun)
|
||||
}
|
||||
if n.Cond != nil {
|
||||
depthWalk(n.Cond, depth+1, fun)
|
||||
}
|
||||
if n.Post != nil {
|
||||
depthWalk(n.Post, depth+1, fun)
|
||||
}
|
||||
depthWalk(n.Body, depth+1, fun)
|
||||
|
||||
case *ast.RangeStmt:
|
||||
if n.Key != nil {
|
||||
depthWalk(n.Key, depth+1, fun)
|
||||
}
|
||||
if n.Value != nil {
|
||||
depthWalk(n.Value, depth+1, fun)
|
||||
}
|
||||
depthWalk(n.X, depth+1, fun)
|
||||
depthWalk(n.Body, depth+1, fun)
|
||||
|
||||
// Declarations
|
||||
case *ast.ImportSpec:
|
||||
if n.Doc != nil {
|
||||
depthWalk(n.Doc, depth+1, fun)
|
||||
}
|
||||
if n.Name != nil {
|
||||
depthWalk(n.Name, depth+1, fun)
|
||||
}
|
||||
depthWalk(n.Path, depth+1, fun)
|
||||
if n.Comment != nil {
|
||||
depthWalk(n.Comment, depth+1, fun)
|
||||
}
|
||||
|
||||
case *ast.ValueSpec:
|
||||
if n.Doc != nil {
|
||||
depthWalk(n.Doc, depth+1, fun)
|
||||
}
|
||||
walkIdentList(n.Names, depth+1, fun)
|
||||
if n.Type != nil {
|
||||
depthWalk(n.Type, depth+1, fun)
|
||||
}
|
||||
walkExprList(n.Values, depth+1, fun)
|
||||
if n.Comment != nil {
|
||||
depthWalk(n.Comment, depth+1, fun)
|
||||
}
|
||||
|
||||
case *ast.TypeSpec:
|
||||
if n.Doc != nil {
|
||||
depthWalk(n.Doc, depth+1, fun)
|
||||
}
|
||||
depthWalk(n.Name, depth+1, fun)
|
||||
depthWalk(n.Type, depth+1, fun)
|
||||
if n.Comment != nil {
|
||||
depthWalk(n.Comment, depth+1, fun)
|
||||
}
|
||||
|
||||
case *ast.BadDecl:
|
||||
|
||||
case *ast.GenDecl:
|
||||
if n.Doc != nil {
|
||||
depthWalk(n.Doc, depth+1, fun)
|
||||
}
|
||||
for _, s := range n.Specs {
|
||||
depthWalk(s, depth+1, fun)
|
||||
}
|
||||
|
||||
case *ast.FuncDecl:
|
||||
if n.Doc != nil {
|
||||
depthWalk(n.Doc, depth+1, fun)
|
||||
}
|
||||
if n.Recv != nil {
|
||||
depthWalk(n.Recv, depth+1, fun)
|
||||
}
|
||||
depthWalk(n.Name, depth+1, fun)
|
||||
depthWalk(n.Type, depth+1, fun)
|
||||
if n.Body != nil {
|
||||
depthWalk(n.Body, depth+1, fun)
|
||||
}
|
||||
|
||||
// Files and packages
|
||||
case *ast.File:
|
||||
if n.Doc != nil {
|
||||
depthWalk(n.Doc, depth+1, fun)
|
||||
}
|
||||
depthWalk(n.Name, depth+1, fun)
|
||||
walkDeclList(n.Decls, depth+1, fun)
|
||||
// don't walk n.Comments - they have been
|
||||
// visited already through the individual
|
||||
// nodes
|
||||
|
||||
case *ast.Package:
|
||||
for _, f := range n.Files {
|
||||
depthWalk(f, depth+1, fun)
|
||||
}
|
||||
|
||||
default:
|
||||
panic(fmt.Sprintf("gas.depthWalk: unexpected node type %T", n))
|
||||
}
|
||||
}
|
||||
|
||||
type Selector interface {
|
||||
Final(ast.Node)
|
||||
Partial(ast.Node) bool
|
||||
}
|
||||
|
||||
func Select(s Selector, n ast.Node, bits ...reflect.Type) {
|
||||
fun := func(n ast.Node, d int) bool {
|
||||
if d < len(bits) && reflect.TypeOf(n) == bits[d] {
|
||||
if d == len(bits)-1 {
|
||||
s.Final(n)
|
||||
return false
|
||||
} else if s.Partial(n) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
depthWalk(n, 0, fun)
|
||||
}
|
||||
|
||||
// SimpleSelect will try to match a path through a sub-tree starting at a given AST node.
|
||||
// The type of each node in the path at a given depth must match its entry in list of
|
||||
// node types given.
|
||||
func SimpleSelect(n ast.Node, bits ...reflect.Type) ast.Node {
|
||||
var found ast.Node
|
||||
fun := func(n ast.Node, d int) bool {
|
||||
if found != nil {
|
||||
return false // short cut logic if we have found a match
|
||||
}
|
||||
|
||||
if d < len(bits) && reflect.TypeOf(n) == bits[d] {
|
||||
if d == len(bits)-1 {
|
||||
found = n
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
depthWalk(n, 0, fun)
|
||||
return found
|
||||
}
|
@@ -12,41 +12,16 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package core
|
||||
package gas
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/token"
|
||||
"go/types"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// helpfull "canned" matching routines ----------------------------------------
|
||||
|
||||
func selectName(n ast.Node, s reflect.Type) (string, bool) {
|
||||
t := reflect.TypeOf(&ast.SelectorExpr{})
|
||||
if node, ok := SimpleSelect(n, s, t).(*ast.SelectorExpr); ok {
|
||||
t = reflect.TypeOf(&ast.Ident{})
|
||||
if ident, ok := SimpleSelect(node.X, t).(*ast.Ident); ok {
|
||||
return strings.Join([]string{ident.Name, node.Sel.Name}, "."), ok
|
||||
}
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
// MatchCall will match an ast.CallNode if its method name obays the given regex.
|
||||
func MatchCall(n ast.Node, r *regexp.Regexp) *ast.CallExpr {
|
||||
t := reflect.TypeOf(&ast.CallExpr{})
|
||||
if name, ok := selectName(n, t); ok && r.MatchString(name) {
|
||||
return n.(*ast.CallExpr)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MatchCallByPackage ensures that the specified package is imported,
|
||||
// adjusts the name for any aliases and ignores cases that are
|
||||
// initialization only imports.
|
||||
@@ -100,11 +75,13 @@ func MatchCallByType(n ast.Node, ctx *Context, requiredType string, calls ...str
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// MatchCompLit will match an ast.CompositeLit if its string value obays the given regex.
|
||||
func MatchCompLit(n ast.Node, r *regexp.Regexp) *ast.CompositeLit {
|
||||
t := reflect.TypeOf(&ast.CompositeLit{})
|
||||
if name, ok := selectName(n, t); ok && r.MatchString(name) {
|
||||
return n.(*ast.CompositeLit)
|
||||
// MatchCompLit will match an ast.CompositeLit based on the supplied type
|
||||
func MatchCompLit(n ast.Node, ctx *Context, required string) *ast.CompositeLit {
|
||||
if complit, ok := n.(*ast.CompositeLit); ok {
|
||||
typeOf := ctx.Info.TypeOf(complit)
|
||||
if typeOf.String() == required {
|
||||
return complit
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -117,7 +94,7 @@ func GetInt(n ast.Node) (int64, error) {
|
||||
return 0, fmt.Errorf("Unexpected AST node type: %T", n)
|
||||
}
|
||||
|
||||
// GetInt will read and return a float value from an ast.BasicLit
|
||||
// GetFloat will read and return a float value from an ast.BasicLit
|
||||
func GetFloat(n ast.Node) (float64, error) {
|
||||
if node, ok := n.(*ast.BasicLit); ok && node.Kind == token.FLOAT {
|
||||
return strconv.ParseFloat(node.Value, 64)
|
||||
@@ -125,7 +102,7 @@ func GetFloat(n ast.Node) (float64, error) {
|
||||
return 0.0, fmt.Errorf("Unexpected AST node type: %T", n)
|
||||
}
|
||||
|
||||
// GetInt will read and return a char value from an ast.BasicLit
|
||||
// GetChar will read and return a char value from an ast.BasicLit
|
||||
func GetChar(n ast.Node) (byte, error) {
|
||||
if node, ok := n.(*ast.BasicLit); ok && node.Kind == token.CHAR {
|
||||
return node.Value[0], nil
|
||||
@@ -133,7 +110,7 @@ func GetChar(n ast.Node) (byte, error) {
|
||||
return 0, fmt.Errorf("Unexpected AST node type: %T", n)
|
||||
}
|
||||
|
||||
// GetInt will read and return a string value from an ast.BasicLit
|
||||
// GetString will read and return a string value from an ast.BasicLit
|
||||
func GetString(n ast.Node) (string, error) {
|
||||
if node, ok := n.(*ast.BasicLit); ok && node.Kind == token.STRING {
|
||||
return strconv.Unquote(node.Value)
|
||||
@@ -170,12 +147,10 @@ func GetCallInfo(n ast.Node, ctx *Context) (string, string, error) {
|
||||
t := ctx.Info.TypeOf(expr)
|
||||
if t != nil {
|
||||
return t.String(), fn.Sel.Name, nil
|
||||
} else {
|
||||
return "undefined", fn.Sel.Name, fmt.Errorf("missing type info")
|
||||
}
|
||||
} else {
|
||||
return expr.Name, fn.Sel.Name, nil
|
||||
return "undefined", fn.Sel.Name, fmt.Errorf("missing type info")
|
||||
}
|
||||
return expr.Name, fn.Sel.Name, nil
|
||||
}
|
||||
case *ast.Ident:
|
||||
return ctx.Pkg.Name(), fn.Name, nil
|
||||
@@ -205,7 +180,7 @@ func GetImportedName(path string, ctx *Context) (string, bool) {
|
||||
// GetImportPath resolves the full import path of an identifer based on
|
||||
// the imports in the current context.
|
||||
func GetImportPath(name string, ctx *Context) (string, bool) {
|
||||
for path, _ := range ctx.Imports.Imported {
|
||||
for path := range ctx.Imports.Imported {
|
||||
if imported, ok := GetImportedName(path, ctx); ok && imported == name {
|
||||
return path, true
|
||||
}
|
67
tools/vendor/github.com/GoASTScanner/gas/import_tracker.go
generated
vendored
Normal file
67
tools/vendor/github.com/GoASTScanner/gas/import_tracker.go
generated
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package gas
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"go/types"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ImportTracker is used to normalize the packages that have been imported
|
||||
// by a source file. It is able to differentiate between plain imports, aliased
|
||||
// imports and init only imports.
|
||||
type ImportTracker struct {
|
||||
Imported map[string]string
|
||||
Aliased map[string]string
|
||||
InitOnly map[string]bool
|
||||
}
|
||||
|
||||
// NewImportTracker creates an empty Import tracker instance
|
||||
func NewImportTracker() *ImportTracker {
|
||||
return &ImportTracker{
|
||||
make(map[string]string),
|
||||
make(map[string]string),
|
||||
make(map[string]bool),
|
||||
}
|
||||
}
|
||||
|
||||
// TrackPackages tracks all the imports used by the supplied packages
|
||||
func (t *ImportTracker) TrackPackages(pkgs ...*types.Package) {
|
||||
for _, pkg := range pkgs {
|
||||
t.Imported[pkg.Path()] = pkg.Name()
|
||||
// Transient imports
|
||||
//for _, imp := range pkg.Imports() {
|
||||
// t.Imported[imp.Path()] = imp.Name()
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
// TrackImport tracks imports and handles the 'unsafe' import
|
||||
func (t *ImportTracker) TrackImport(n ast.Node) {
|
||||
if imported, ok := n.(*ast.ImportSpec); ok {
|
||||
path := strings.Trim(imported.Path.Value, `"`)
|
||||
if imported.Name != nil {
|
||||
if imported.Name.Name == "_" {
|
||||
// Initialization only import
|
||||
t.InitOnly[path] = true
|
||||
} else {
|
||||
// Aliased import
|
||||
t.Aliased[path] = imported.Name.Name
|
||||
}
|
||||
}
|
||||
if path == "unsafe" {
|
||||
t.Imported[path] = path
|
||||
}
|
||||
}
|
||||
}
|
@@ -11,32 +11,37 @@
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
package core
|
||||
|
||||
package gas
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"os"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Score type used by severity and confidence values
|
||||
type Score int
|
||||
|
||||
const (
|
||||
Low Score = iota // Low value
|
||||
Medium // Medium value
|
||||
High // High value
|
||||
// Low severity or confidence
|
||||
Low Score = iota
|
||||
// Medium severity or confidence
|
||||
Medium
|
||||
// High severity or confidence
|
||||
High
|
||||
)
|
||||
|
||||
// An Issue is returnd by a GAS rule if it discovers an issue with the scanned code.
|
||||
// Issue is returnd by a GAS rule if it discovers an issue with the scanned code.
|
||||
type Issue struct {
|
||||
Severity Score `json:"severity"` // issue severity (how problematic it is)
|
||||
Confidence Score `json:"confidence"` // issue confidence (how sure we are we found it)
|
||||
What string `json:"details"` // Human readable explanation
|
||||
File string `json:"file"` // File name we found it in
|
||||
Code string `json:"code"` // Impacted code line
|
||||
Line int `json:"line"` // Line number in file
|
||||
Line string `json:"line"` // Line number in file
|
||||
}
|
||||
|
||||
// MetaData is embedded in all GAS rules. The Severity, Confidence and What message
|
||||
@@ -71,7 +76,7 @@ func codeSnippet(file *os.File, start int64, end int64, n ast.Node) (string, err
|
||||
}
|
||||
|
||||
size := (int)(end - start) // Go bug, os.File.Read should return int64 ...
|
||||
file.Seek(start, 0)
|
||||
file.Seek(start, 0) // #nosec
|
||||
|
||||
buf := make([]byte, size)
|
||||
if nread, err := file.Read(buf); err != nil || nread != size {
|
||||
@@ -85,7 +90,12 @@ func NewIssue(ctx *Context, node ast.Node, desc string, severity Score, confiden
|
||||
var code string
|
||||
fobj := ctx.FileSet.File(node.Pos())
|
||||
name := fobj.Name()
|
||||
line := fobj.Line(node.Pos())
|
||||
|
||||
start, end := fobj.Line(node.Pos()), fobj.Line(node.End())
|
||||
line := strconv.Itoa(start)
|
||||
if start != end {
|
||||
line = fmt.Sprintf("%d-%d", start, end)
|
||||
}
|
||||
|
||||
if file, err := os.Open(fobj.Name()); err == nil {
|
||||
defer file.Close()
|
293
tools/vendor/github.com/GoASTScanner/gas/main.go
generated
vendored
293
tools/vendor/github.com/GoASTScanner/gas/main.go
generated
vendored
@@ -1,293 +0,0 @@
|
||||
// (c) Copyright 2016 Hewlett Packard Enterprise Development LP
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
gas "github.com/GoASTScanner/gas/core"
|
||||
"github.com/GoASTScanner/gas/output"
|
||||
)
|
||||
|
||||
type recursion bool
|
||||
|
||||
const (
|
||||
recurse recursion = true
|
||||
noRecurse recursion = false
|
||||
)
|
||||
|
||||
var (
|
||||
// #nosec flag
|
||||
flagIgnoreNoSec = flag.Bool("nosec", false, "Ignores #nosec comments when set")
|
||||
|
||||
// format output
|
||||
flagFormat = flag.String("fmt", "text", "Set output format. Valid options are: json, csv, html, or text")
|
||||
|
||||
// output file
|
||||
flagOutput = flag.String("out", "", "Set output file for results")
|
||||
|
||||
// config file
|
||||
flagConfig = flag.String("conf", "", "Path to optional config file")
|
||||
|
||||
// quiet
|
||||
flagQuiet = flag.Bool("quiet", false, "Only show output when errors are found")
|
||||
|
||||
usageText = `
|
||||
GAS - Go AST Scanner
|
||||
|
||||
Gas analyzes Go source code to look for common programming mistakes that
|
||||
can lead to security problems.
|
||||
|
||||
USAGE:
|
||||
|
||||
# Check a single Go file
|
||||
$ gas example.go
|
||||
|
||||
# Check all files under the current directory and save results in
|
||||
# json format.
|
||||
$ gas -fmt=json -out=results.json ./...
|
||||
|
||||
# Run a specific set of rules (by default all rules will be run):
|
||||
$ gas -include=G101,G203,G401 ./...
|
||||
|
||||
# Run all rules except the provided
|
||||
$ gas -exclude=G101 ./...
|
||||
|
||||
`
|
||||
|
||||
logger *log.Logger
|
||||
)
|
||||
|
||||
func extendConfList(conf map[string]interface{}, name string, inputStr string) {
|
||||
if inputStr == "" {
|
||||
conf[name] = []string{}
|
||||
} else {
|
||||
input := strings.Split(inputStr, ",")
|
||||
if val, ok := conf[name]; ok {
|
||||
if data, ok := val.(*[]string); ok {
|
||||
conf[name] = append(*data, input...)
|
||||
} else {
|
||||
logger.Fatal("Config item must be a string list: ", name)
|
||||
}
|
||||
} else {
|
||||
conf[name] = input
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func buildConfig(incRules string, excRules string) map[string]interface{} {
|
||||
config := make(map[string]interface{})
|
||||
if flagConfig != nil && *flagConfig != "" { // parse config if we have one
|
||||
if data, err := ioutil.ReadFile(*flagConfig); err == nil {
|
||||
if err := json.Unmarshal(data, &(config)); err != nil {
|
||||
logger.Fatal("Could not parse JSON config: ", *flagConfig, ": ", err)
|
||||
}
|
||||
} else {
|
||||
logger.Fatal("Could not read config file: ", *flagConfig)
|
||||
}
|
||||
}
|
||||
|
||||
// add in CLI include and exclude data
|
||||
extendConfList(config, "include", incRules)
|
||||
extendConfList(config, "exclude", excRules)
|
||||
|
||||
// override ignoreNosec if given on CLI
|
||||
if flagIgnoreNoSec != nil {
|
||||
config["ignoreNosec"] = *flagIgnoreNoSec
|
||||
} else {
|
||||
val, ok := config["ignoreNosec"]
|
||||
if !ok {
|
||||
config["ignoreNosec"] = false
|
||||
} else if _, ok := val.(bool); !ok {
|
||||
logger.Fatal("Config value must be a bool: 'ignoreNosec'")
|
||||
}
|
||||
}
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
// #nosec
|
||||
func usage() {
|
||||
|
||||
fmt.Fprintln(os.Stderr, usageText)
|
||||
fmt.Fprint(os.Stderr, "OPTIONS:\n\n")
|
||||
flag.PrintDefaults()
|
||||
fmt.Fprint(os.Stderr, "\n\nRULES:\n\n")
|
||||
|
||||
// sorted rule list for eas of reading
|
||||
rl := GetFullRuleList()
|
||||
keys := make([]string, 0, len(rl))
|
||||
for key := range rl {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
for _, k := range keys {
|
||||
v := rl[k]
|
||||
fmt.Fprintf(os.Stderr, "\t%s: %s\n", k, v.description)
|
||||
}
|
||||
fmt.Fprint(os.Stderr, "\n")
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
// Setup usage description
|
||||
flag.Usage = usage
|
||||
|
||||
// Exclude files
|
||||
excluded := newFileList("*_test.go")
|
||||
flag.Var(excluded, "skip", "File pattern to exclude from scan. Uses simple * globs and requires full or partial match")
|
||||
|
||||
incRules := ""
|
||||
flag.StringVar(&incRules, "include", "", "Comma separated list of rules IDs to include. (see rule list)")
|
||||
|
||||
excRules := ""
|
||||
flag.StringVar(&excRules, "exclude", "", "Comma separated list of rules IDs to exclude. (see rule list)")
|
||||
|
||||
// Custom commands / utilities to run instead of default analyzer
|
||||
tools := newUtils()
|
||||
flag.Var(tools, "tool", "GAS utilities to assist with rule development")
|
||||
|
||||
// Setup logging
|
||||
logger = log.New(os.Stderr, "[gas] ", log.LstdFlags)
|
||||
|
||||
// Parse command line arguments
|
||||
flag.Parse()
|
||||
|
||||
// Ensure at least one file was specified
|
||||
if flag.NArg() == 0 {
|
||||
|
||||
fmt.Fprintf(os.Stderr, "\nError: FILE [FILE...] or './...' expected\n")
|
||||
flag.Usage()
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Run utils instead of analysis
|
||||
if len(tools.call) > 0 {
|
||||
tools.run(flag.Args()...)
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
// Setup analyzer
|
||||
config := buildConfig(incRules, excRules)
|
||||
analyzer := gas.NewAnalyzer(config, logger)
|
||||
AddRules(&analyzer, config)
|
||||
|
||||
toAnalyze := getFilesToAnalyze(flag.Args(), excluded)
|
||||
|
||||
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.`)
|
||||
}
|
||||
}
|
||||
|
||||
issuesFound := len(analyzer.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)
|
||||
}
|
||||
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)
|
||||
}
|
||||
} else {
|
||||
toAnalyze = listFiles(path, noRecurse, excluded)
|
||||
}
|
||||
}
|
||||
}
|
||||
//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)
|
||||
}
|
||||
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)
|
||||
}
|
74
tools/vendor/github.com/GoASTScanner/gas/output/formatter.go
generated
vendored
74
tools/vendor/github.com/GoASTScanner/gas/output/formatter.go
generated
vendored
@@ -17,21 +17,30 @@ package output
|
||||
import (
|
||||
"encoding/csv"
|
||||
"encoding/json"
|
||||
"encoding/xml"
|
||||
htmlTemplate "html/template"
|
||||
"io"
|
||||
"strconv"
|
||||
plainTemplate "text/template"
|
||||
|
||||
gas "github.com/GoASTScanner/gas/core"
|
||||
"github.com/GoASTScanner/gas"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
// The output format for reported issues
|
||||
// ReportFormat enumrates the output format for reported issues
|
||||
type ReportFormat int
|
||||
|
||||
const (
|
||||
// ReportText is the default format that writes to stdout
|
||||
ReportText ReportFormat = iota // Plain text format
|
||||
ReportJSON // Json format
|
||||
ReportCSV // CSV format
|
||||
|
||||
// ReportJSON set the output format to json
|
||||
ReportJSON // Json format
|
||||
|
||||
// ReportCSV set the output format to csv
|
||||
ReportCSV // CSV format
|
||||
|
||||
// ReportJUnitXML set the output format to junit xml
|
||||
ReportJUnitXML // JUnit XML format
|
||||
)
|
||||
|
||||
var text = `Results:
|
||||
@@ -48,13 +57,28 @@ Summary:
|
||||
|
||||
`
|
||||
|
||||
func CreateReport(w io.Writer, format string, data *gas.Analyzer) error {
|
||||
type reportInfo struct {
|
||||
Issues []*gas.Issue
|
||||
Stats *gas.Metrics
|
||||
}
|
||||
|
||||
// CreateReport generates a report based for the supplied issues and metrics given
|
||||
// the specified format. The formats currently accepted are: json, csv, html and text.
|
||||
func CreateReport(w io.Writer, format string, issues []*gas.Issue, metrics *gas.Metrics) error {
|
||||
data := &reportInfo{
|
||||
Issues: issues,
|
||||
Stats: metrics,
|
||||
}
|
||||
var err error
|
||||
switch format {
|
||||
case "json":
|
||||
err = reportJSON(w, data)
|
||||
case "yaml":
|
||||
err = reportYAML(w, data)
|
||||
case "csv":
|
||||
err = reportCSV(w, data)
|
||||
case "junit-xml":
|
||||
err = reportJUnitXML(w, data)
|
||||
case "html":
|
||||
err = reportFromHTMLTemplate(w, html, data)
|
||||
case "text":
|
||||
@@ -65,7 +89,7 @@ func CreateReport(w io.Writer, format string, data *gas.Analyzer) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func reportJSON(w io.Writer, data *gas.Analyzer) error {
|
||||
func reportJSON(w io.Writer, data *reportInfo) error {
|
||||
raw, err := json.MarshalIndent(data, "", "\t")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@@ -78,13 +102,22 @@ func reportJSON(w io.Writer, data *gas.Analyzer) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func reportCSV(w io.Writer, data *gas.Analyzer) error {
|
||||
func reportYAML(w io.Writer, data *reportInfo) error {
|
||||
raw, err := yaml.Marshal(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = w.Write(raw)
|
||||
return err
|
||||
}
|
||||
|
||||
func reportCSV(w io.Writer, data *reportInfo) error {
|
||||
out := csv.NewWriter(w)
|
||||
defer out.Flush()
|
||||
for _, issue := range data.Issues {
|
||||
err := out.Write([]string{
|
||||
issue.File,
|
||||
strconv.Itoa(issue.Line),
|
||||
issue.Line,
|
||||
issue.What,
|
||||
issue.Severity.String(),
|
||||
issue.Confidence.String(),
|
||||
@@ -97,7 +130,26 @@ func reportCSV(w io.Writer, data *gas.Analyzer) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func reportFromPlaintextTemplate(w io.Writer, reportTemplate string, data *gas.Analyzer) error {
|
||||
func reportJUnitXML(w io.Writer, data *reportInfo) error {
|
||||
groupedData := groupDataByRules(data)
|
||||
junitXMLStruct := createJUnitXMLStruct(groupedData)
|
||||
|
||||
raw, err := xml.MarshalIndent(junitXMLStruct, "", "\t")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
xmlHeader := []byte("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
|
||||
raw = append(xmlHeader, raw...)
|
||||
_, err = w.Write(raw)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func reportFromPlaintextTemplate(w io.Writer, reportTemplate string, data *reportInfo) error {
|
||||
t, e := plainTemplate.New("gas").Parse(reportTemplate)
|
||||
if e != nil {
|
||||
return e
|
||||
@@ -106,7 +158,7 @@ func reportFromPlaintextTemplate(w io.Writer, reportTemplate string, data *gas.A
|
||||
return t.Execute(w, data)
|
||||
}
|
||||
|
||||
func reportFromHTMLTemplate(w io.Writer, reportTemplate string, data *gas.Analyzer) error {
|
||||
func reportFromHTMLTemplate(w io.Writer, reportTemplate string, data *reportInfo) error {
|
||||
t, e := htmlTemplate.New("gas").Parse(reportTemplate)
|
||||
if e != nil {
|
||||
return e
|
||||
|
74
tools/vendor/github.com/GoASTScanner/gas/output/junit_xml_format.go
generated
vendored
Normal file
74
tools/vendor/github.com/GoASTScanner/gas/output/junit_xml_format.go
generated
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
package output
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
htmlLib "html"
|
||||
"strconv"
|
||||
|
||||
"github.com/GoASTScanner/gas"
|
||||
)
|
||||
|
||||
type junitXMLReport struct {
|
||||
XMLName xml.Name `xml:"testsuites"`
|
||||
Testsuites []testsuite `xml:"testsuite"`
|
||||
}
|
||||
|
||||
type testsuite struct {
|
||||
XMLName xml.Name `xml:"testsuite"`
|
||||
Name string `xml:"name,attr"`
|
||||
Tests int `xml:"tests,attr"`
|
||||
Testcases []testcase `xml:"testcase"`
|
||||
}
|
||||
|
||||
type testcase struct {
|
||||
XMLName xml.Name `xml:"testcase"`
|
||||
Name string `xml:"name,attr"`
|
||||
Failure failure `xml:"failure"`
|
||||
}
|
||||
|
||||
type failure struct {
|
||||
XMLName xml.Name `xml:"failure"`
|
||||
Message string `xml:"message,attr"`
|
||||
Text string `xml:",innerxml"`
|
||||
}
|
||||
|
||||
func generatePlaintext(issue *gas.Issue) string {
|
||||
return "Results:\n" +
|
||||
"[" + issue.File + ":" + issue.Line + "] - " +
|
||||
issue.What + " (Confidence: " + strconv.Itoa(int(issue.Confidence)) +
|
||||
", Severity: " + strconv.Itoa(int(issue.Severity)) + ")\n" + "> " + htmlLib.EscapeString(issue.Code)
|
||||
}
|
||||
|
||||
func groupDataByRules(data *reportInfo) map[string][]*gas.Issue {
|
||||
groupedData := make(map[string][]*gas.Issue)
|
||||
for _, issue := range data.Issues {
|
||||
if _, ok := groupedData[issue.What]; ok {
|
||||
groupedData[issue.What] = append(groupedData[issue.What], issue)
|
||||
} else {
|
||||
groupedData[issue.What] = []*gas.Issue{issue}
|
||||
}
|
||||
}
|
||||
return groupedData
|
||||
}
|
||||
|
||||
func createJUnitXMLStruct(groupedData map[string][]*gas.Issue) junitXMLReport {
|
||||
var xmlReport junitXMLReport
|
||||
for what, issues := range groupedData {
|
||||
testsuite := testsuite{
|
||||
Name: what,
|
||||
Tests: len(issues),
|
||||
}
|
||||
for _, issue := range issues {
|
||||
testcase := testcase{
|
||||
Name: issue.File,
|
||||
Failure: failure{
|
||||
Message: "Found 1 vulnerability. See stacktrace for details.",
|
||||
Text: generatePlaintext(issue),
|
||||
},
|
||||
}
|
||||
testsuite.Testcases = append(testsuite.Testcases, testcase)
|
||||
}
|
||||
xmlReport.Testsuites = append(xmlReport.Testsuites, testsuite)
|
||||
}
|
||||
return xmlReport
|
||||
}
|
@@ -12,11 +12,12 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package core
|
||||
package gas
|
||||
|
||||
import "go/ast"
|
||||
|
||||
func resolveIdent(n *ast.Ident, c *Context) bool {
|
||||
|
||||
if n.Obj == nil || n.Obj.Kind != ast.Var {
|
||||
return true
|
||||
}
|
58
tools/vendor/github.com/GoASTScanner/gas/rule.go
generated
vendored
Normal file
58
tools/vendor/github.com/GoASTScanner/gas/rule.go
generated
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package gas
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// The Rule interface used by all rules supported by GAS.
|
||||
type Rule interface {
|
||||
Match(ast.Node, *Context) (*Issue, error)
|
||||
}
|
||||
|
||||
// RuleBuilder is used to register a rule definition with the analyzer
|
||||
type RuleBuilder func(c Config) (Rule, []ast.Node)
|
||||
|
||||
// A RuleSet maps lists of rules to the type of AST node they should be run on.
|
||||
// The anaylzer will only invoke rules contained in the list associated with the
|
||||
// type of AST node it is currently visiting.
|
||||
type RuleSet map[reflect.Type][]Rule
|
||||
|
||||
// NewRuleSet constructs a new RuleSet
|
||||
func NewRuleSet() RuleSet {
|
||||
return make(RuleSet)
|
||||
}
|
||||
|
||||
// Register adds a trigger for the supplied rule for the the
|
||||
// specified ast nodes.
|
||||
func (r RuleSet) Register(rule Rule, nodes ...ast.Node) {
|
||||
for _, n := range nodes {
|
||||
t := reflect.TypeOf(n)
|
||||
if rules, ok := r[t]; ok {
|
||||
r[t] = append(rules, rule)
|
||||
} else {
|
||||
r[t] = []Rule{rule}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// RegisteredFor will return all rules that are registered for a
|
||||
// specified ast node.
|
||||
func (r RuleSet) RegisteredFor(n ast.Node) []Rule {
|
||||
if rules, found := r[reflect.TypeOf(n)]; found {
|
||||
return rules
|
||||
}
|
||||
return []Rule{}
|
||||
}
|
91
tools/vendor/github.com/GoASTScanner/gas/rulelist.go
generated
vendored
91
tools/vendor/github.com/GoASTScanner/gas/rulelist.go
generated
vendored
@@ -1,91 +0,0 @@
|
||||
// (c) Copyright 2016 Hewlett Packard Enterprise Development LP
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
|
||||
gas "github.com/GoASTScanner/gas/core"
|
||||
"github.com/GoASTScanner/gas/rules"
|
||||
)
|
||||
|
||||
type RuleInfo struct {
|
||||
description string
|
||||
build func(map[string]interface{}) (gas.Rule, []ast.Node)
|
||||
}
|
||||
|
||||
// GetFullRuleList get the full list of all rules available to GAS
|
||||
func GetFullRuleList() map[string]RuleInfo {
|
||||
return map[string]RuleInfo{
|
||||
// misc
|
||||
"G101": RuleInfo{"Look for hardcoded credentials", rules.NewHardcodedCredentials},
|
||||
"G102": RuleInfo{"Bind to all interfaces", rules.NewBindsToAllNetworkInterfaces},
|
||||
"G103": RuleInfo{"Audit the use of unsafe block", rules.NewUsingUnsafe},
|
||||
"G104": RuleInfo{"Audit errors not checked", rules.NewNoErrorCheck},
|
||||
"G105": RuleInfo{"Audit the use of big.Exp function", rules.NewUsingBigExp},
|
||||
|
||||
// injection
|
||||
"G201": RuleInfo{"SQL query construction using format string", rules.NewSqlStrFormat},
|
||||
"G202": RuleInfo{"SQL query construction using string concatenation", rules.NewSqlStrConcat},
|
||||
"G203": RuleInfo{"Use of unescaped data in HTML templates", rules.NewTemplateCheck},
|
||||
"G204": RuleInfo{"Audit use of command execution", rules.NewSubproc},
|
||||
|
||||
// filesystem
|
||||
"G301": RuleInfo{"Poor file permissions used when creating a directory", rules.NewMkdirPerms},
|
||||
"G302": RuleInfo{"Poor file permisions used when creation file or using chmod", rules.NewFilePerms},
|
||||
"G303": RuleInfo{"Creating tempfile using a predictable path", rules.NewBadTempFile},
|
||||
|
||||
// crypto
|
||||
"G401": RuleInfo{"Detect the usage of DES, RC4, or MD5", rules.NewUsesWeakCryptography},
|
||||
"G402": RuleInfo{"Look for bad TLS connection settings", rules.NewIntermediateTlsCheck},
|
||||
"G403": RuleInfo{"Ensure minimum RSA key length of 2048 bits", rules.NewWeakKeyStrength},
|
||||
"G404": RuleInfo{"Insecure random number source (rand)", rules.NewWeakRandCheck},
|
||||
|
||||
// blacklist
|
||||
"G501": RuleInfo{"Import blacklist: crypto/md5", rules.NewBlacklist_crypto_md5},
|
||||
"G502": RuleInfo{"Import blacklist: crypto/des", rules.NewBlacklist_crypto_des},
|
||||
"G503": RuleInfo{"Import blacklist: crypto/rc4", rules.NewBlacklist_crypto_rc4},
|
||||
"G504": RuleInfo{"Import blacklist: net/http/cgi", rules.NewBlacklist_net_http_cgi},
|
||||
}
|
||||
}
|
||||
|
||||
func AddRules(analyzer *gas.Analyzer, conf map[string]interface{}) {
|
||||
var all map[string]RuleInfo
|
||||
|
||||
inc := conf["include"].([]string)
|
||||
exc := conf["exclude"].([]string)
|
||||
|
||||
// add included rules
|
||||
if len(inc) == 0 {
|
||||
all = GetFullRuleList()
|
||||
} else {
|
||||
all = map[string]RuleInfo{}
|
||||
tmp := GetFullRuleList()
|
||||
for _, v := range inc {
|
||||
if val, ok := tmp[v]; ok {
|
||||
all[v] = val
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// remove excluded rules
|
||||
for _, v := range exc {
|
||||
delete(all, v)
|
||||
}
|
||||
|
||||
for _, v := range all {
|
||||
analyzer.AddRule(v.build(conf))
|
||||
}
|
||||
}
|
13
tools/vendor/github.com/GoASTScanner/gas/rules/big.go
generated
vendored
13
tools/vendor/github.com/GoASTScanner/gas/rules/big.go
generated
vendored
@@ -15,24 +15,27 @@
|
||||
package rules
|
||||
|
||||
import (
|
||||
gas "github.com/GoASTScanner/gas/core"
|
||||
"go/ast"
|
||||
|
||||
"github.com/GoASTScanner/gas"
|
||||
)
|
||||
|
||||
type UsingBigExp struct {
|
||||
type usingBigExp struct {
|
||||
gas.MetaData
|
||||
pkg string
|
||||
calls []string
|
||||
}
|
||||
|
||||
func (r *UsingBigExp) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err error) {
|
||||
func (r *usingBigExp) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err error) {
|
||||
if _, matched := gas.MatchCallByType(n, c, r.pkg, r.calls...); matched {
|
||||
return gas.NewIssue(c, n, r.What, r.Severity, r.Confidence), nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
func NewUsingBigExp(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||
return &UsingBigExp{
|
||||
|
||||
// NewUsingBigExp detects issues with modulus == 0 for Bignum
|
||||
func NewUsingBigExp(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
return &usingBigExp{
|
||||
pkg: "*math/big.Int",
|
||||
calls: []string{"Exp"},
|
||||
MetaData: gas.MetaData{
|
||||
|
33
tools/vendor/github.com/GoASTScanner/gas/rules/bind.go
generated
vendored
33
tools/vendor/github.com/GoASTScanner/gas/rules/bind.go
generated
vendored
@@ -18,30 +18,37 @@ import (
|
||||
"go/ast"
|
||||
"regexp"
|
||||
|
||||
gas "github.com/GoASTScanner/gas/core"
|
||||
"github.com/GoASTScanner/gas"
|
||||
)
|
||||
|
||||
// Looks for net.Listen("0.0.0.0") or net.Listen(":8080")
|
||||
type BindsToAllNetworkInterfaces struct {
|
||||
type bindsToAllNetworkInterfaces struct {
|
||||
gas.MetaData
|
||||
call *regexp.Regexp
|
||||
calls gas.CallList
|
||||
pattern *regexp.Regexp
|
||||
}
|
||||
|
||||
func (r *BindsToAllNetworkInterfaces) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err error) {
|
||||
if node := gas.MatchCall(n, r.call); node != nil {
|
||||
if arg, err := gas.GetString(node.Args[1]); err == nil {
|
||||
if r.pattern.MatchString(arg) {
|
||||
return gas.NewIssue(c, n, r.What, r.Severity, r.Confidence), nil
|
||||
}
|
||||
func (r *bindsToAllNetworkInterfaces) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
|
||||
callExpr := r.calls.ContainsCallExpr(n, c)
|
||||
if callExpr == nil {
|
||||
return nil, nil
|
||||
}
|
||||
if arg, err := gas.GetString(callExpr.Args[1]); err == nil {
|
||||
if r.pattern.MatchString(arg) {
|
||||
return gas.NewIssue(c, n, r.What, r.Severity, r.Confidence), nil
|
||||
}
|
||||
}
|
||||
return
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func NewBindsToAllNetworkInterfaces(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||
return &BindsToAllNetworkInterfaces{
|
||||
call: regexp.MustCompile(`^(net|tls)\.Listen$`),
|
||||
// NewBindsToAllNetworkInterfaces detects socket connections that are setup to
|
||||
// listen on all network interfaces.
|
||||
func NewBindsToAllNetworkInterfaces(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
calls := gas.NewCallList()
|
||||
calls.Add("net", "Listen")
|
||||
calls.Add("crypto/tls", "Listen")
|
||||
return &bindsToAllNetworkInterfaces{
|
||||
calls: calls,
|
||||
pattern: regexp.MustCompile(`^(0.0.0.0|:).*$`),
|
||||
MetaData: gas.MetaData{
|
||||
Severity: gas.Medium,
|
||||
|
79
tools/vendor/github.com/GoASTScanner/gas/rules/blacklist.go
generated
vendored
79
tools/vendor/github.com/GoASTScanner/gas/rules/blacklist.go
generated
vendored
@@ -16,64 +16,67 @@ package rules
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"strings"
|
||||
|
||||
gas "github.com/GoASTScanner/gas/core"
|
||||
"github.com/GoASTScanner/gas"
|
||||
)
|
||||
|
||||
type BlacklistImport struct {
|
||||
type blacklistedImport struct {
|
||||
gas.MetaData
|
||||
Path string
|
||||
Blacklisted map[string]string
|
||||
}
|
||||
|
||||
func (r *BlacklistImport) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err error) {
|
||||
func unquote(original string) string {
|
||||
copy := strings.TrimSpace(original)
|
||||
copy = strings.TrimLeft(copy, `"`)
|
||||
return strings.TrimRight(copy, `"`)
|
||||
}
|
||||
|
||||
func (r *blacklistedImport) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
|
||||
if node, ok := n.(*ast.ImportSpec); ok {
|
||||
if r.Path == node.Path.Value && node.Name.String() != "_" {
|
||||
return gas.NewIssue(c, n, r.What, r.Severity, r.Confidence), nil
|
||||
if description, ok := r.Blacklisted[unquote(node.Path.Value)]; ok {
|
||||
return gas.NewIssue(c, node, description, r.Severity, r.Confidence), nil
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func NewBlacklist_crypto_md5(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||
return &BlacklistImport{
|
||||
// NewBlacklistedImports reports when a blacklisted import is being used.
|
||||
// Typically when a deprecated technology is being used.
|
||||
func NewBlacklistedImports(conf gas.Config, blacklist map[string]string) (gas.Rule, []ast.Node) {
|
||||
return &blacklistedImport{
|
||||
MetaData: gas.MetaData{
|
||||
Severity: gas.High,
|
||||
Severity: gas.Medium,
|
||||
Confidence: gas.High,
|
||||
What: "Use of weak cryptographic primitive",
|
||||
},
|
||||
Path: `"crypto/md5"`,
|
||||
Blacklisted: blacklist,
|
||||
}, []ast.Node{(*ast.ImportSpec)(nil)}
|
||||
}
|
||||
|
||||
func NewBlacklist_crypto_des(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||
return &BlacklistImport{
|
||||
MetaData: gas.MetaData{
|
||||
Severity: gas.High,
|
||||
Confidence: gas.High,
|
||||
What: "Use of weak cryptographic primitive",
|
||||
},
|
||||
Path: `"crypto/des"`,
|
||||
}, []ast.Node{(*ast.ImportSpec)(nil)}
|
||||
// NewBlacklistedImportMD5 fails if MD5 is imported
|
||||
func NewBlacklistedImportMD5(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
return NewBlacklistedImports(conf, map[string]string{
|
||||
"crypto/md5": "Blacklisted import crypto/md5: weak cryptographic primitive",
|
||||
})
|
||||
}
|
||||
|
||||
func NewBlacklist_crypto_rc4(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||
return &BlacklistImport{
|
||||
MetaData: gas.MetaData{
|
||||
Severity: gas.High,
|
||||
Confidence: gas.High,
|
||||
What: "Use of weak cryptographic primitive",
|
||||
},
|
||||
Path: `"crypto/rc4"`,
|
||||
}, []ast.Node{(*ast.ImportSpec)(nil)}
|
||||
// NewBlacklistedImportDES fails if DES is imported
|
||||
func NewBlacklistedImportDES(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
return NewBlacklistedImports(conf, map[string]string{
|
||||
"crypto/des": "Blacklisted import crypto/des: weak cryptographic primitive",
|
||||
})
|
||||
}
|
||||
|
||||
func NewBlacklist_net_http_cgi(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||
return &BlacklistImport{
|
||||
MetaData: gas.MetaData{
|
||||
Severity: gas.High,
|
||||
Confidence: gas.High,
|
||||
What: "Go versions < 1.6.3 are vulnerable to Httpoxy attack: (CVE-2016-5386)",
|
||||
},
|
||||
Path: `"net/http/cgi"`,
|
||||
}, []ast.Node{(*ast.ImportSpec)(nil)}
|
||||
// NewBlacklistedImportRC4 fails if DES is imported
|
||||
func NewBlacklistedImportRC4(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
return NewBlacklistedImports(conf, map[string]string{
|
||||
"crypto/rc4": "Blacklisted import crypto/rc4: weak cryptographic primitive",
|
||||
})
|
||||
}
|
||||
|
||||
// NewBlacklistedImportCGI fails if CGI is imported
|
||||
func NewBlacklistedImportCGI(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
return NewBlacklistedImports(conf, map[string]string{
|
||||
"net/http/cgi": "Blacklisted import net/http/cgi: Go versions < 1.6.3 are vulnerable to Httpoxy attack: (CVE-2016-5386)",
|
||||
})
|
||||
}
|
||||
|
20
tools/vendor/github.com/GoASTScanner/gas/rules/errors.go
generated
vendored
20
tools/vendor/github.com/GoASTScanner/gas/rules/errors.go
generated
vendored
@@ -15,12 +15,13 @@
|
||||
package rules
|
||||
|
||||
import (
|
||||
gas "github.com/GoASTScanner/gas/core"
|
||||
"go/ast"
|
||||
"go/types"
|
||||
|
||||
"github.com/GoASTScanner/gas"
|
||||
)
|
||||
|
||||
type NoErrorCheck struct {
|
||||
type noErrorCheck struct {
|
||||
gas.MetaData
|
||||
whitelist gas.CallList
|
||||
}
|
||||
@@ -29,7 +30,7 @@ func returnsError(callExpr *ast.CallExpr, ctx *gas.Context) int {
|
||||
if tv := ctx.Info.TypeOf(callExpr); tv != nil {
|
||||
switch t := tv.(type) {
|
||||
case *types.Tuple:
|
||||
for pos := 0; pos < t.Len(); pos += 1 {
|
||||
for pos := 0; pos < t.Len(); pos++ {
|
||||
variable := t.At(pos)
|
||||
if variable != nil && variable.Type().String() == "error" {
|
||||
return pos
|
||||
@@ -44,11 +45,11 @@ func returnsError(callExpr *ast.CallExpr, ctx *gas.Context) int {
|
||||
return -1
|
||||
}
|
||||
|
||||
func (r *NoErrorCheck) Match(n ast.Node, ctx *gas.Context) (*gas.Issue, error) {
|
||||
func (r *noErrorCheck) Match(n ast.Node, ctx *gas.Context) (*gas.Issue, error) {
|
||||
switch stmt := n.(type) {
|
||||
case *ast.AssignStmt:
|
||||
for _, expr := range stmt.Rhs {
|
||||
if callExpr, ok := expr.(*ast.CallExpr); ok && !r.whitelist.ContainsCallExpr(callExpr, ctx) {
|
||||
if callExpr, ok := expr.(*ast.CallExpr); ok && r.whitelist.ContainsCallExpr(expr, ctx) == nil {
|
||||
pos := returnsError(callExpr, ctx)
|
||||
if pos < 0 || pos >= len(stmt.Lhs) {
|
||||
return nil, nil
|
||||
@@ -59,7 +60,7 @@ func (r *NoErrorCheck) Match(n ast.Node, ctx *gas.Context) (*gas.Issue, error) {
|
||||
}
|
||||
}
|
||||
case *ast.ExprStmt:
|
||||
if callExpr, ok := stmt.X.(*ast.CallExpr); ok && !r.whitelist.ContainsCallExpr(callExpr, ctx) {
|
||||
if callExpr, ok := stmt.X.(*ast.CallExpr); ok && r.whitelist.ContainsCallExpr(stmt.X, ctx) == nil {
|
||||
pos := returnsError(callExpr, ctx)
|
||||
if pos >= 0 {
|
||||
return gas.NewIssue(ctx, n, r.What, r.Severity, r.Confidence), nil
|
||||
@@ -69,13 +70,14 @@ func (r *NoErrorCheck) Match(n ast.Node, ctx *gas.Context) (*gas.Issue, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func NewNoErrorCheck(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||
// NewNoErrorCheck detects if the returned error is unchecked
|
||||
func NewNoErrorCheck(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
|
||||
// TODO(gm) Come up with sensible defaults here. Or flip it to use a
|
||||
// black list instead.
|
||||
whitelist := gas.NewCallList()
|
||||
whitelist.AddAll("bytes.Buffer", "Write", "WriteByte", "WriteRune", "WriteString")
|
||||
whitelist.AddAll("fmt", "Print", "Printf", "Println")
|
||||
whitelist.AddAll("fmt", "Print", "Printf", "Println", "Fprint", "Fprintf", "Fprintln")
|
||||
whitelist.Add("io.PipeWriter", "CloseWithError")
|
||||
|
||||
if configured, ok := conf["G104"]; ok {
|
||||
@@ -85,7 +87,7 @@ func NewNoErrorCheck(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||
}
|
||||
}
|
||||
}
|
||||
return &NoErrorCheck{
|
||||
return &noErrorCheck{
|
||||
MetaData: gas.MetaData{
|
||||
Severity: gas.Low,
|
||||
Confidence: gas.High,
|
||||
|
22
tools/vendor/github.com/GoASTScanner/gas/rules/fileperms.go
generated
vendored
22
tools/vendor/github.com/GoASTScanner/gas/rules/fileperms.go
generated
vendored
@@ -19,10 +19,10 @@ import (
|
||||
"go/ast"
|
||||
"strconv"
|
||||
|
||||
gas "github.com/GoASTScanner/gas/core"
|
||||
"github.com/GoASTScanner/gas"
|
||||
)
|
||||
|
||||
type FilePermissions struct {
|
||||
type filePermissions struct {
|
||||
gas.MetaData
|
||||
mode int64
|
||||
pkg string
|
||||
@@ -30,7 +30,7 @@ type FilePermissions struct {
|
||||
}
|
||||
|
||||
func getConfiguredMode(conf map[string]interface{}, configKey string, defaultMode int64) int64 {
|
||||
var mode int64 = defaultMode
|
||||
var mode = defaultMode
|
||||
if value, ok := conf[configKey]; ok {
|
||||
switch value.(type) {
|
||||
case int64:
|
||||
@@ -46,7 +46,7 @@ func getConfiguredMode(conf map[string]interface{}, configKey string, defaultMod
|
||||
return mode
|
||||
}
|
||||
|
||||
func (r *FilePermissions) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
|
||||
func (r *filePermissions) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
|
||||
if callexpr, matched := gas.MatchCallByPackage(n, c, r.pkg, r.calls...); matched {
|
||||
modeArg := callexpr.Args[len(callexpr.Args)-1]
|
||||
if mode, err := gas.GetInt(modeArg); err == nil && mode > r.mode {
|
||||
@@ -56,9 +56,11 @@ func (r *FilePermissions) Match(n ast.Node, c *gas.Context) (*gas.Issue, error)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func NewFilePerms(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||
// NewFilePerms creates a rule to detect file creation with a more permissive than configured
|
||||
// permission mask.
|
||||
func NewFilePerms(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
mode := getConfiguredMode(conf, "G302", 0600)
|
||||
return &FilePermissions{
|
||||
return &filePermissions{
|
||||
mode: mode,
|
||||
pkg: "os",
|
||||
calls: []string{"OpenFile", "Chmod"},
|
||||
@@ -70,9 +72,11 @@ func NewFilePerms(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||
}, []ast.Node{(*ast.CallExpr)(nil)}
|
||||
}
|
||||
|
||||
func NewMkdirPerms(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||
mode := getConfiguredMode(conf, "G301", 0700)
|
||||
return &FilePermissions{
|
||||
// NewMkdirPerms creates a rule to detect directory creation with more permissive than
|
||||
// configured permission mask.
|
||||
func NewMkdirPerms(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
mode := getConfiguredMode(conf, "G301", 0750)
|
||||
return &filePermissions{
|
||||
mode: mode,
|
||||
pkg: "os",
|
||||
calls: []string{"Mkdir", "MkdirAll"},
|
||||
|
24
tools/vendor/github.com/GoASTScanner/gas/rules/hardcoded_credentials.go
generated
vendored
24
tools/vendor/github.com/GoASTScanner/gas/rules/hardcoded_credentials.go
generated
vendored
@@ -15,16 +15,16 @@
|
||||
package rules
|
||||
|
||||
import (
|
||||
gas "github.com/GoASTScanner/gas/core"
|
||||
"go/ast"
|
||||
"go/token"
|
||||
"regexp"
|
||||
|
||||
"github.com/nbutton23/zxcvbn-go"
|
||||
"strconv"
|
||||
|
||||
"github.com/GoASTScanner/gas"
|
||||
"github.com/nbutton23/zxcvbn-go"
|
||||
)
|
||||
|
||||
type Credentials struct {
|
||||
type credentials struct {
|
||||
gas.MetaData
|
||||
pattern *regexp.Regexp
|
||||
entropyThreshold float64
|
||||
@@ -40,7 +40,7 @@ func truncate(s string, n int) string {
|
||||
return s[:n]
|
||||
}
|
||||
|
||||
func (r *Credentials) isHighEntropyString(str string) bool {
|
||||
func (r *credentials) isHighEntropyString(str string) bool {
|
||||
s := truncate(str, r.truncate)
|
||||
info := zxcvbn.PasswordStrength(s, []string{})
|
||||
entropyPerChar := info.Entropy / float64(len(s))
|
||||
@@ -49,7 +49,7 @@ func (r *Credentials) isHighEntropyString(str string) bool {
|
||||
entropyPerChar >= r.perCharThreshold))
|
||||
}
|
||||
|
||||
func (r *Credentials) Match(n ast.Node, ctx *gas.Context) (*gas.Issue, error) {
|
||||
func (r *credentials) Match(n ast.Node, ctx *gas.Context) (*gas.Issue, error) {
|
||||
switch node := n.(type) {
|
||||
case *ast.AssignStmt:
|
||||
return r.matchAssign(node, ctx)
|
||||
@@ -59,7 +59,7 @@ func (r *Credentials) Match(n ast.Node, ctx *gas.Context) (*gas.Issue, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (r *Credentials) matchAssign(assign *ast.AssignStmt, ctx *gas.Context) (*gas.Issue, error) {
|
||||
func (r *credentials) matchAssign(assign *ast.AssignStmt, ctx *gas.Context) (*gas.Issue, error) {
|
||||
for _, i := range assign.Lhs {
|
||||
if ident, ok := i.(*ast.Ident); ok {
|
||||
if r.pattern.MatchString(ident.Name) {
|
||||
@@ -76,7 +76,7 @@ func (r *Credentials) matchAssign(assign *ast.AssignStmt, ctx *gas.Context) (*ga
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (r *Credentials) matchGenDecl(decl *ast.GenDecl, ctx *gas.Context) (*gas.Issue, error) {
|
||||
func (r *credentials) matchGenDecl(decl *ast.GenDecl, ctx *gas.Context) (*gas.Issue, error) {
|
||||
if decl.Tok != token.CONST && decl.Tok != token.VAR {
|
||||
return nil, nil
|
||||
}
|
||||
@@ -100,12 +100,14 @@ func (r *Credentials) matchGenDecl(decl *ast.GenDecl, ctx *gas.Context) (*gas.Is
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func NewHardcodedCredentials(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||
// NewHardcodedCredentials attempts to find high entropy string constants being
|
||||
// assigned to variables that appear to be related to credentials.
|
||||
func NewHardcodedCredentials(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
pattern := `(?i)passwd|pass|password|pwd|secret|token`
|
||||
entropyThreshold := 80.0
|
||||
perCharThreshold := 3.0
|
||||
ignoreEntropy := false
|
||||
var truncateString int = 16
|
||||
var truncateString = 16
|
||||
if val, ok := conf["G101"]; ok {
|
||||
conf := val.(map[string]string)
|
||||
if configPattern, ok := conf["pattern"]; ok {
|
||||
@@ -133,7 +135,7 @@ func NewHardcodedCredentials(conf map[string]interface{}) (gas.Rule, []ast.Node)
|
||||
}
|
||||
}
|
||||
|
||||
return &Credentials{
|
||||
return &credentials{
|
||||
pattern: regexp.MustCompile(pattern),
|
||||
entropyThreshold: entropyThreshold,
|
||||
perCharThreshold: perCharThreshold,
|
||||
|
11
tools/vendor/github.com/GoASTScanner/gas/rules/rand.go
generated
vendored
11
tools/vendor/github.com/GoASTScanner/gas/rules/rand.go
generated
vendored
@@ -17,16 +17,16 @@ package rules
|
||||
import (
|
||||
"go/ast"
|
||||
|
||||
gas "github.com/GoASTScanner/gas/core"
|
||||
"github.com/GoASTScanner/gas"
|
||||
)
|
||||
|
||||
type WeakRand struct {
|
||||
type weakRand struct {
|
||||
gas.MetaData
|
||||
funcNames []string
|
||||
packagePath string
|
||||
}
|
||||
|
||||
func (w *WeakRand) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
|
||||
func (w *weakRand) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
|
||||
for _, funcName := range w.funcNames {
|
||||
if _, matched := gas.MatchCallByPackage(n, c, w.packagePath, funcName); matched {
|
||||
return gas.NewIssue(c, n, w.What, w.Severity, w.Confidence), nil
|
||||
@@ -36,8 +36,9 @@ func (w *WeakRand) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func NewWeakRandCheck(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||
return &WeakRand{
|
||||
// NewWeakRandCheck detects the use of random number generator that isn't cryptographically secure
|
||||
func NewWeakRandCheck(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
return &weakRand{
|
||||
funcNames: []string{"Read", "Int"},
|
||||
packagePath: "math/rand",
|
||||
MetaData: gas.MetaData{
|
||||
|
26
tools/vendor/github.com/GoASTScanner/gas/rules/rsa.go
generated
vendored
26
tools/vendor/github.com/GoASTScanner/gas/rules/rsa.go
generated
vendored
@@ -17,31 +17,33 @@ package rules
|
||||
import (
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"regexp"
|
||||
|
||||
gas "github.com/GoASTScanner/gas/core"
|
||||
"github.com/GoASTScanner/gas"
|
||||
)
|
||||
|
||||
type WeakKeyStrength struct {
|
||||
type weakKeyStrength struct {
|
||||
gas.MetaData
|
||||
pattern *regexp.Regexp
|
||||
bits int
|
||||
calls gas.CallList
|
||||
bits int
|
||||
}
|
||||
|
||||
func (w *WeakKeyStrength) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
|
||||
if node := gas.MatchCall(n, w.pattern); node != nil {
|
||||
if bits, err := gas.GetInt(node.Args[1]); err == nil && bits < (int64)(w.bits) {
|
||||
func (w *weakKeyStrength) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
|
||||
if callExpr := w.calls.ContainsCallExpr(n, c); callExpr != nil {
|
||||
if bits, err := gas.GetInt(callExpr.Args[1]); err == nil && bits < (int64)(w.bits) {
|
||||
return gas.NewIssue(c, n, w.What, w.Severity, w.Confidence), nil
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func NewWeakKeyStrength(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||
// NewWeakKeyStrength builds a rule that detects RSA keys < 2048 bits
|
||||
func NewWeakKeyStrength(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
calls := gas.NewCallList()
|
||||
calls.Add("crypto/rsa", "GenerateKey")
|
||||
bits := 2048
|
||||
return &WeakKeyStrength{
|
||||
pattern: regexp.MustCompile(`^rsa\.GenerateKey$`),
|
||||
bits: bits,
|
||||
return &weakKeyStrength{
|
||||
calls: calls,
|
||||
bits: bits,
|
||||
MetaData: gas.MetaData{
|
||||
Severity: gas.Medium,
|
||||
Confidence: gas.High,
|
||||
|
102
tools/vendor/github.com/GoASTScanner/gas/rules/rulelist.go
generated
vendored
Normal file
102
tools/vendor/github.com/GoASTScanner/gas/rules/rulelist.go
generated
vendored
Normal file
@@ -0,0 +1,102 @@
|
||||
// (c) Copyright 2016 Hewlett Packard Enterprise Development LP
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package rules
|
||||
|
||||
import (
|
||||
"github.com/GoASTScanner/gas"
|
||||
)
|
||||
|
||||
// RuleDefinition contains the description of a rule and a mechanism to
|
||||
// create it.
|
||||
type RuleDefinition struct {
|
||||
Description string
|
||||
Create gas.RuleBuilder
|
||||
}
|
||||
|
||||
// RuleList is a mapping of rule ID's to rule definitions
|
||||
type RuleList map[string]RuleDefinition
|
||||
|
||||
// Builders returns all the create methods for a given rule list
|
||||
func (rl RuleList) Builders() []gas.RuleBuilder {
|
||||
builders := make([]gas.RuleBuilder, 0, len(rl))
|
||||
for _, def := range rl {
|
||||
builders = append(builders, def.Create)
|
||||
}
|
||||
return builders
|
||||
}
|
||||
|
||||
// RuleFilter can be used to include or exclude a rule depending on the return
|
||||
// value of the function
|
||||
type RuleFilter func(string) bool
|
||||
|
||||
// NewRuleFilter is a closure that will include/exclude the rule ID's based on
|
||||
// the supplied boolean value.
|
||||
func NewRuleFilter(action bool, ruleIDs ...string) RuleFilter {
|
||||
rulelist := make(map[string]bool)
|
||||
for _, rule := range ruleIDs {
|
||||
rulelist[rule] = true
|
||||
}
|
||||
return func(rule string) bool {
|
||||
if _, found := rulelist[rule]; found {
|
||||
return action
|
||||
}
|
||||
return !action
|
||||
}
|
||||
}
|
||||
|
||||
// Generate the list of rules to use
|
||||
func Generate(filters ...RuleFilter) RuleList {
|
||||
rules := map[string]RuleDefinition{
|
||||
// misc
|
||||
"G101": {"Look for hardcoded credentials", NewHardcodedCredentials},
|
||||
"G102": {"Bind to all interfaces", NewBindsToAllNetworkInterfaces},
|
||||
"G103": {"Audit the use of unsafe block", NewUsingUnsafe},
|
||||
"G104": {"Audit errors not checked", NewNoErrorCheck},
|
||||
"G105": {"Audit the use of big.Exp function", NewUsingBigExp},
|
||||
"G106": {"Audit the use of ssh.InsecureIgnoreHostKey function", NewSSHHostKey},
|
||||
|
||||
// injection
|
||||
"G201": {"SQL query construction using format string", NewSQLStrFormat},
|
||||
"G202": {"SQL query construction using string concatenation", NewSQLStrConcat},
|
||||
"G203": {"Use of unescaped data in HTML templates", NewTemplateCheck},
|
||||
"G204": {"Audit use of command execution", NewSubproc},
|
||||
|
||||
// filesystem
|
||||
"G301": {"Poor file permissions used when creating a directory", NewMkdirPerms},
|
||||
"G302": {"Poor file permisions used when creation file or using chmod", NewFilePerms},
|
||||
"G303": {"Creating tempfile using a predictable path", NewBadTempFile},
|
||||
|
||||
// crypto
|
||||
"G401": {"Detect the usage of DES, RC4, or MD5", NewUsesWeakCryptography},
|
||||
"G402": {"Look for bad TLS connection settings", NewIntermediateTLSCheck},
|
||||
"G403": {"Ensure minimum RSA key length of 2048 bits", NewWeakKeyStrength},
|
||||
"G404": {"Insecure random number source (rand)", NewWeakRandCheck},
|
||||
|
||||
// blacklist
|
||||
"G501": {"Import blacklist: crypto/md5", NewBlacklistedImportMD5},
|
||||
"G502": {"Import blacklist: crypto/des", NewBlacklistedImportDES},
|
||||
"G503": {"Import blacklist: crypto/rc4", NewBlacklistedImportRC4},
|
||||
"G504": {"Import blacklist: net/http/cgi", NewBlacklistedImportCGI},
|
||||
}
|
||||
|
||||
for rule := range rules {
|
||||
for _, filter := range filters {
|
||||
if filter(rule) {
|
||||
delete(rules, rule)
|
||||
}
|
||||
}
|
||||
}
|
||||
return rules
|
||||
}
|
74
tools/vendor/github.com/GoASTScanner/gas/rules/sql.go
generated
vendored
74
tools/vendor/github.com/GoASTScanner/gas/rules/sql.go
generated
vendored
@@ -18,20 +18,32 @@ import (
|
||||
"go/ast"
|
||||
"regexp"
|
||||
|
||||
gas "github.com/GoASTScanner/gas/core"
|
||||
"github.com/GoASTScanner/gas"
|
||||
)
|
||||
|
||||
type SqlStatement struct {
|
||||
type sqlStatement struct {
|
||||
gas.MetaData
|
||||
pattern *regexp.Regexp
|
||||
|
||||
// Contains a list of patterns which must all match for the rule to match.
|
||||
patterns []*regexp.Regexp
|
||||
}
|
||||
|
||||
type SqlStrConcat struct {
|
||||
SqlStatement
|
||||
// See if the string matches the patterns for the statement.
|
||||
func (s sqlStatement) MatchPatterns(str string) bool {
|
||||
for _, pattern := range s.patterns {
|
||||
if !pattern.MatchString(str) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
type sqlStrConcat struct {
|
||||
sqlStatement
|
||||
}
|
||||
|
||||
// see if we can figure out what it is
|
||||
func (s *SqlStrConcat) checkObject(n *ast.Ident) bool {
|
||||
func (s *sqlStrConcat) checkObject(n *ast.Ident) bool {
|
||||
if n.Obj != nil {
|
||||
return n.Obj.Kind != ast.Var && n.Obj.Kind != ast.Fun
|
||||
}
|
||||
@@ -39,10 +51,13 @@ func (s *SqlStrConcat) checkObject(n *ast.Ident) bool {
|
||||
}
|
||||
|
||||
// Look for "SELECT * FROM table WHERE " + " ' OR 1=1"
|
||||
func (s *SqlStrConcat) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
|
||||
func (s *sqlStrConcat) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
|
||||
if node, ok := n.(*ast.BinaryExpr); ok {
|
||||
if start, ok := node.X.(*ast.BasicLit); ok {
|
||||
if str, e := gas.GetString(start); s.pattern.MatchString(str) && e == nil {
|
||||
if str, e := gas.GetString(start); e == nil {
|
||||
if !s.MatchPatterns(str) {
|
||||
return nil, nil
|
||||
}
|
||||
if _, ok := node.Y.(*ast.BasicLit); ok {
|
||||
return nil, nil // string cat OK
|
||||
}
|
||||
@@ -56,10 +71,13 @@ func (s *SqlStrConcat) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func NewSqlStrConcat(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||
return &SqlStrConcat{
|
||||
SqlStatement: SqlStatement{
|
||||
pattern: regexp.MustCompile(`(?)(SELECT|DELETE|INSERT|UPDATE|INTO|FROM|WHERE) `),
|
||||
// NewSQLStrConcat looks for cases where we are building SQL strings via concatenation
|
||||
func NewSQLStrConcat(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
return &sqlStrConcat{
|
||||
sqlStatement: sqlStatement{
|
||||
patterns: []*regexp.Regexp{
|
||||
regexp.MustCompile(`(?)(SELECT|DELETE|INSERT|UPDATE|INTO|FROM|WHERE) `),
|
||||
},
|
||||
MetaData: gas.MetaData{
|
||||
Severity: gas.Medium,
|
||||
Confidence: gas.High,
|
||||
@@ -69,31 +87,39 @@ func NewSqlStrConcat(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||
}, []ast.Node{(*ast.BinaryExpr)(nil)}
|
||||
}
|
||||
|
||||
type SqlStrFormat struct {
|
||||
SqlStatement
|
||||
call *regexp.Regexp
|
||||
type sqlStrFormat struct {
|
||||
sqlStatement
|
||||
calls gas.CallList
|
||||
}
|
||||
|
||||
// Looks for "fmt.Sprintf("SELECT * FROM foo where '%s', userInput)"
|
||||
func (s *SqlStrFormat) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err error) {
|
||||
if node := gas.MatchCall(n, s.call); node != nil {
|
||||
if arg, e := gas.GetString(node.Args[0]); s.pattern.MatchString(arg) && e == nil {
|
||||
func (s *sqlStrFormat) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
|
||||
|
||||
// TODO(gm) improve confidence if database/sql is being used
|
||||
if node := s.calls.ContainsCallExpr(n, c); node != nil {
|
||||
if arg, e := gas.GetString(node.Args[0]); s.MatchPatterns(arg) && e == nil {
|
||||
return gas.NewIssue(c, n, s.What, s.Severity, s.Confidence), nil
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func NewSqlStrFormat(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||
return &SqlStrFormat{
|
||||
call: regexp.MustCompile(`^fmt\.Sprintf$`),
|
||||
SqlStatement: SqlStatement{
|
||||
pattern: regexp.MustCompile("(?)(SELECT|DELETE|INSERT|UPDATE|INTO|FROM|WHERE) "),
|
||||
// NewSQLStrFormat looks for cases where we're building SQL query strings using format strings
|
||||
func NewSQLStrFormat(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
rule := &sqlStrFormat{
|
||||
calls: gas.NewCallList(),
|
||||
sqlStatement: sqlStatement{
|
||||
patterns: []*regexp.Regexp{
|
||||
regexp.MustCompile("(?)(SELECT|DELETE|INSERT|UPDATE|INTO|FROM|WHERE) "),
|
||||
regexp.MustCompile("%[^bdoxXfFp]"),
|
||||
},
|
||||
MetaData: gas.MetaData{
|
||||
Severity: gas.Medium,
|
||||
Confidence: gas.High,
|
||||
What: "SQL string formatting",
|
||||
},
|
||||
},
|
||||
}, []ast.Node{(*ast.CallExpr)(nil)}
|
||||
}
|
||||
rule.calls.AddAll("fmt", "Sprint", "Sprintf", "Sprintln")
|
||||
return rule, []ast.Node{(*ast.CallExpr)(nil)}
|
||||
}
|
||||
|
33
tools/vendor/github.com/GoASTScanner/gas/rules/ssh.go
generated
vendored
Normal file
33
tools/vendor/github.com/GoASTScanner/gas/rules/ssh.go
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
package rules
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
|
||||
"github.com/GoASTScanner/gas"
|
||||
)
|
||||
|
||||
type sshHostKey struct {
|
||||
gas.MetaData
|
||||
pkg string
|
||||
calls []string
|
||||
}
|
||||
|
||||
func (r *sshHostKey) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err error) {
|
||||
if _, matches := gas.MatchCallByPackage(n, c, r.pkg, r.calls...); matches {
|
||||
return gas.NewIssue(c, n, r.What, r.Severity, r.Confidence), nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// NewSSHHostKey rule detects the use of insecure ssh HostKeyCallback.
|
||||
func NewSSHHostKey(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
return &sshHostKey{
|
||||
pkg: "golang.org/x/crypto/ssh",
|
||||
calls: []string{"InsecureIgnoreHostKey"},
|
||||
MetaData: gas.MetaData{
|
||||
What: "Use of ssh InsecureIgnoreHostKey should be audited",
|
||||
Severity: gas.Medium,
|
||||
Confidence: gas.High,
|
||||
},
|
||||
}, []ast.Node{(*ast.CallExpr)(nil)}
|
||||
}
|
52
tools/vendor/github.com/GoASTScanner/gas/rules/subproc.go
generated
vendored
52
tools/vendor/github.com/GoASTScanner/gas/rules/subproc.go
generated
vendored
@@ -16,41 +16,43 @@ package rules
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"regexp"
|
||||
"strings"
|
||||
"go/types"
|
||||
|
||||
gas "github.com/GoASTScanner/gas/core"
|
||||
"github.com/GoASTScanner/gas"
|
||||
)
|
||||
|
||||
type Subprocess struct {
|
||||
pattern *regexp.Regexp
|
||||
type subprocess struct {
|
||||
gas.CallList
|
||||
}
|
||||
|
||||
func (r *Subprocess) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
|
||||
if node := gas.MatchCall(n, r.pattern); node != nil {
|
||||
// TODO(gm) The only real potential for command injection with a Go project
|
||||
// is something like this:
|
||||
//
|
||||
// syscall.Exec("/bin/sh", []string{"-c", tainted})
|
||||
//
|
||||
// E.g. Input is correctly escaped but the execution context being used
|
||||
// is unsafe. For example:
|
||||
//
|
||||
// syscall.Exec("echo", "foobar" + tainted)
|
||||
func (r *subprocess) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
|
||||
if node := r.ContainsCallExpr(n, c); node != nil {
|
||||
for _, arg := range node.Args {
|
||||
if !gas.TryResolve(arg, c) {
|
||||
what := "Subprocess launching with variable."
|
||||
return gas.NewIssue(c, n, what, gas.High, gas.High), nil
|
||||
if ident, ok := arg.(*ast.Ident); ok {
|
||||
obj := c.Info.ObjectOf(ident)
|
||||
if _, ok := obj.(*types.Var); ok && !gas.TryResolve(ident, c) {
|
||||
return gas.NewIssue(c, n, "Subprocess launched with variable", gas.Medium, gas.High), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// call with partially qualified command
|
||||
if str, err := gas.GetString(node.Args[0]); err == nil {
|
||||
if !strings.HasPrefix(str, "/") {
|
||||
what := "Subprocess launching with partial path."
|
||||
return gas.NewIssue(c, n, what, gas.Medium, gas.High), nil
|
||||
}
|
||||
}
|
||||
|
||||
what := "Subprocess launching should be audited."
|
||||
return gas.NewIssue(c, n, what, gas.Low, gas.High), nil
|
||||
return gas.NewIssue(c, n, "Subprocess launching should be audited", gas.Low, gas.High), nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func NewSubproc(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||
return &Subprocess{
|
||||
pattern: regexp.MustCompile(`^exec\.Command|syscall\.Exec$`),
|
||||
}, []ast.Node{(*ast.CallExpr)(nil)}
|
||||
// NewSubproc detects cases where we are forking out to an external process
|
||||
func NewSubproc(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
rule := &subprocess{gas.NewCallList()}
|
||||
rule.Add("os/exec", "Command")
|
||||
rule.Add("syscall", "Exec")
|
||||
return rule, []ast.Node{(*ast.CallExpr)(nil)}
|
||||
}
|
||||
|
24
tools/vendor/github.com/GoASTScanner/gas/rules/tempfiles.go
generated
vendored
24
tools/vendor/github.com/GoASTScanner/gas/rules/tempfiles.go
generated
vendored
@@ -18,17 +18,17 @@ import (
|
||||
"go/ast"
|
||||
"regexp"
|
||||
|
||||
gas "github.com/GoASTScanner/gas/core"
|
||||
"github.com/GoASTScanner/gas"
|
||||
)
|
||||
|
||||
type BadTempFile struct {
|
||||
type badTempFile struct {
|
||||
gas.MetaData
|
||||
args *regexp.Regexp
|
||||
call *regexp.Regexp
|
||||
calls gas.CallList
|
||||
args *regexp.Regexp
|
||||
}
|
||||
|
||||
func (t *BadTempFile) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err error) {
|
||||
if node := gas.MatchCall(n, t.call); node != nil {
|
||||
func (t *badTempFile) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err error) {
|
||||
if node := t.calls.ContainsCallExpr(n, c); node != nil {
|
||||
if arg, e := gas.GetString(node.Args[0]); t.args.MatchString(arg) && e == nil {
|
||||
return gas.NewIssue(c, n, t.What, t.Severity, t.Confidence), nil
|
||||
}
|
||||
@@ -36,10 +36,14 @@ func (t *BadTempFile) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err erro
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func NewBadTempFile(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||
return &BadTempFile{
|
||||
call: regexp.MustCompile(`ioutil\.WriteFile|os\.Create`),
|
||||
args: regexp.MustCompile(`^/tmp/.*$|^/var/tmp/.*$`),
|
||||
// NewBadTempFile detects direct writes to predictable path in temporary directory
|
||||
func NewBadTempFile(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
calls := gas.NewCallList()
|
||||
calls.Add("io/ioutil", "WriteFile")
|
||||
calls.Add("os", "Create")
|
||||
return &badTempFile{
|
||||
calls: calls,
|
||||
args: regexp.MustCompile(`^/tmp/.*$|^/var/tmp/.*$`),
|
||||
MetaData: gas.MetaData{
|
||||
Severity: gas.Medium,
|
||||
Confidence: gas.High,
|
||||
|
25
tools/vendor/github.com/GoASTScanner/gas/rules/templates.go
generated
vendored
25
tools/vendor/github.com/GoASTScanner/gas/rules/templates.go
generated
vendored
@@ -16,18 +16,17 @@ package rules
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"regexp"
|
||||
|
||||
gas "github.com/GoASTScanner/gas/core"
|
||||
"github.com/GoASTScanner/gas"
|
||||
)
|
||||
|
||||
type TemplateCheck struct {
|
||||
type templateCheck struct {
|
||||
gas.MetaData
|
||||
call *regexp.Regexp
|
||||
calls gas.CallList
|
||||
}
|
||||
|
||||
func (t *TemplateCheck) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err error) {
|
||||
if node := gas.MatchCall(n, t.call); node != nil {
|
||||
func (t *templateCheck) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
|
||||
if node := t.calls.ContainsCallExpr(n, c); node != nil {
|
||||
for _, arg := range node.Args {
|
||||
if _, ok := arg.(*ast.BasicLit); !ok { // basic lits are safe
|
||||
return gas.NewIssue(c, n, t.What, t.Severity, t.Confidence), nil
|
||||
@@ -37,9 +36,17 @@ func (t *TemplateCheck) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err er
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func NewTemplateCheck(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||
return &TemplateCheck{
|
||||
call: regexp.MustCompile(`^template\.(HTML|JS|URL)$`),
|
||||
// NewTemplateCheck constructs the template check rule. This rule is used to
|
||||
// find use of tempaltes where HTML/JS escaping is not being used
|
||||
func NewTemplateCheck(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
|
||||
calls := gas.NewCallList()
|
||||
calls.Add("html/template", "HTML")
|
||||
calls.Add("html/template", "HTMLAttr")
|
||||
calls.Add("html/template", "JS")
|
||||
calls.Add("html/template", "URL")
|
||||
return &templateCheck{
|
||||
calls: calls,
|
||||
MetaData: gas.MetaData{
|
||||
Severity: gas.Medium,
|
||||
Confidence: gas.Low,
|
||||
|
124
tools/vendor/github.com/GoASTScanner/gas/rules/tls.go
generated
vendored
124
tools/vendor/github.com/GoASTScanner/gas/rules/tls.go
generated
vendored
@@ -12,22 +12,22 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//go:generate tlsconfig
|
||||
|
||||
package rules
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"reflect"
|
||||
"regexp"
|
||||
|
||||
gas "github.com/GoASTScanner/gas/core"
|
||||
"github.com/GoASTScanner/gas"
|
||||
)
|
||||
|
||||
type InsecureConfigTLS struct {
|
||||
MinVersion int16
|
||||
MaxVersion int16
|
||||
pattern *regexp.Regexp
|
||||
goodCiphers []string
|
||||
type insecureConfigTLS struct {
|
||||
MinVersion int16
|
||||
MaxVersion int16
|
||||
requiredType string
|
||||
goodCiphers []string
|
||||
}
|
||||
|
||||
func stringInSlice(a string, list []string) bool {
|
||||
@@ -39,15 +39,14 @@ func stringInSlice(a string, list []string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (t *InsecureConfigTLS) processTlsCipherSuites(n ast.Node, c *gas.Context) *gas.Issue {
|
||||
a := reflect.TypeOf(&ast.KeyValueExpr{})
|
||||
b := reflect.TypeOf(&ast.CompositeLit{})
|
||||
if node, ok := gas.SimpleSelect(n, a, b).(*ast.CompositeLit); ok {
|
||||
for _, elt := range node.Elts {
|
||||
if ident, ok := elt.(*ast.SelectorExpr); ok {
|
||||
func (t *insecureConfigTLS) processTLSCipherSuites(n ast.Node, c *gas.Context) *gas.Issue {
|
||||
|
||||
if ciphers, ok := n.(*ast.CompositeLit); ok {
|
||||
for _, cipher := range ciphers.Elts {
|
||||
if ident, ok := cipher.(*ast.SelectorExpr); ok {
|
||||
if !stringInSlice(ident.Sel.Name, t.goodCiphers) {
|
||||
str := fmt.Sprintf("TLS Bad Cipher Suite: %s", ident.Sel.Name)
|
||||
return gas.NewIssue(c, n, str, gas.High, gas.High)
|
||||
err := fmt.Sprintf("TLS Bad Cipher Suite: %s", ident.Sel.Name)
|
||||
return gas.NewIssue(c, ident, err, gas.High, gas.High)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -55,9 +54,10 @@ func (t *InsecureConfigTLS) processTlsCipherSuites(n ast.Node, c *gas.Context) *
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *InsecureConfigTLS) processTlsConfVal(n *ast.KeyValueExpr, c *gas.Context) *gas.Issue {
|
||||
func (t *insecureConfigTLS) processTLSConfVal(n *ast.KeyValueExpr, c *gas.Context) *gas.Issue {
|
||||
if ident, ok := n.Key.(*ast.Ident); ok {
|
||||
switch ident.Name {
|
||||
|
||||
case "InsecureSkipVerify":
|
||||
if node, ok := n.Value.(*ast.Ident); ok {
|
||||
if node.Name != "false" {
|
||||
@@ -97,7 +97,7 @@ func (t *InsecureConfigTLS) processTlsConfVal(n *ast.KeyValueExpr, c *gas.Contex
|
||||
}
|
||||
|
||||
case "CipherSuites":
|
||||
if ret := t.processTlsCipherSuites(n, c); ret != nil {
|
||||
if ret := t.processTLSCipherSuites(n.Value, c); ret != nil {
|
||||
return ret
|
||||
}
|
||||
|
||||
@@ -107,85 +107,19 @@ func (t *InsecureConfigTLS) processTlsConfVal(n *ast.KeyValueExpr, c *gas.Contex
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *InsecureConfigTLS) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err error) {
|
||||
if node := gas.MatchCompLit(n, t.pattern); node != nil {
|
||||
for _, elt := range node.Elts {
|
||||
if kve, ok := elt.(*ast.KeyValueExpr); ok {
|
||||
gi = t.processTlsConfVal(kve, c)
|
||||
if gi != nil {
|
||||
break
|
||||
func (t *insecureConfigTLS) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
|
||||
if complit, ok := n.(*ast.CompositeLit); ok && complit.Type != nil {
|
||||
actualType := c.Info.TypeOf(complit.Type)
|
||||
if actualType != nil && actualType.String() == t.requiredType {
|
||||
for _, elt := range complit.Elts {
|
||||
if kve, ok := elt.(*ast.KeyValueExpr); ok {
|
||||
issue := t.processTLSConfVal(kve, c)
|
||||
if issue != nil {
|
||||
return issue, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func NewModernTlsCheck(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||
// https://wiki.mozilla.org/Security/Server_Side_TLS#Modern_compatibility
|
||||
return &InsecureConfigTLS{
|
||||
pattern: regexp.MustCompile(`^tls\.Config$`),
|
||||
MinVersion: 0x0303, // TLS 1.2 only
|
||||
MaxVersion: 0x0303,
|
||||
goodCiphers: []string{
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
|
||||
},
|
||||
}, []ast.Node{(*ast.CompositeLit)(nil)}
|
||||
}
|
||||
|
||||
func NewIntermediateTlsCheck(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||
// https://wiki.mozilla.org/Security/Server_Side_TLS#Intermediate_compatibility_.28default.29
|
||||
return &InsecureConfigTLS{
|
||||
pattern: regexp.MustCompile(`^tls\.Config$`),
|
||||
MinVersion: 0x0301, // TLS 1.2, 1.1, 1.0
|
||||
MaxVersion: 0x0303,
|
||||
goodCiphers: []string{
|
||||
"TLS_RSA_WITH_AES_128_CBC_SHA",
|
||||
"TLS_RSA_WITH_AES_256_CBC_SHA",
|
||||
"TLS_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_RSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_ECDHE_ECDSA_WITH_RC4_128_SHA",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
|
||||
"TLS_ECDHE_RSA_WITH_RC4_128_SHA",
|
||||
"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
|
||||
},
|
||||
}, []ast.Node{(*ast.CompositeLit)(nil)}
|
||||
}
|
||||
|
||||
func NewCompatTlsCheck(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||
// https://wiki.mozilla.org/Security/Server_Side_TLS#Old_compatibility_.28default.29
|
||||
return &InsecureConfigTLS{
|
||||
pattern: regexp.MustCompile(`^tls\.Config$`),
|
||||
MinVersion: 0x0301, // TLS 1.2, 1.1, 1.0
|
||||
MaxVersion: 0x0303,
|
||||
goodCiphers: []string{
|
||||
"TLS_RSA_WITH_RC4_128_SHA",
|
||||
"TLS_RSA_WITH_3DES_EDE_CBC_SHA",
|
||||
"TLS_RSA_WITH_AES_128_CBC_SHA",
|
||||
"TLS_RSA_WITH_AES_256_CBC_SHA",
|
||||
"TLS_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_RSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_ECDHE_ECDSA_WITH_RC4_128_SHA",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
|
||||
"TLS_ECDHE_RSA_WITH_RC4_128_SHA",
|
||||
"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
|
||||
},
|
||||
}, []ast.Node{(*ast.CompositeLit)(nil)}
|
||||
return nil, nil
|
||||
}
|
||||
|
132
tools/vendor/github.com/GoASTScanner/gas/rules/tls_config.go
generated
vendored
Normal file
132
tools/vendor/github.com/GoASTScanner/gas/rules/tls_config.go
generated
vendored
Normal file
@@ -0,0 +1,132 @@
|
||||
package rules
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
|
||||
"github.com/GoASTScanner/gas"
|
||||
)
|
||||
|
||||
// NewModernTLSCheck creates a check for Modern TLS ciphers
|
||||
// DO NOT EDIT - generated by tlsconfig tool
|
||||
func NewModernTLSCheck(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
return &insecureConfigTLS{
|
||||
requiredType: "crypto/tls.Config",
|
||||
MinVersion: 0x0303,
|
||||
MaxVersion: 0x0303,
|
||||
goodCiphers: []string{
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384",
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
|
||||
},
|
||||
}, []ast.Node{(*ast.CompositeLit)(nil)}
|
||||
}
|
||||
|
||||
// NewIntermediateTLSCheck creates a check for Intermediate TLS ciphers
|
||||
// DO NOT EDIT - generated by tlsconfig tool
|
||||
func NewIntermediateTLSCheck(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
return &insecureConfigTLS{
|
||||
requiredType: "crypto/tls.Config",
|
||||
MinVersion: 0x0301,
|
||||
MaxVersion: 0x0303,
|
||||
goodCiphers: []string{
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_DHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_DHE_RSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
|
||||
"TLS_DHE_RSA_WITH_AES_128_CBC_SHA256",
|
||||
"TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
|
||||
"TLS_DHE_RSA_WITH_AES_256_CBC_SHA256",
|
||||
"TLS_DHE_RSA_WITH_AES_256_CBC_SHA",
|
||||
"TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA",
|
||||
"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
|
||||
"TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA",
|
||||
"TLS_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_RSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_RSA_WITH_AES_128_CBC_SHA256",
|
||||
"TLS_RSA_WITH_AES_256_CBC_SHA256",
|
||||
"TLS_RSA_WITH_AES_128_CBC_SHA",
|
||||
"TLS_RSA_WITH_AES_256_CBC_SHA",
|
||||
"TLS_RSA_WITH_3DES_EDE_CBC_SHA",
|
||||
},
|
||||
}, []ast.Node{(*ast.CompositeLit)(nil)}
|
||||
}
|
||||
|
||||
// NewOldTLSCheck creates a check for Old TLS ciphers
|
||||
// DO NOT EDIT - generated by tlsconfig tool
|
||||
func NewOldTLSCheck(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
return &insecureConfigTLS{
|
||||
requiredType: "crypto/tls.Config",
|
||||
MinVersion: 0x0300,
|
||||
MaxVersion: 0x0303,
|
||||
goodCiphers: []string{
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_DHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_DHE_DSS_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_DHE_DSS_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_DHE_RSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384",
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
|
||||
"TLS_DHE_RSA_WITH_AES_128_CBC_SHA256",
|
||||
"TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
|
||||
"TLS_DHE_DSS_WITH_AES_128_CBC_SHA256",
|
||||
"TLS_DHE_RSA_WITH_AES_256_CBC_SHA256",
|
||||
"TLS_DHE_DSS_WITH_AES_256_CBC_SHA",
|
||||
"TLS_DHE_RSA_WITH_AES_256_CBC_SHA",
|
||||
"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
|
||||
"TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA",
|
||||
"TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA",
|
||||
"TLS_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_RSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_RSA_WITH_AES_128_CBC_SHA256",
|
||||
"TLS_RSA_WITH_AES_256_CBC_SHA256",
|
||||
"TLS_RSA_WITH_AES_128_CBC_SHA",
|
||||
"TLS_RSA_WITH_AES_256_CBC_SHA",
|
||||
"TLS_DHE_DSS_WITH_AES_256_CBC_SHA256",
|
||||
"TLS_DHE_DSS_WITH_AES_128_CBC_SHA",
|
||||
"TLS_RSA_WITH_3DES_EDE_CBC_SHA",
|
||||
"TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384",
|
||||
"TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384",
|
||||
"TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256",
|
||||
"TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256",
|
||||
"TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA",
|
||||
"TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA",
|
||||
"TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256",
|
||||
"TLS_RSA_WITH_CAMELLIA_256_CBC_SHA",
|
||||
"TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256",
|
||||
"TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256",
|
||||
"TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256",
|
||||
"TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256",
|
||||
"TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA",
|
||||
"TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA",
|
||||
"TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256",
|
||||
"TLS_RSA_WITH_CAMELLIA_128_CBC_SHA",
|
||||
"TLS_DHE_RSA_WITH_SEED_CBC_SHA",
|
||||
"TLS_DHE_DSS_WITH_SEED_CBC_SHA",
|
||||
"TLS_RSA_WITH_SEED_CBC_SHA",
|
||||
},
|
||||
}, []ast.Node{(*ast.CompositeLit)(nil)}
|
||||
}
|
13
tools/vendor/github.com/GoASTScanner/gas/rules/unsafe.go
generated
vendored
13
tools/vendor/github.com/GoASTScanner/gas/rules/unsafe.go
generated
vendored
@@ -15,25 +15,28 @@
|
||||
package rules
|
||||
|
||||
import (
|
||||
gas "github.com/GoASTScanner/gas/core"
|
||||
"go/ast"
|
||||
|
||||
"github.com/GoASTScanner/gas"
|
||||
)
|
||||
|
||||
type UsingUnsafe struct {
|
||||
type usingUnsafe struct {
|
||||
gas.MetaData
|
||||
pkg string
|
||||
calls []string
|
||||
}
|
||||
|
||||
func (r *UsingUnsafe) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err error) {
|
||||
func (r *usingUnsafe) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err error) {
|
||||
if _, matches := gas.MatchCallByPackage(n, c, r.pkg, r.calls...); matches {
|
||||
return gas.NewIssue(c, n, r.What, r.Severity, r.Confidence), nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func NewUsingUnsafe(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||
return &UsingUnsafe{
|
||||
// NewUsingUnsafe rule detects the use of the unsafe package. This is only
|
||||
// really useful for auditing purposes.
|
||||
func NewUsingUnsafe(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
return &usingUnsafe{
|
||||
pkg: "unsafe",
|
||||
calls: []string{"Alignof", "Offsetof", "Sizeof", "Pointer"},
|
||||
MetaData: gas.MetaData{
|
||||
|
12
tools/vendor/github.com/GoASTScanner/gas/rules/weakcrypto.go
generated
vendored
12
tools/vendor/github.com/GoASTScanner/gas/rules/weakcrypto.go
generated
vendored
@@ -17,15 +17,15 @@ package rules
|
||||
import (
|
||||
"go/ast"
|
||||
|
||||
gas "github.com/GoASTScanner/gas/core"
|
||||
"github.com/GoASTScanner/gas"
|
||||
)
|
||||
|
||||
type UsesWeakCryptography struct {
|
||||
type usesWeakCryptography struct {
|
||||
gas.MetaData
|
||||
blacklist map[string][]string
|
||||
}
|
||||
|
||||
func (r *UsesWeakCryptography) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
|
||||
func (r *usesWeakCryptography) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) {
|
||||
|
||||
for pkg, funcs := range r.blacklist {
|
||||
if _, matched := gas.MatchCallByPackage(n, c, pkg, funcs...); matched {
|
||||
@@ -35,13 +35,13 @@ func (r *UsesWeakCryptography) Match(n ast.Node, c *gas.Context) (*gas.Issue, er
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Uses des.* md5.* or rc4.*
|
||||
func NewUsesWeakCryptography(conf map[string]interface{}) (gas.Rule, []ast.Node) {
|
||||
// NewUsesWeakCryptography detects uses of des.* md5.* or rc4.*
|
||||
func NewUsesWeakCryptography(conf gas.Config) (gas.Rule, []ast.Node) {
|
||||
calls := make(map[string][]string)
|
||||
calls["crypto/des"] = []string{"NewCipher", "NewTripleDESCipher"}
|
||||
calls["crypto/md5"] = []string{"New", "Sum"}
|
||||
calls["crypto/rc4"] = []string{"NewCipher"}
|
||||
rule := &UsesWeakCryptography{
|
||||
rule := &usesWeakCryptography{
|
||||
blacklist: calls,
|
||||
MetaData: gas.MetaData{
|
||||
Severity: gas.Medium,
|
||||
|
276
tools/vendor/github.com/GoASTScanner/gas/tools.go
generated
vendored
276
tools/vendor/github.com/GoASTScanner/gas/tools.go
generated
vendored
@@ -1,276 +0,0 @@
|
||||
// (c) Copyright 2016 Hewlett Packard Enterprise Development LP
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/importer"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"go/types"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type command func(args ...string)
|
||||
type utilities struct {
|
||||
commands map[string]command
|
||||
call []string
|
||||
}
|
||||
|
||||
// Custom commands / utilities to run instead of default analyzer
|
||||
func newUtils() *utilities {
|
||||
utils := make(map[string]command)
|
||||
utils["ast"] = dumpAst
|
||||
utils["callobj"] = dumpCallObj
|
||||
utils["uses"] = dumpUses
|
||||
utils["types"] = dumpTypes
|
||||
utils["defs"] = dumpDefs
|
||||
utils["comments"] = dumpComments
|
||||
utils["imports"] = dumpImports
|
||||
return &utilities{utils, make([]string, 0)}
|
||||
}
|
||||
|
||||
func (u *utilities) String() string {
|
||||
i := 0
|
||||
keys := make([]string, len(u.commands))
|
||||
for k := range u.commands {
|
||||
keys[i] = k
|
||||
i++
|
||||
}
|
||||
return strings.Join(keys, ", ")
|
||||
}
|
||||
|
||||
func (u *utilities) Set(opt string) error {
|
||||
if _, ok := u.commands[opt]; !ok {
|
||||
return fmt.Errorf("valid tools are: %s", u.String())
|
||||
|
||||
}
|
||||
u.call = append(u.call, opt)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *utilities) run(args ...string) {
|
||||
for _, util := range u.call {
|
||||
if cmd, ok := u.commands[util]; ok {
|
||||
cmd(args...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func shouldSkip(path string) bool {
|
||||
st, e := os.Stat(path)
|
||||
if e != nil {
|
||||
// #nosec
|
||||
fmt.Fprintf(os.Stderr, "Skipping: %s - %s\n", path, e)
|
||||
return true
|
||||
}
|
||||
if st.IsDir() {
|
||||
// #nosec
|
||||
fmt.Fprintf(os.Stderr, "Skipping: %s - directory\n", path)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func dumpAst(files ...string) {
|
||||
for _, arg := range files {
|
||||
// Ensure file exists and not a directory
|
||||
if shouldSkip(arg) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Create the AST by parsing src.
|
||||
fset := token.NewFileSet() // positions are relative to fset
|
||||
f, err := parser.ParseFile(fset, arg, nil, 0)
|
||||
if err != nil {
|
||||
// #nosec
|
||||
fmt.Fprintf(os.Stderr, "Unable to parse file %s\n", err)
|
||||
continue
|
||||
}
|
||||
|
||||
// Print the AST. #nosec
|
||||
ast.Print(fset, f)
|
||||
}
|
||||
}
|
||||
|
||||
type context struct {
|
||||
fileset *token.FileSet
|
||||
comments ast.CommentMap
|
||||
info *types.Info
|
||||
pkg *types.Package
|
||||
config *types.Config
|
||||
root *ast.File
|
||||
}
|
||||
|
||||
func createContext(filename string) *context {
|
||||
fileset := token.NewFileSet()
|
||||
root, e := parser.ParseFile(fileset, filename, nil, parser.ParseComments)
|
||||
if e != nil {
|
||||
// #nosec
|
||||
fmt.Fprintf(os.Stderr, "Unable to parse file: %s. Reason: %s\n", filename, e)
|
||||
return nil
|
||||
}
|
||||
comments := ast.NewCommentMap(fileset, root, root.Comments)
|
||||
info := &types.Info{
|
||||
Types: make(map[ast.Expr]types.TypeAndValue),
|
||||
Defs: make(map[*ast.Ident]types.Object),
|
||||
Uses: make(map[*ast.Ident]types.Object),
|
||||
Selections: make(map[*ast.SelectorExpr]*types.Selection),
|
||||
Scopes: make(map[ast.Node]*types.Scope),
|
||||
Implicits: make(map[ast.Node]types.Object),
|
||||
}
|
||||
config := types.Config{Importer: importer.Default()}
|
||||
pkg, e := config.Check("main.go", fileset, []*ast.File{root}, info)
|
||||
if e != nil {
|
||||
// #nosec
|
||||
fmt.Fprintf(os.Stderr, "Type check failed for file: %s. Reason: %s\n", filename, e)
|
||||
return nil
|
||||
}
|
||||
return &context{fileset, comments, info, pkg, &config, root}
|
||||
}
|
||||
|
||||
func printObject(obj types.Object) {
|
||||
fmt.Println("OBJECT")
|
||||
if obj == nil {
|
||||
fmt.Println("object is nil")
|
||||
return
|
||||
}
|
||||
fmt.Printf(" Package = %v\n", obj.Pkg())
|
||||
if obj.Pkg() != nil {
|
||||
fmt.Println(" Path = ", obj.Pkg().Path())
|
||||
fmt.Println(" Name = ", obj.Pkg().Name())
|
||||
fmt.Println(" String = ", obj.Pkg().String())
|
||||
}
|
||||
fmt.Printf(" Name = %v\n", obj.Name())
|
||||
fmt.Printf(" Type = %v\n", obj.Type())
|
||||
fmt.Printf(" Id = %v\n", obj.Id())
|
||||
}
|
||||
|
||||
func checkContext(ctx *context, file string) bool {
|
||||
// #nosec
|
||||
if ctx == nil {
|
||||
fmt.Fprintln(os.Stderr, "Failed to create context for file: ", file)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func dumpCallObj(files ...string) {
|
||||
|
||||
for _, file := range files {
|
||||
if shouldSkip(file) {
|
||||
continue
|
||||
}
|
||||
context := createContext(file)
|
||||
if !checkContext(context, file) {
|
||||
return
|
||||
}
|
||||
ast.Inspect(context.root, func(n ast.Node) bool {
|
||||
var obj types.Object
|
||||
switch node := n.(type) {
|
||||
case *ast.Ident:
|
||||
obj = context.info.ObjectOf(node) //context.info.Uses[node]
|
||||
case *ast.SelectorExpr:
|
||||
obj = context.info.ObjectOf(node.Sel) //context.info.Uses[node.Sel]
|
||||
default:
|
||||
obj = nil
|
||||
}
|
||||
if obj != nil {
|
||||
printObject(obj)
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func dumpUses(files ...string) {
|
||||
for _, file := range files {
|
||||
if shouldSkip(file) {
|
||||
continue
|
||||
}
|
||||
context := createContext(file)
|
||||
if !checkContext(context, file) {
|
||||
return
|
||||
}
|
||||
for ident, obj := range context.info.Uses {
|
||||
fmt.Printf("IDENT: %v, OBJECT: %v\n", ident, obj)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func dumpTypes(files ...string) {
|
||||
for _, file := range files {
|
||||
if shouldSkip(file) {
|
||||
continue
|
||||
}
|
||||
context := createContext(file)
|
||||
if !checkContext(context, file) {
|
||||
return
|
||||
}
|
||||
for expr, tv := range context.info.Types {
|
||||
fmt.Printf("EXPR: %v, TYPE: %v\n", expr, tv)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func dumpDefs(files ...string) {
|
||||
for _, file := range files {
|
||||
if shouldSkip(file) {
|
||||
continue
|
||||
}
|
||||
context := createContext(file)
|
||||
if !checkContext(context, file) {
|
||||
return
|
||||
}
|
||||
for ident, obj := range context.info.Defs {
|
||||
fmt.Printf("IDENT: %v, OBJ: %v\n", ident, obj)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func dumpComments(files ...string) {
|
||||
for _, file := range files {
|
||||
if shouldSkip(file) {
|
||||
continue
|
||||
}
|
||||
context := createContext(file)
|
||||
if !checkContext(context, file) {
|
||||
return
|
||||
}
|
||||
for _, group := range context.comments.Comments() {
|
||||
fmt.Println(group.Text())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func dumpImports(files ...string) {
|
||||
for _, file := range files {
|
||||
if shouldSkip(file) {
|
||||
continue
|
||||
}
|
||||
context := createContext(file)
|
||||
if !checkContext(context, file) {
|
||||
return
|
||||
}
|
||||
for _, pkg := range context.pkg.Imports() {
|
||||
fmt.Println(pkg.Path(), pkg.Name())
|
||||
for _, name := range pkg.Scope().Names() {
|
||||
fmt.Println(" => ", name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
7
tools/vendor/github.com/GoASTScanner/gas/vendor.conf
generated
vendored
7
tools/vendor/github.com/GoASTScanner/gas/vendor.conf
generated
vendored
@@ -1,7 +0,0 @@
|
||||
# package
|
||||
github.com/GoAstScanner/gas
|
||||
|
||||
# import
|
||||
github.com/GoASTScanner/gas cc52ef5
|
||||
github.com/nbutton23/zxcvbn-go a22cb81
|
||||
github.com/ryanuber/go-glob v0.1
|
Reference in New Issue
Block a user