From 893b87b34342eadd448aba7638c5cc25f7ad26dd Mon Sep 17 00:00:00 2001 From: Cosmin Cojocar Date: Thu, 19 Jul 2018 18:42:25 +0200 Subject: [PATCH] Replace gas with gosec everywhere in the project --- .github/issue_template.md | 2 +- .travis.yml | 2 +- Dockerfile | 2 +- Makefile | 8 +- analyzer.go | 98 ++++++++++++------------ analyzer_test.go | 16 ++-- call_list.go | 2 +- call_list_test.go | 12 +-- cmd/{gas => gosec}/filelist.go | 0 cmd/{gas => gosec}/main.go | 28 +++---- cmd/{gas => gosec}/sort_issues.go | 6 +- cmd/{gas => gosec}/version.go | 0 cmd/{gasutil => gosecutil}/tools.go | 0 cmd/tlsconfig/header_template.go | 2 +- cmd/tlsconfig/rule_template.go | 4 +- config.go | 4 +- config_test.go | 8 +- gas_suite_test.go => gosec_suite_test.go | 6 +- helpers.go | 2 +- helpers_test.go | 2 +- import_tracker.go | 2 +- issue.go | 6 +- issue_test.go | 18 ++--- output/formatter.go | 12 +-- output/junit_xml_format.go | 12 +-- resolve.go | 2 +- resolve_test.go | 22 +++--- rule.go | 4 +- rule_test.go | 28 +++---- rules/archive.go | 20 ++--- rules/big.go | 18 ++--- rules/bind.go | 22 +++--- rules/blacklist.go | 24 +++--- rules/errors.go | 24 +++--- rules/fileperms.go | 28 +++---- rules/hardcoded_credentials.go | 28 +++---- rules/rand.go | 18 ++--- rules/readfile.go | 22 +++--- rules/rsa.go | 22 +++--- rules/rulelist.go | 10 +-- rules/rules_test.go | 17 ++-- rules/sql.go | 36 ++++----- rules/ssh.go | 18 ++--- rules/subproc.go | 18 ++--- rules/tempfiles.go | 22 +++--- rules/templates.go | 20 ++--- rules/tls.go | 32 ++++---- rules/tls_config.go | 14 ++-- rules/unsafe.go | 18 ++--- rules/weakcrypto.go | 18 ++--- testutils/pkg.go | 12 +-- testutils/visitor.go | 6 +- 52 files changed, 387 insertions(+), 390 deletions(-) rename cmd/{gas => gosec}/filelist.go (100%) rename cmd/{gas => gosec}/main.go (92%) rename cmd/{gas => gosec}/sort_issues.go (76%) rename cmd/{gas => gosec}/version.go (100%) rename cmd/{gasutil => gosecutil}/tools.go (100%) rename gas_suite_test.go => gosec_suite_test.go (58%) diff --git a/.github/issue_template.md b/.github/issue_template.md index 14aec56..9c3ef02 100644 --- a/.github/issue_template.md +++ b/.github/issue_template.md @@ -2,7 +2,7 @@ ### Steps to reproduce the behavior -### Gas version +### gosec version ### Go version (output of 'go version') diff --git a/.travis.yml b/.travis.yml index 4b1c9c4..d12ef10 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,7 @@ install: - go get -u github.com/onsi/ginkgo/ginkgo - go get -u github.com/onsi/gomega - go get -u golang.org/x/crypto/ssh - - go get -u github.com/securego/gas/cmd/gas/... + - go get -u github.com/securego/gosec/cmd/gosec/... - go get -v -t ./... - export PATH=$PATH:$HOME/gopath/bin diff --git a/Dockerfile b/Dockerfile index bbe12ca..e2ff565 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ FROM golang:1.9.4-alpine3.7 -ENV BIN=gas +ENV BIN=gosec COPY build/*-linux-amd64 /go/bin/$BIN COPY docker-entrypoint.sh /usr/local/bin diff --git a/Makefile b/Makefile index db55f0e..fc6002b 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ GIT_TAG?= $(shell git describe --always --tags) BUILD_DATE = $(shell date +%Y-%m-%d) -BIN = gas -BUILD_CMD = go build -ldflags "-X main.Version=${VERSION} -X main.GitTag=${GIT_TAG} -X main.BuildDate=${BUILD_DATE}" -o build/$(BIN)-$(VERSION)-$${GOOS}-$${GOARCH} ./cmd/gas/ & +BIN = gosec +BUILD_CMD = go build -ldflags "-X main.Version=${VERSION} -X main.GitTag=${GIT_TAG} -X main.BuildDate=${BUILD_DATE}" -o build/$(BIN)-$(VERSION)-$${GOOS}-$${GOARCH} ./cmd/gosec/ & FMT_CMD = $(gofmt -s -l -w $(find . -type f -name '*.go' -not -path './vendor/*') | tee /dev/stderr) IMAGE_REPO = docker.io @@ -13,12 +13,12 @@ test: bootstrap test -z '$(FMT_CMD)' go vet $(go list ./... | grep -v /vendor/) golint -set_exit_status $(shell go list ./... | grep -v vendor) - gas ./... + gosec ./... ginkgo -r -v bootstrap: dep ensure build: - go build -o $(BIN) ./cmd/gas/ + go build -o $(BIN) ./cmd/gosec/ clean: rm -rf build vendor rm -f release image bootstrap $(BIN) diff --git a/analyzer.go b/analyzer.go index d3a47ec..e21722f 100644 --- a/analyzer.go +++ b/analyzer.go @@ -12,8 +12,8 @@ // 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 +// Package gosec holds the central scanning logic used by gosec security scanner +package gosec import ( "go/ast" @@ -55,7 +55,7 @@ type Metrics struct { NumFound int `json:"found"` } -// Analyzer object is the main object of GAS. It has methods traverse an AST +// Analyzer object is the main object of gosec. It has methods traverse an AST // and invoke the correct checking rules as on each node as required. type Analyzer struct { ignoreNosec bool @@ -74,7 +74,7 @@ func NewAnalyzer(conf Config, logger *log.Logger) *Analyzer { ignoreNoSec = setting == "true" || setting == "enabled" } if logger == nil { - logger = log.New(os.Stderr, "[gas]", log.LstdFlags) + logger = log.New(os.Stderr, "[gosec]", log.LstdFlags) } return &Analyzer{ ignoreNosec: ignoreNoSec, @@ -89,15 +89,15 @@ func NewAnalyzer(conf Config, logger *log.Logger) *Analyzer { // LoadRules instantiates all the rules to be used when analyzing source // packages -func (gas *Analyzer) LoadRules(ruleDefinitions map[string]RuleBuilder) { +func (gosec *Analyzer) LoadRules(ruleDefinitions map[string]RuleBuilder) { for id, def := range ruleDefinitions { - r, nodes := def(id, gas.config) - gas.ruleset.Register(r, nodes...) + r, nodes := def(id, gosec.config) + gosec.ruleset.Register(r, nodes...) } } // Process kicks off the analysis process for a given package -func (gas *Analyzer) Process(buildTags []string, packagePaths ...string) error { +func (gosec *Analyzer) Process(buildTags []string, packagePaths ...string) error { ctx := build.Default ctx.BuildTags = append(ctx.BuildTags, buildTags...) packageConfig := loader.Config{ @@ -111,10 +111,10 @@ func (gas *Analyzer) Process(buildTags []string, packagePaths ...string) error { return err } if _, err := os.Stat(abspath); os.IsNotExist(err) { - gas.logger.Printf("Skipping: %s. Path doesn't exist.", abspath) + gosec.logger.Printf("Skipping: %s. Path doesn't exist.", abspath) continue } - gas.logger.Println("Searching directory:", abspath) + gosec.logger.Println("Searching directory:", abspath) basePackage, err := build.Default.ImportDir(packagePath, build.ImportComment) if err != nil { @@ -135,31 +135,31 @@ func (gas *Analyzer) Process(buildTags []string, packagePaths ...string) error { } for _, pkg := range builtPackage.Created { - gas.logger.Println("Checking package:", pkg.String()) + gosec.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() + gosec.logger.Println("Checking file:", builtPackage.Fset.File(file.Pos()).Name()) + gosec.context.FileSet = builtPackage.Fset + gosec.context.Config = gosec.config + gosec.context.Comments = ast.NewCommentMap(gosec.context.FileSet, file, file.Comments) + gosec.context.Root = file + gosec.context.Info = &pkg.Info + gosec.context.Pkg = pkg.Pkg + gosec.context.Imports = NewImportTracker() + gosec.context.Imports.TrackPackages(gosec.context.Pkg.Imports()...) + ast.Walk(gosec, file) + gosec.stats.NumFiles++ + gosec.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) ([]string, bool) { - if groups, ok := gas.context.Comments[n]; ok && !gas.ignoreNosec { +func (gosec *Analyzer) ignore(n ast.Node) ([]string, bool) { + if groups, ok := gosec.context.Comments[n]; ok && !gosec.ignoreNosec { for _, group := range groups { if strings.Contains(group.Text(), "#nosec") { - gas.stats.NumNosec++ + gosec.stats.NumNosec++ // Pull out the specific rules that are listed to be ignored. re := regexp.MustCompile("(G\\d{3})") @@ -182,27 +182,27 @@ func (gas *Analyzer) ignore(n ast.Node) ([]string, bool) { return nil, false } -// Visit runs the GAS visitor logic over an AST created by parsing go code. +// Visit runs the gosec 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 { +func (gosec *Analyzer) Visit(n ast.Node) ast.Visitor { // If we've reached the end of this branch, pop off the ignores stack. if n == nil { - if len(gas.context.Ignores) > 0 { - gas.context.Ignores = gas.context.Ignores[1:] + if len(gosec.context.Ignores) > 0 { + gosec.context.Ignores = gosec.context.Ignores[1:] } - return gas + return gosec } // Get any new rule exclusions. - ignoredRules, ignoreAll := gas.ignore(n) + ignoredRules, ignoreAll := gosec.ignore(n) if ignoreAll { return nil } // Now create the union of exclusions. ignores := make(map[string]bool, 0) - if len(gas.context.Ignores) > 0 { - for k, v := range gas.context.Ignores[0] { + if len(gosec.context.Ignores) > 0 { + for k, v := range gosec.context.Ignores[0] { ignores[k] = v } } @@ -212,37 +212,37 @@ func (gas *Analyzer) Visit(n ast.Node) ast.Visitor { } // Push the new set onto the stack. - gas.context.Ignores = append([]map[string]bool{ignores}, gas.context.Ignores...) + gosec.context.Ignores = append([]map[string]bool{ignores}, gosec.context.Ignores...) // Track aliased and initialization imports - gas.context.Imports.TrackImport(n) + gosec.context.Imports.TrackImport(n) - for _, rule := range gas.ruleset.RegisteredFor(n) { + for _, rule := range gosec.ruleset.RegisteredFor(n) { if _, ok := ignores[rule.ID()]; ok { continue } - issue, err := rule.Match(n, gas.context) + issue, err := rule.Match(n, gosec.context) if err != nil { - file, line := GetLocation(n, gas.context) + file, line := GetLocation(n, gosec.context) file = path.Base(file) - gas.logger.Printf("Rule error: %v => %s (%s:%d)\n", reflect.TypeOf(rule), err, file, line) + gosec.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++ + gosec.issues = append(gosec.issues, issue) + gosec.stats.NumFound++ } } - return gas + return gosec } // Report returns the current issues discovered and the metrics about the scan -func (gas *Analyzer) Report() ([]*Issue, *Metrics) { - return gas.issues, gas.stats +func (gosec *Analyzer) Report() ([]*Issue, *Metrics) { + return gosec.issues, gosec.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{} +func (gosec *Analyzer) Reset() { + gosec.context = &Context{} + gosec.issues = make([]*Issue, 0, 16) + gosec.stats = &Metrics{} } diff --git a/analyzer_test.go b/analyzer_test.go index 5f75db1..5252af1 100644 --- a/analyzer_test.go +++ b/analyzer_test.go @@ -1,4 +1,4 @@ -package gas_test +package gosec_test import ( "io/ioutil" @@ -6,24 +6,24 @@ import ( "os" "strings" - "github.com/securego/gas" - "github.com/securego/gas/rules" + "github.com/securego/gosec" + "github.com/securego/gosec/rules" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" - "github.com/securego/gas/testutils" + "github.com/securego/gosec/testutils" ) var _ = Describe("Analyzer", func() { var ( - analyzer *gas.Analyzer + analyzer *gosec.Analyzer logger *log.Logger buildTags []string ) BeforeEach(func() { logger, _ = testutils.NewLogger() - analyzer = gas.NewAnalyzer(nil, logger) + analyzer = gosec.NewAnalyzer(nil, logger) }) Context("when processing a package", func() { @@ -200,9 +200,9 @@ var _ = Describe("Analyzer", func() { source := sample.Code // overwrite nosec option - nosecIgnoreConfig := gas.NewConfig() + nosecIgnoreConfig := gosec.NewConfig() nosecIgnoreConfig.SetGlobal("nosec", "true") - customAnalyzer := gas.NewAnalyzer(nosecIgnoreConfig, logger) + customAnalyzer := gosec.NewAnalyzer(nosecIgnoreConfig, logger) customAnalyzer.LoadRules(rules.Generate(rules.NewRuleFilter(false, "G401")).Builders()) nosecPackage := testutils.NewTestPackage() diff --git a/call_list.go b/call_list.go index e277950..8370f8f 100644 --- a/call_list.go +++ b/call_list.go @@ -11,7 +11,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package gas +package gosec import ( "go/ast" diff --git a/call_list_test.go b/call_list_test.go index 3b01b68..41aa51d 100644 --- a/call_list_test.go +++ b/call_list_test.go @@ -1,20 +1,20 @@ -package gas_test +package gosec_test import ( "go/ast" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" - "github.com/securego/gas" - "github.com/securego/gas/testutils" + "github.com/securego/gosec" + "github.com/securego/gosec/testutils" ) var _ = Describe("call list", func() { var ( - calls gas.CallList + calls gosec.CallList ) BeforeEach(func() { - calls = gas.NewCallList() + calls = gosec.NewCallList() }) It("should not return any matches when empty", func() { @@ -72,7 +72,7 @@ var _ = Describe("call list", func() { matched := 0 v := testutils.NewMockVisitor() v.Context = ctx - v.Callback = func(n ast.Node, ctx *gas.Context) bool { + v.Callback = func(n ast.Node, ctx *gosec.Context) bool { if _, ok := n.(*ast.CallExpr); ok && calls.ContainsCallExpr(n, ctx) != nil { matched++ } diff --git a/cmd/gas/filelist.go b/cmd/gosec/filelist.go similarity index 100% rename from cmd/gas/filelist.go rename to cmd/gosec/filelist.go diff --git a/cmd/gas/main.go b/cmd/gosec/main.go similarity index 92% rename from cmd/gas/main.go rename to cmd/gosec/main.go index 0a1db68..df88a19 100644 --- a/cmd/gas/main.go +++ b/cmd/gosec/main.go @@ -28,16 +28,16 @@ import ( "strings" "github.com/kisielk/gotool" - "github.com/securego/gas" - "github.com/securego/gas/output" - "github.com/securego/gas/rules" + "github.com/securego/gosec" + "github.com/securego/gosec/output" + "github.com/securego/gosec/rules" ) const ( usageText = ` -GAS - Go AST Scanner +gosec - Golang security checker -Gas analyzes Go source code to look for common programming mistakes that +gosec analyzes Go source code to look for common programming mistakes that can lead to security problems. VERSION: %s @@ -47,17 +47,17 @@ BUILD DATE: %s USAGE: # Check a single package - $ gas $GOPATH/src/github.com/example/project + $ gosec $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 ./... + $ gosec -fmt=json -out=results.json ./... # Run a specific set of rules (by default all rules will be run): - $ gas -include=G101,G203,G401 ./... + $ gosec -include=G101,G203,G401 ./... # Run all rules except the provided - $ gas -exclude=G101 $GOPATH/src/github.com/example/project/... + $ gosec -exclude=G101 $GOPATH/src/github.com/example/project/... ` ) @@ -119,8 +119,8 @@ func usage() { fmt.Fprint(os.Stderr, "\n") } -func loadConfig(configFile string) (gas.Config, error) { - config := gas.NewConfig() +func loadConfig(configFile string) (gosec.Config, error) { + config := gosec.NewConfig() if configFile != "" { // #nosec file, err := os.Open(configFile) @@ -158,7 +158,7 @@ func loadRules(include, exclude string) rules.RuleList { return rules.Generate(filters...) } -func saveOutput(filename, format string, issues []*gas.Issue, metrics *gas.Metrics) error { +func saveOutput(filename, format string, issues []*gosec.Issue, metrics *gosec.Metrics) error { if filename != "" { outfile, err := os.Create(filename) if err != nil { @@ -283,7 +283,7 @@ func main() { if *flagQuiet { logger = log.New(ioutil.Discard, "", 0) } else { - logger = log.New(logWriter, "[gas] ", log.LstdFlags) + logger = log.New(logWriter, "[gosec] ", log.LstdFlags) } // Load config @@ -299,7 +299,7 @@ func main() { } // Create the analyzer - analyzer := gas.NewAnalyzer(config, logger) + analyzer := gosec.NewAnalyzer(config, logger) analyzer.LoadRules(ruleDefinitions.Builders()) vendor := regexp.MustCompile(`[\\/]vendor([\\/]|$)`) diff --git a/cmd/gas/sort_issues.go b/cmd/gosec/sort_issues.go similarity index 76% rename from cmd/gas/sort_issues.go rename to cmd/gosec/sort_issues.go index 208253c..10a86eb 100644 --- a/cmd/gas/sort_issues.go +++ b/cmd/gosec/sort_issues.go @@ -3,10 +3,10 @@ package main import ( "sort" - "github.com/securego/gas" + "github.com/securego/gosec" ) -type sortBySeverity []*gas.Issue +type sortBySeverity []*gosec.Issue func (s sortBySeverity) Len() int { return len(s) } @@ -15,6 +15,6 @@ func (s sortBySeverity) Less(i, j int) bool { return s[i].Severity > s[i].Severi 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) { +func sortIssues(issues []*gosec.Issue) { sort.Sort(sortBySeverity(issues)) } diff --git a/cmd/gas/version.go b/cmd/gosec/version.go similarity index 100% rename from cmd/gas/version.go rename to cmd/gosec/version.go diff --git a/cmd/gasutil/tools.go b/cmd/gosecutil/tools.go similarity index 100% rename from cmd/gasutil/tools.go rename to cmd/gosecutil/tools.go diff --git a/cmd/tlsconfig/header_template.go b/cmd/tlsconfig/header_template.go index 99da96e..3593645 100644 --- a/cmd/tlsconfig/header_template.go +++ b/cmd/tlsconfig/header_template.go @@ -8,6 +8,6 @@ package {{.}} import ( "go/ast" - "github.com/securego/gas" + "github.com/securego/gosec" ) `)) diff --git a/cmd/tlsconfig/rule_template.go b/cmd/tlsconfig/rule_template.go index bea9c39..952be29 100644 --- a/cmd/tlsconfig/rule_template.go +++ b/cmd/tlsconfig/rule_template.go @@ -5,9 +5,9 @@ import "text/template" var generatedRuleTmpl = template.Must(template.New("generated").Parse(` // New{{.Name}}TLSCheck creates a check for {{.Name}} TLS ciphers // DO NOT EDIT - generated by tlsconfig tool -func New{{.Name}}TLSCheck(id string, conf gas.Config) (gas.Rule, []ast.Node) { +func New{{.Name}}TLSCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) { return &insecureConfigTLS{ - MetaData: gas.MetaData{ID: id}, + MetaData: gosec.MetaData{ID: id}, requiredType: "crypto/tls.Config", MinVersion: {{ .MinVersion }}, MaxVersion: {{ .MaxVersion }}, diff --git a/config.go b/config.go index 09b97d3..a19937f 100644 --- a/config.go +++ b/config.go @@ -1,4 +1,4 @@ -package gas +package gosec import ( "bytes" @@ -10,7 +10,7 @@ import ( const ( // Globals are applicable to all rules and used for general - // configuration settings for gas. + // configuration settings for gosec. Globals = "global" ) diff --git a/config_test.go b/config_test.go index e1e2ff3..724717a 100644 --- a/config_test.go +++ b/config_test.go @@ -1,17 +1,17 @@ -package gas_test +package gosec_test import ( "bytes" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" - "github.com/securego/gas" + "github.com/securego/gosec" ) var _ = Describe("Configuration", func() { - var configuration gas.Config + var configuration gosec.Config BeforeEach(func() { - configuration = gas.NewConfig() + configuration = gosec.NewConfig() }) Context("when loading from disk", func() { diff --git a/gas_suite_test.go b/gosec_suite_test.go similarity index 58% rename from gas_suite_test.go rename to gosec_suite_test.go index 649d89a..7475c35 100644 --- a/gas_suite_test.go +++ b/gosec_suite_test.go @@ -1,4 +1,4 @@ -package gas_test +package gosec_test import ( . "github.com/onsi/ginkgo" @@ -7,7 +7,7 @@ import ( "testing" ) -func TestGas(t *testing.T) { +func TestGosec(t *testing.T) { RegisterFailHandler(Fail) - RunSpecs(t, "Gas Suite") + RunSpecs(t, "gosec Suite") } diff --git a/helpers.go b/helpers.go index 8bd1f5c..515ee8b 100644 --- a/helpers.go +++ b/helpers.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package gas +package gosec import ( "fmt" diff --git a/helpers_test.go b/helpers_test.go index 5676707..2f683cb 100644 --- a/helpers_test.go +++ b/helpers_test.go @@ -1,4 +1,4 @@ -package gas_test +package gosec_test import ( . "github.com/onsi/ginkgo" diff --git a/import_tracker.go b/import_tracker.go index 0f948fb..b56b65a 100644 --- a/import_tracker.go +++ b/import_tracker.go @@ -10,7 +10,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package gas +package gosec import ( "go/ast" diff --git a/issue.go b/issue.go index 5ec39bc..40bfa3d 100644 --- a/issue.go +++ b/issue.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package gas +package gosec import ( "encoding/json" @@ -34,7 +34,7 @@ const ( High ) -// Issue is returnd by a GAS rule if it discovers an issue with the scanned code. +// Issue is returnd by a gosec 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) @@ -45,7 +45,7 @@ type Issue struct { Line string `json:"line"` // Line number in file } -// MetaData is embedded in all GAS rules. The Severity, Confidence and What message +// MetaData is embedded in all gosec rules. The Severity, Confidence and What message // will be passed tbhrough to reported issues. type MetaData struct { ID string diff --git a/issue_test.go b/issue_test.go index bb3e162..68c4a5f 100644 --- a/issue_test.go +++ b/issue_test.go @@ -1,13 +1,13 @@ -package gas_test +package gosec_test import ( "go/ast" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" - "github.com/securego/gas" - "github.com/securego/gas/rules" - "github.com/securego/gas/testutils" + "github.com/securego/gosec" + "github.com/securego/gosec/rules" + "github.com/securego/gosec/testutils" ) var _ = Describe("Issue", func() { @@ -26,7 +26,7 @@ var _ = Describe("Issue", func() { pkg.AddFile("foo.go", source) ctx := pkg.CreateContext("foo.go") v := testutils.NewMockVisitor() - v.Callback = func(n ast.Node, ctx *gas.Context) bool { + v.Callback = func(n ast.Node, ctx *gosec.Context) bool { if node, ok := n.(*ast.BasicLit); ok { target = node return false @@ -37,7 +37,7 @@ var _ = Describe("Issue", func() { ast.Walk(v, ctx.Root) Expect(target).ShouldNot(BeNil()) - issue := gas.NewIssue(ctx, target, "TEST", "", gas.High, gas.High) + issue := gosec.NewIssue(ctx, target, "TEST", "", gosec.High, gosec.High) Expect(issue).ShouldNot(BeNil()) Expect(issue.Code).Should(MatchRegexp(`"bar"`)) Expect(issue.Line).Should(Equal("2")) @@ -58,7 +58,7 @@ var _ = Describe("Issue", func() { source := `package main import "os" func main(){` - source += "q := `SELECT * FROM table WHERE` + \n os.Args[1] + `= ?` // nolint: gas\n" + source += "q := `SELECT * FROM table WHERE` + \n os.Args[1] + `= ?` // nolint: gosec\n" source += `println(q)}` pkg := testutils.NewTestPackage() @@ -66,7 +66,7 @@ var _ = Describe("Issue", func() { pkg.AddFile("foo.go", source) ctx := pkg.CreateContext("foo.go") v := testutils.NewMockVisitor() - v.Callback = func(n ast.Node, ctx *gas.Context) bool { + v.Callback = func(n ast.Node, ctx *gosec.Context) bool { if node, ok := n.(*ast.BinaryExpr); ok { target = node } @@ -77,7 +77,7 @@ var _ = Describe("Issue", func() { Expect(target).ShouldNot(BeNil()) // Use SQL rule to check binary expr - cfg := gas.NewConfig() + cfg := gosec.NewConfig() rule, _ := rules.NewSQLStrConcat("TEST", cfg) issue, err := rule.Match(target, ctx) Expect(err).ShouldNot(HaveOccurred()) diff --git a/output/formatter.go b/output/formatter.go index 9ab13db..ee98de4 100644 --- a/output/formatter.go +++ b/output/formatter.go @@ -22,7 +22,7 @@ import ( "io" plainTemplate "text/template" - "github.com/securego/gas" + "github.com/securego/gosec" "gopkg.in/yaml.v2" ) @@ -58,13 +58,13 @@ Summary: ` type reportInfo struct { - Issues []*gas.Issue - Stats *gas.Metrics + Issues []*gosec.Issue + Stats *gosec.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 { +func CreateReport(w io.Writer, format string, issues []*gosec.Issue, metrics *gosec.Metrics) error { data := &reportInfo{ Issues: issues, Stats: metrics, @@ -150,7 +150,7 @@ func reportJUnitXML(w io.Writer, data *reportInfo) error { } func reportFromPlaintextTemplate(w io.Writer, reportTemplate string, data *reportInfo) error { - t, e := plainTemplate.New("gas").Parse(reportTemplate) + t, e := plainTemplate.New("gosec").Parse(reportTemplate) if e != nil { return e } @@ -159,7 +159,7 @@ func reportFromPlaintextTemplate(w io.Writer, reportTemplate string, data *repor } func reportFromHTMLTemplate(w io.Writer, reportTemplate string, data *reportInfo) error { - t, e := htmlTemplate.New("gas").Parse(reportTemplate) + t, e := htmlTemplate.New("gosec").Parse(reportTemplate) if e != nil { return e } diff --git a/output/junit_xml_format.go b/output/junit_xml_format.go index a3b0739..547d5b2 100644 --- a/output/junit_xml_format.go +++ b/output/junit_xml_format.go @@ -5,7 +5,7 @@ import ( htmlLib "html" "strconv" - "github.com/securego/gas" + "github.com/securego/gosec" ) type junitXMLReport struct { @@ -32,26 +32,26 @@ type failure struct { Text string `xml:",innerxml"` } -func generatePlaintext(issue *gas.Issue) string { +func generatePlaintext(issue *gosec.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) +func groupDataByRules(data *reportInfo) map[string][]*gosec.Issue { + groupedData := make(map[string][]*gosec.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} + groupedData[issue.What] = []*gosec.Issue{issue} } } return groupedData } -func createJUnitXMLStruct(groupedData map[string][]*gas.Issue) junitXMLReport { +func createJUnitXMLStruct(groupedData map[string][]*gosec.Issue) junitXMLReport { var xmlReport junitXMLReport for what, issues := range groupedData { testsuite := testsuite{ diff --git a/resolve.go b/resolve.go index d7c6dce..b563e7d 100644 --- a/resolve.go +++ b/resolve.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package gas +package gosec import "go/ast" diff --git a/resolve_test.go b/resolve_test.go index 1589c10..afc0316 100644 --- a/resolve_test.go +++ b/resolve_test.go @@ -1,12 +1,12 @@ -package gas_test +package gosec_test import ( "go/ast" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" - "github.com/securego/gas" - "github.com/securego/gas/testutils" + "github.com/securego/gosec" + "github.com/securego/gosec/testutils" ) var _ = Describe("Resolve ast node to concrete value", func() { @@ -19,7 +19,7 @@ var _ = Describe("Resolve ast node to concrete value", func() { pkg.AddFile("foo.go", `package main; const foo = "bar"; func main(){}`) ctx := pkg.CreateContext("foo.go") v := testutils.NewMockVisitor() - v.Callback = func(n ast.Node, ctx *gas.Context) bool { + v.Callback = func(n ast.Node, ctx *gosec.Context) bool { if node, ok := n.(*ast.BasicLit); ok { basicLiteral = node return false @@ -29,7 +29,7 @@ var _ = Describe("Resolve ast node to concrete value", func() { v.Context = ctx ast.Walk(v, ctx.Root) Expect(basicLiteral).ShouldNot(BeNil()) - Expect(gas.TryResolve(basicLiteral, ctx)).Should(BeTrue()) + Expect(gosec.TryResolve(basicLiteral, ctx)).Should(BeTrue()) }) It("should successfully resolve identifier", func() { @@ -39,7 +39,7 @@ var _ = Describe("Resolve ast node to concrete value", func() { pkg.AddFile("foo.go", `package main; var foo string = "bar"; func main(){}`) ctx := pkg.CreateContext("foo.go") v := testutils.NewMockVisitor() - v.Callback = func(n ast.Node, ctx *gas.Context) bool { + v.Callback = func(n ast.Node, ctx *gosec.Context) bool { if node, ok := n.(*ast.Ident); ok { ident = node return false @@ -49,7 +49,7 @@ var _ = Describe("Resolve ast node to concrete value", func() { v.Context = ctx ast.Walk(v, ctx.Root) Expect(ident).ShouldNot(BeNil()) - Expect(gas.TryResolve(ident, ctx)).Should(BeTrue()) + Expect(gosec.TryResolve(ident, ctx)).Should(BeTrue()) }) It("should successfully resolve assign statement", func() { @@ -59,7 +59,7 @@ var _ = Describe("Resolve ast node to concrete value", func() { pkg.AddFile("foo.go", `package main; const x = "bar"; func main(){ y := x; println(y) }`) ctx := pkg.CreateContext("foo.go") v := testutils.NewMockVisitor() - v.Callback = func(n ast.Node, ctx *gas.Context) bool { + v.Callback = func(n ast.Node, ctx *gosec.Context) bool { if node, ok := n.(*ast.AssignStmt); ok { if id, ok := node.Lhs[0].(*ast.Ident); ok && id.Name == "y" { assign = node @@ -70,7 +70,7 @@ var _ = Describe("Resolve ast node to concrete value", func() { v.Context = ctx ast.Walk(v, ctx.Root) Expect(assign).ShouldNot(BeNil()) - Expect(gas.TryResolve(assign, ctx)).Should(BeTrue()) + Expect(gosec.TryResolve(assign, ctx)).Should(BeTrue()) }) It("should successfully resolve a binary statement", func() { @@ -80,7 +80,7 @@ var _ = Describe("Resolve ast node to concrete value", func() { pkg.AddFile("foo.go", `package main; const (x = "bar"; y = "baz"); func main(){ z := x + y; println(z) }`) ctx := pkg.CreateContext("foo.go") v := testutils.NewMockVisitor() - v.Callback = func(n ast.Node, ctx *gas.Context) bool { + v.Callback = func(n ast.Node, ctx *gosec.Context) bool { if node, ok := n.(*ast.BinaryExpr); ok { target = node } @@ -89,7 +89,7 @@ var _ = Describe("Resolve ast node to concrete value", func() { v.Context = ctx ast.Walk(v, ctx.Root) Expect(target).ShouldNot(BeNil()) - Expect(gas.TryResolve(target, ctx)).Should(BeTrue()) + Expect(gosec.TryResolve(target, ctx)).Should(BeTrue()) }) // TODO: It should resolve call expressions diff --git a/rule.go b/rule.go index 95c6562..415c708 100644 --- a/rule.go +++ b/rule.go @@ -10,14 +10,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -package gas +package gosec import ( "go/ast" "reflect" ) -// The Rule interface used by all rules supported by GAS. +// The Rule interface used by all rules supported by gosec. type Rule interface { ID() string Match(ast.Node, *Context) (*Issue, error) diff --git a/rule_test.go b/rule_test.go index df5f21e..dbbf38f 100644 --- a/rule_test.go +++ b/rule_test.go @@ -1,4 +1,4 @@ -package gas_test +package gosec_test import ( "fmt" @@ -6,20 +6,20 @@ import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" - "github.com/securego/gas" + "github.com/securego/gosec" ) type mockrule struct { - issue *gas.Issue + issue *gosec.Issue err error - callback func(n ast.Node, ctx *gas.Context) bool + callback func(n ast.Node, ctx *gosec.Context) bool } func (m *mockrule) ID() string { return "MOCK" } -func (m *mockrule) Match(n ast.Node, ctx *gas.Context) (*gas.Issue, error) { +func (m *mockrule) Match(n ast.Node, ctx *gosec.Context) (*gosec.Issue, error) { if m.callback(n, ctx) { return m.issue, nil } @@ -31,29 +31,29 @@ var _ = Describe("Rule", func() { Context("when using a ruleset", func() { var ( - ruleset gas.RuleSet - dummyErrorRule gas.Rule - dummyIssueRule gas.Rule + ruleset gosec.RuleSet + dummyErrorRule gosec.Rule + dummyIssueRule gosec.Rule ) JustBeforeEach(func() { - ruleset = gas.NewRuleSet() + ruleset = gosec.NewRuleSet() dummyErrorRule = &mockrule{ issue: nil, err: fmt.Errorf("An unexpected error occurred"), - callback: func(n ast.Node, ctx *gas.Context) bool { return false }, + callback: func(n ast.Node, ctx *gosec.Context) bool { return false }, } dummyIssueRule = &mockrule{ - issue: &gas.Issue{ - Severity: gas.High, - Confidence: gas.High, + issue: &gosec.Issue{ + Severity: gosec.High, + Confidence: gosec.High, What: `Some explanation of the thing`, File: "main.go", Code: `#include int main(){ puts("hello world"); }`, Line: "42", }, err: nil, - callback: func(n ast.Node, ctx *gas.Context) bool { return true }, + callback: func(n ast.Node, ctx *gosec.Context) bool { return true }, } }) It("should be possible to register a rule for multiple ast.Node", func() { diff --git a/rules/archive.go b/rules/archive.go index 09648fb..1fa2b40 100644 --- a/rules/archive.go +++ b/rules/archive.go @@ -4,12 +4,12 @@ import ( "go/ast" "go/types" - "github.com/securego/gas" + "github.com/securego/gosec" ) type archive struct { - gas.MetaData - calls gas.CallList + gosec.MetaData + calls gosec.CallList argType string } @@ -18,7 +18,7 @@ func (a *archive) ID() string { } // Match inspects AST nodes to determine if the filepath.Joins uses any argument derived from type zip.File -func (a *archive) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) { +func (a *archive) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) { if node := a.calls.ContainsCallExpr(n, c); node != nil { for _, arg := range node.Args { var argType types.Type @@ -36,7 +36,7 @@ func (a *archive) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) { } if argType != nil && argType.String() == a.argType { - return gas.NewIssue(c, n, a.ID(), a.What, a.Severity, a.Confidence), nil + return gosec.NewIssue(c, n, a.ID(), a.What, a.Severity, a.Confidence), nil } } } @@ -44,16 +44,16 @@ func (a *archive) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) { } // NewArchive creates a new rule which detects the file traversal when extracting zip archives -func NewArchive(id string, conf gas.Config) (gas.Rule, []ast.Node) { - calls := gas.NewCallList() +func NewArchive(id string, conf gosec.Config) (gosec.Rule, []ast.Node) { + calls := gosec.NewCallList() calls.Add("path/filepath", "Join") return &archive{ calls: calls, argType: "*archive/zip.File", - MetaData: gas.MetaData{ + MetaData: gosec.MetaData{ ID: id, - Severity: gas.Medium, - Confidence: gas.High, + Severity: gosec.Medium, + Confidence: gosec.High, What: "File traversal when extracting zip archive", }, }, []ast.Node{(*ast.CallExpr)(nil)} diff --git a/rules/big.go b/rules/big.go index 10270a0..8c45a53 100644 --- a/rules/big.go +++ b/rules/big.go @@ -17,11 +17,11 @@ package rules import ( "go/ast" - "github.com/securego/gas" + "github.com/securego/gosec" ) type usingBigExp struct { - gas.MetaData + gosec.MetaData pkg string calls []string } @@ -30,23 +30,23 @@ func (r *usingBigExp) ID() string { return r.MetaData.ID } -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.ID(), r.What, r.Severity, r.Confidence), nil +func (r *usingBigExp) Match(n ast.Node, c *gosec.Context) (gi *gosec.Issue, err error) { + if _, matched := gosec.MatchCallByType(n, c, r.pkg, r.calls...); matched { + return gosec.NewIssue(c, n, r.ID(), r.What, r.Severity, r.Confidence), nil } return nil, nil } // NewUsingBigExp detects issues with modulus == 0 for Bignum -func NewUsingBigExp(id string, conf gas.Config) (gas.Rule, []ast.Node) { +func NewUsingBigExp(id string, conf gosec.Config) (gosec.Rule, []ast.Node) { return &usingBigExp{ pkg: "*math/big.Int", calls: []string{"Exp"}, - MetaData: gas.MetaData{ + MetaData: gosec.MetaData{ ID: id, What: "Use of math/big.Int.Exp function should be audited for modulus == 0", - Severity: gas.Low, - Confidence: gas.High, + Severity: gosec.Low, + Confidence: gosec.High, }, }, []ast.Node{(*ast.CallExpr)(nil)} } diff --git a/rules/bind.go b/rules/bind.go index c669951..a7d599b 100644 --- a/rules/bind.go +++ b/rules/bind.go @@ -18,13 +18,13 @@ import ( "go/ast" "regexp" - "github.com/securego/gas" + "github.com/securego/gosec" ) // Looks for net.Listen("0.0.0.0") or net.Listen(":8080") type bindsToAllNetworkInterfaces struct { - gas.MetaData - calls gas.CallList + gosec.MetaData + calls gosec.CallList pattern *regexp.Regexp } @@ -32,14 +32,14 @@ func (r *bindsToAllNetworkInterfaces) ID() string { return r.MetaData.ID } -func (r *bindsToAllNetworkInterfaces) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) { +func (r *bindsToAllNetworkInterfaces) Match(n ast.Node, c *gosec.Context) (*gosec.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 arg, err := gosec.GetString(callExpr.Args[1]); err == nil { if r.pattern.MatchString(arg) { - return gas.NewIssue(c, n, r.ID(), r.What, r.Severity, r.Confidence), nil + return gosec.NewIssue(c, n, r.ID(), r.What, r.Severity, r.Confidence), nil } } return nil, nil @@ -47,17 +47,17 @@ func (r *bindsToAllNetworkInterfaces) Match(n ast.Node, c *gas.Context) (*gas.Is // NewBindsToAllNetworkInterfaces detects socket connections that are setup to // listen on all network interfaces. -func NewBindsToAllNetworkInterfaces(id string, conf gas.Config) (gas.Rule, []ast.Node) { - calls := gas.NewCallList() +func NewBindsToAllNetworkInterfaces(id string, conf gosec.Config) (gosec.Rule, []ast.Node) { + calls := gosec.NewCallList() calls.Add("net", "Listen") calls.Add("crypto/tls", "Listen") return &bindsToAllNetworkInterfaces{ calls: calls, pattern: regexp.MustCompile(`^(0.0.0.0|:).*$`), - MetaData: gas.MetaData{ + MetaData: gosec.MetaData{ ID: id, - Severity: gas.Medium, - Confidence: gas.High, + Severity: gosec.Medium, + Confidence: gosec.High, What: "Binds to all network interfaces", }, }, []ast.Node{(*ast.CallExpr)(nil)} diff --git a/rules/blacklist.go b/rules/blacklist.go index 6ab3b8f..74a769c 100644 --- a/rules/blacklist.go +++ b/rules/blacklist.go @@ -18,11 +18,11 @@ import ( "go/ast" "strings" - "github.com/securego/gas" + "github.com/securego/gosec" ) type blacklistedImport struct { - gas.MetaData + gosec.MetaData Blacklisted map[string]string } @@ -36,10 +36,10 @@ func (r *blacklistedImport) ID() string { return r.MetaData.ID } -func (r *blacklistedImport) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) { +func (r *blacklistedImport) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) { if node, ok := n.(*ast.ImportSpec); ok { if description, ok := r.Blacklisted[unquote(node.Path.Value)]; ok { - return gas.NewIssue(c, node, r.ID(), description, r.Severity, r.Confidence), nil + return gosec.NewIssue(c, node, r.ID(), description, r.Severity, r.Confidence), nil } } return nil, nil @@ -47,40 +47,40 @@ func (r *blacklistedImport) Match(n ast.Node, c *gas.Context) (*gas.Issue, error // NewBlacklistedImports reports when a blacklisted import is being used. // Typically when a deprecated technology is being used. -func NewBlacklistedImports(id string, conf gas.Config, blacklist map[string]string) (gas.Rule, []ast.Node) { +func NewBlacklistedImports(id string, conf gosec.Config, blacklist map[string]string) (gosec.Rule, []ast.Node) { return &blacklistedImport{ - MetaData: gas.MetaData{ + MetaData: gosec.MetaData{ ID: id, - Severity: gas.Medium, - Confidence: gas.High, + Severity: gosec.Medium, + Confidence: gosec.High, }, Blacklisted: blacklist, }, []ast.Node{(*ast.ImportSpec)(nil)} } // NewBlacklistedImportMD5 fails if MD5 is imported -func NewBlacklistedImportMD5(id string, conf gas.Config) (gas.Rule, []ast.Node) { +func NewBlacklistedImportMD5(id string, conf gosec.Config) (gosec.Rule, []ast.Node) { return NewBlacklistedImports(id, conf, map[string]string{ "crypto/md5": "Blacklisted import crypto/md5: weak cryptographic primitive", }) } // NewBlacklistedImportDES fails if DES is imported -func NewBlacklistedImportDES(id string, conf gas.Config) (gas.Rule, []ast.Node) { +func NewBlacklistedImportDES(id string, conf gosec.Config) (gosec.Rule, []ast.Node) { return NewBlacklistedImports(id, conf, map[string]string{ "crypto/des": "Blacklisted import crypto/des: weak cryptographic primitive", }) } // NewBlacklistedImportRC4 fails if DES is imported -func NewBlacklistedImportRC4(id string, conf gas.Config) (gas.Rule, []ast.Node) { +func NewBlacklistedImportRC4(id string, conf gosec.Config) (gosec.Rule, []ast.Node) { return NewBlacklistedImports(id, conf, map[string]string{ "crypto/rc4": "Blacklisted import crypto/rc4: weak cryptographic primitive", }) } // NewBlacklistedImportCGI fails if CGI is imported -func NewBlacklistedImportCGI(id string, conf gas.Config) (gas.Rule, []ast.Node) { +func NewBlacklistedImportCGI(id string, conf gosec.Config) (gosec.Rule, []ast.Node) { return NewBlacklistedImports(id, 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)", }) diff --git a/rules/errors.go b/rules/errors.go index 73f5f87..5aea57d 100644 --- a/rules/errors.go +++ b/rules/errors.go @@ -18,19 +18,19 @@ import ( "go/ast" "go/types" - "github.com/securego/gas" + "github.com/securego/gosec" ) type noErrorCheck struct { - gas.MetaData - whitelist gas.CallList + gosec.MetaData + whitelist gosec.CallList } func (r *noErrorCheck) ID() string { return r.MetaData.ID } -func returnsError(callExpr *ast.CallExpr, ctx *gas.Context) int { +func returnsError(callExpr *ast.CallExpr, ctx *gosec.Context) int { if tv := ctx.Info.TypeOf(callExpr); tv != nil { switch t := tv.(type) { case *types.Tuple: @@ -49,7 +49,7 @@ 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 *gosec.Context) (*gosec.Issue, error) { switch stmt := n.(type) { case *ast.AssignStmt: for _, expr := range stmt.Rhs { @@ -59,7 +59,7 @@ func (r *noErrorCheck) Match(n ast.Node, ctx *gas.Context) (*gas.Issue, error) { return nil, nil } if id, ok := stmt.Lhs[pos].(*ast.Ident); ok && id.Name == "_" { - return gas.NewIssue(ctx, n, r.ID(), r.What, r.Severity, r.Confidence), nil + return gosec.NewIssue(ctx, n, r.ID(), r.What, r.Severity, r.Confidence), nil } } } @@ -67,7 +67,7 @@ func (r *noErrorCheck) Match(n ast.Node, ctx *gas.Context) (*gas.Issue, error) { 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.ID(), r.What, r.Severity, r.Confidence), nil + return gosec.NewIssue(ctx, n, r.ID(), r.What, r.Severity, r.Confidence), nil } } } @@ -75,10 +75,10 @@ func (r *noErrorCheck) Match(n ast.Node, ctx *gas.Context) (*gas.Issue, error) { } // NewNoErrorCheck detects if the returned error is unchecked -func NewNoErrorCheck(id string, conf gas.Config) (gas.Rule, []ast.Node) { +func NewNoErrorCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) { // TODO(gm) Come up with sensible defaults here. Or flip it to use a // black list instead. - whitelist := gas.NewCallList() + whitelist := gosec.NewCallList() whitelist.AddAll("bytes.Buffer", "Write", "WriteByte", "WriteRune", "WriteString") whitelist.AddAll("fmt", "Print", "Printf", "Println", "Fprint", "Fprintf", "Fprintln") whitelist.Add("io.PipeWriter", "CloseWithError") @@ -91,10 +91,10 @@ func NewNoErrorCheck(id string, conf gas.Config) (gas.Rule, []ast.Node) { } } return &noErrorCheck{ - MetaData: gas.MetaData{ + MetaData: gosec.MetaData{ ID: id, - Severity: gas.Low, - Confidence: gas.High, + Severity: gosec.Low, + Confidence: gosec.High, What: "Errors unhandled.", }, whitelist: whitelist, diff --git a/rules/fileperms.go b/rules/fileperms.go index 883f6a4..8e94369 100644 --- a/rules/fileperms.go +++ b/rules/fileperms.go @@ -19,11 +19,11 @@ import ( "go/ast" "strconv" - "github.com/securego/gas" + "github.com/securego/gosec" ) type filePermissions struct { - gas.MetaData + gosec.MetaData mode int64 pkg string calls []string @@ -50,11 +50,11 @@ func getConfiguredMode(conf map[string]interface{}, configKey string, defaultMod return mode } -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 { +func (r *filePermissions) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) { + if callexpr, matched := gosec.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 { - return gas.NewIssue(c, n, r.ID(), r.What, r.Severity, r.Confidence), nil + if mode, err := gosec.GetInt(modeArg); err == nil && mode > r.mode { + return gosec.NewIssue(c, n, r.ID(), r.What, r.Severity, r.Confidence), nil } } return nil, nil @@ -62,16 +62,16 @@ func (r *filePermissions) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) // NewFilePerms creates a rule to detect file creation with a more permissive than configured // permission mask. -func NewFilePerms(id string, conf gas.Config) (gas.Rule, []ast.Node) { +func NewFilePerms(id string, conf gosec.Config) (gosec.Rule, []ast.Node) { mode := getConfiguredMode(conf, "G302", 0600) return &filePermissions{ mode: mode, pkg: "os", calls: []string{"OpenFile", "Chmod"}, - MetaData: gas.MetaData{ + MetaData: gosec.MetaData{ ID: id, - Severity: gas.Medium, - Confidence: gas.High, + Severity: gosec.Medium, + Confidence: gosec.High, What: fmt.Sprintf("Expect file permissions to be %#o or less", mode), }, }, []ast.Node{(*ast.CallExpr)(nil)} @@ -79,16 +79,16 @@ func NewFilePerms(id string, conf gas.Config) (gas.Rule, []ast.Node) { // NewMkdirPerms creates a rule to detect directory creation with more permissive than // configured permission mask. -func NewMkdirPerms(id string, conf gas.Config) (gas.Rule, []ast.Node) { +func NewMkdirPerms(id string, conf gosec.Config) (gosec.Rule, []ast.Node) { mode := getConfiguredMode(conf, "G301", 0750) return &filePermissions{ mode: mode, pkg: "os", calls: []string{"Mkdir", "MkdirAll"}, - MetaData: gas.MetaData{ + MetaData: gosec.MetaData{ ID: id, - Severity: gas.Medium, - Confidence: gas.High, + Severity: gosec.Medium, + Confidence: gosec.High, What: fmt.Sprintf("Expect directory permissions to be %#o or less", mode), }, }, []ast.Node{(*ast.CallExpr)(nil)} diff --git a/rules/hardcoded_credentials.go b/rules/hardcoded_credentials.go index 6b811b6..17a5cdf 100644 --- a/rules/hardcoded_credentials.go +++ b/rules/hardcoded_credentials.go @@ -19,12 +19,12 @@ import ( "regexp" "strconv" - "github.com/nbutton23/zxcvbn-go" - "github.com/securego/gas" + zxcvbn "github.com/nbutton23/zxcvbn-go" + "github.com/securego/gosec" ) type credentials struct { - gas.MetaData + gosec.MetaData pattern *regexp.Regexp entropyThreshold float64 perCharThreshold float64 @@ -52,7 +52,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 *gosec.Context) (*gosec.Issue, error) { switch node := n.(type) { case *ast.AssignStmt: return r.matchAssign(node, ctx) @@ -62,14 +62,14 @@ 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 *gosec.Context) (*gosec.Issue, error) { for _, i := range assign.Lhs { if ident, ok := i.(*ast.Ident); ok { if r.pattern.MatchString(ident.Name) { for _, e := range assign.Rhs { - if val, err := gas.GetString(e); err == nil { + if val, err := gosec.GetString(e); err == nil { if r.ignoreEntropy || (!r.ignoreEntropy && r.isHighEntropyString(val)) { - return gas.NewIssue(ctx, assign, r.ID(), r.What, r.Severity, r.Confidence), nil + return gosec.NewIssue(ctx, assign, r.ID(), r.What, r.Severity, r.Confidence), nil } } } @@ -79,16 +79,16 @@ func (r *credentials) matchAssign(assign *ast.AssignStmt, ctx *gas.Context) (*ga return nil, nil } -func (r *credentials) matchValueSpec(valueSpec *ast.ValueSpec, ctx *gas.Context) (*gas.Issue, error) { +func (r *credentials) matchValueSpec(valueSpec *ast.ValueSpec, ctx *gosec.Context) (*gosec.Issue, error) { for index, ident := range valueSpec.Names { if r.pattern.MatchString(ident.Name) && valueSpec.Values != nil { // const foo, bar = "same value" if len(valueSpec.Values) <= index { index = len(valueSpec.Values) - 1 } - if val, err := gas.GetString(valueSpec.Values[index]); err == nil { + if val, err := gosec.GetString(valueSpec.Values[index]); err == nil { if r.ignoreEntropy || (!r.ignoreEntropy && r.isHighEntropyString(val)) { - return gas.NewIssue(ctx, valueSpec, r.ID(), r.What, r.Severity, r.Confidence), nil + return gosec.NewIssue(ctx, valueSpec, r.ID(), r.What, r.Severity, r.Confidence), nil } } } @@ -98,7 +98,7 @@ func (r *credentials) matchValueSpec(valueSpec *ast.ValueSpec, ctx *gas.Context) // NewHardcodedCredentials attempts to find high entropy string constants being // assigned to variables that appear to be related to credentials. -func NewHardcodedCredentials(id string, conf gas.Config) (gas.Rule, []ast.Node) { +func NewHardcodedCredentials(id string, conf gosec.Config) (gosec.Rule, []ast.Node) { pattern := `(?i)passwd|pass|password|pwd|secret|token` entropyThreshold := 80.0 perCharThreshold := 3.0 @@ -137,11 +137,11 @@ func NewHardcodedCredentials(id string, conf gas.Config) (gas.Rule, []ast.Node) perCharThreshold: perCharThreshold, ignoreEntropy: ignoreEntropy, truncate: truncateString, - MetaData: gas.MetaData{ + MetaData: gosec.MetaData{ ID: id, What: "Potential hardcoded credentials", - Confidence: gas.Low, - Severity: gas.High, + Confidence: gosec.Low, + Severity: gosec.High, }, }, []ast.Node{(*ast.AssignStmt)(nil), (*ast.ValueSpec)(nil)} } diff --git a/rules/rand.go b/rules/rand.go index 1e9e055..a2bdabe 100644 --- a/rules/rand.go +++ b/rules/rand.go @@ -17,11 +17,11 @@ package rules import ( "go/ast" - "github.com/securego/gas" + "github.com/securego/gosec" ) type weakRand struct { - gas.MetaData + gosec.MetaData funcNames []string packagePath string } @@ -30,10 +30,10 @@ func (w *weakRand) ID() string { return w.MetaData.ID } -func (w *weakRand) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) { +func (w *weakRand) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) { for _, funcName := range w.funcNames { - if _, matched := gas.MatchCallByPackage(n, c, w.packagePath, funcName); matched { - return gas.NewIssue(c, n, w.ID(), w.What, w.Severity, w.Confidence), nil + if _, matched := gosec.MatchCallByPackage(n, c, w.packagePath, funcName); matched { + return gosec.NewIssue(c, n, w.ID(), w.What, w.Severity, w.Confidence), nil } } @@ -41,14 +41,14 @@ func (w *weakRand) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) { } // NewWeakRandCheck detects the use of random number generator that isn't cryptographically secure -func NewWeakRandCheck(id string, conf gas.Config) (gas.Rule, []ast.Node) { +func NewWeakRandCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) { return &weakRand{ funcNames: []string{"Read", "Int"}, packagePath: "math/rand", - MetaData: gas.MetaData{ + MetaData: gosec.MetaData{ ID: id, - Severity: gas.High, - Confidence: gas.Medium, + Severity: gosec.High, + Confidence: gosec.Medium, What: "Use of weak random number generator (math/rand instead of crypto/rand)", }, }, []ast.Node{(*ast.CallExpr)(nil)} diff --git a/rules/readfile.go b/rules/readfile.go index 9e573be..61e1c85 100644 --- a/rules/readfile.go +++ b/rules/readfile.go @@ -18,12 +18,12 @@ import ( "go/ast" "go/types" - "github.com/securego/gas" + "github.com/securego/gosec" ) type readfile struct { - gas.MetaData - gas.CallList + gosec.MetaData + gosec.CallList } // ID returns the identifier for this rule @@ -32,13 +32,13 @@ func (r *readfile) ID() string { } // Match inspects AST nodes to determine if the match the methods `os.Open` or `ioutil.ReadFile` -func (r *readfile) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) { +func (r *readfile) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) { if node := r.ContainsCallExpr(n, c); node != nil { for _, arg := range node.Args { 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, r.ID(), r.What, r.Severity, r.Confidence), nil + if _, ok := obj.(*types.Var); ok && !gosec.TryResolve(ident, c) { + return gosec.NewIssue(c, n, r.ID(), r.What, r.Severity, r.Confidence), nil } } } @@ -47,14 +47,14 @@ func (r *readfile) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) { } // NewReadFile detects cases where we read files -func NewReadFile(id string, conf gas.Config) (gas.Rule, []ast.Node) { +func NewReadFile(id string, conf gosec.Config) (gosec.Rule, []ast.Node) { rule := &readfile{ - CallList: gas.NewCallList(), - MetaData: gas.MetaData{ + CallList: gosec.NewCallList(), + MetaData: gosec.MetaData{ ID: id, What: "Potential file inclusion via variable", - Severity: gas.Medium, - Confidence: gas.High, + Severity: gosec.Medium, + Confidence: gosec.High, }, } rule.Add("io/ioutil", "ReadFile") diff --git a/rules/rsa.go b/rules/rsa.go index e11cc99..4a42905 100644 --- a/rules/rsa.go +++ b/rules/rsa.go @@ -18,12 +18,12 @@ import ( "fmt" "go/ast" - "github.com/securego/gas" + "github.com/securego/gosec" ) type weakKeyStrength struct { - gas.MetaData - calls gas.CallList + gosec.MetaData + calls gosec.CallList bits int } @@ -31,27 +31,27 @@ func (w *weakKeyStrength) ID() string { return w.MetaData.ID } -func (w *weakKeyStrength) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) { +func (w *weakKeyStrength) Match(n ast.Node, c *gosec.Context) (*gosec.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.ID(), w.What, w.Severity, w.Confidence), nil + if bits, err := gosec.GetInt(callExpr.Args[1]); err == nil && bits < (int64)(w.bits) { + return gosec.NewIssue(c, n, w.ID(), w.What, w.Severity, w.Confidence), nil } } return nil, nil } // NewWeakKeyStrength builds a rule that detects RSA keys < 2048 bits -func NewWeakKeyStrength(id string, conf gas.Config) (gas.Rule, []ast.Node) { - calls := gas.NewCallList() +func NewWeakKeyStrength(id string, conf gosec.Config) (gosec.Rule, []ast.Node) { + calls := gosec.NewCallList() calls.Add("crypto/rsa", "GenerateKey") bits := 2048 return &weakKeyStrength{ calls: calls, bits: bits, - MetaData: gas.MetaData{ + MetaData: gosec.MetaData{ ID: id, - Severity: gas.Medium, - Confidence: gas.High, + Severity: gosec.Medium, + Confidence: gosec.High, What: fmt.Sprintf("RSA keys should be at least %d bits", bits), }, }, []ast.Node{(*ast.CallExpr)(nil)} diff --git a/rules/rulelist.go b/rules/rulelist.go index 63d98ab..16cb273 100644 --- a/rules/rulelist.go +++ b/rules/rulelist.go @@ -14,24 +14,22 @@ package rules -import ( - "github.com/securego/gas" -) +import "github.com/securego/gosec" // RuleDefinition contains the description of a rule and a mechanism to // create it. type RuleDefinition struct { ID string Description string - Create gas.RuleBuilder + Create gosec.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() map[string]gas.RuleBuilder { - builders := make(map[string]gas.RuleBuilder) +func (rl RuleList) Builders() map[string]gosec.RuleBuilder { + builders := make(map[string]gosec.RuleBuilder) for _, def := range rl { builders[def.ID] = def.Create } diff --git a/rules/rules_test.go b/rules/rules_test.go index 7e9324b..958932f 100644 --- a/rules/rules_test.go +++ b/rules/rules_test.go @@ -4,28 +4,27 @@ import ( "fmt" "log" - "github.com/securego/gas" - . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" - "github.com/securego/gas/rules" - "github.com/securego/gas/testutils" + "github.com/securego/gosec" + "github.com/securego/gosec/rules" + "github.com/securego/gosec/testutils" ) -var _ = Describe("gas rules", func() { +var _ = Describe("gosec rules", func() { var ( logger *log.Logger - config gas.Config - analyzer *gas.Analyzer + config gosec.Config + analyzer *gosec.Analyzer runner func(string, []testutils.CodeSample) buildTags []string ) BeforeEach(func() { logger, _ = testutils.NewLogger() - config = gas.NewConfig() - analyzer = gas.NewAnalyzer(config, logger) + config = gosec.NewConfig() + analyzer = gosec.NewAnalyzer(config, logger) runner = func(rule string, samples []testutils.CodeSample) { analyzer.LoadRules(rules.Generate(rules.NewRuleFilter(false, rule)).Builders()) for n, sample := range samples { diff --git a/rules/sql.go b/rules/sql.go index 5e37c58..655f4b0 100644 --- a/rules/sql.go +++ b/rules/sql.go @@ -18,11 +18,11 @@ import ( "go/ast" "regexp" - "github.com/securego/gas" + "github.com/securego/gosec" ) type sqlStatement struct { - gas.MetaData + gosec.MetaData // Contains a list of patterns which must all match for the rule to match. patterns []*regexp.Regexp @@ -59,10 +59,10 @@ 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 *gosec.Context) (*gosec.Issue, error) { if node, ok := n.(*ast.BinaryExpr); ok { if start, ok := node.X.(*ast.BasicLit); ok { - if str, e := gas.GetString(start); e == nil { + if str, e := gosec.GetString(start); e == nil { if !s.MatchPatterns(str) { return nil, nil } @@ -72,7 +72,7 @@ func (s *sqlStrConcat) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) { if second, ok := node.Y.(*ast.Ident); ok && s.checkObject(second) { return nil, nil } - return gas.NewIssue(c, n, s.ID(), s.What, s.Severity, s.Confidence), nil + return gosec.NewIssue(c, n, s.ID(), s.What, s.Severity, s.Confidence), nil } } } @@ -80,16 +80,16 @@ func (s *sqlStrConcat) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) { } // NewSQLStrConcat looks for cases where we are building SQL strings via concatenation -func NewSQLStrConcat(id string, conf gas.Config) (gas.Rule, []ast.Node) { +func NewSQLStrConcat(id string, conf gosec.Config) (gosec.Rule, []ast.Node) { return &sqlStrConcat{ sqlStatement: sqlStatement{ patterns: []*regexp.Regexp{ regexp.MustCompile(`(?)(SELECT|DELETE|INSERT|UPDATE|INTO|FROM|WHERE) `), }, - MetaData: gas.MetaData{ + MetaData: gosec.MetaData{ ID: id, - Severity: gas.Medium, - Confidence: gas.High, + Severity: gosec.Medium, + Confidence: gosec.High, What: "SQL string concatenation", }, }, @@ -98,34 +98,34 @@ func NewSQLStrConcat(id string, conf gas.Config) (gas.Rule, []ast.Node) { type sqlStrFormat struct { sqlStatement - calls gas.CallList + calls gosec.CallList } // Looks for "fmt.Sprintf("SELECT * FROM foo where '%s', userInput)" -func (s *sqlStrFormat) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) { +func (s *sqlStrFormat) Match(n ast.Node, c *gosec.Context) (*gosec.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.ID(), s.What, s.Severity, s.Confidence), nil + if arg, e := gosec.GetString(node.Args[0]); s.MatchPatterns(arg) && e == nil { + return gosec.NewIssue(c, n, s.ID(), s.What, s.Severity, s.Confidence), nil } } return nil, nil } // NewSQLStrFormat looks for cases where we're building SQL query strings using format strings -func NewSQLStrFormat(id string, conf gas.Config) (gas.Rule, []ast.Node) { +func NewSQLStrFormat(id string, conf gosec.Config) (gosec.Rule, []ast.Node) { rule := &sqlStrFormat{ - calls: gas.NewCallList(), + calls: gosec.NewCallList(), sqlStatement: sqlStatement{ patterns: []*regexp.Regexp{ regexp.MustCompile("(?)(SELECT|DELETE|INSERT|UPDATE|INTO|FROM|WHERE) "), regexp.MustCompile("%[^bdoxXfFp]"), }, - MetaData: gas.MetaData{ + MetaData: gosec.MetaData{ ID: id, - Severity: gas.Medium, - Confidence: gas.High, + Severity: gosec.Medium, + Confidence: gosec.High, What: "SQL string formatting", }, }, diff --git a/rules/ssh.go b/rules/ssh.go index 17ed71b..7496b5f 100644 --- a/rules/ssh.go +++ b/rules/ssh.go @@ -3,11 +3,11 @@ package rules import ( "go/ast" - "github.com/securego/gas" + "github.com/securego/gosec" ) type sshHostKey struct { - gas.MetaData + gosec.MetaData pkg string calls []string } @@ -16,23 +16,23 @@ func (r *sshHostKey) ID() string { return r.MetaData.ID } -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.ID(), r.What, r.Severity, r.Confidence), nil +func (r *sshHostKey) Match(n ast.Node, c *gosec.Context) (gi *gosec.Issue, err error) { + if _, matches := gosec.MatchCallByPackage(n, c, r.pkg, r.calls...); matches { + return gosec.NewIssue(c, n, r.ID(), r.What, r.Severity, r.Confidence), nil } return nil, nil } // NewSSHHostKey rule detects the use of insecure ssh HostKeyCallback. -func NewSSHHostKey(id string, conf gas.Config) (gas.Rule, []ast.Node) { +func NewSSHHostKey(id string, conf gosec.Config) (gosec.Rule, []ast.Node) { return &sshHostKey{ pkg: "golang.org/x/crypto/ssh", calls: []string{"InsecureIgnoreHostKey"}, - MetaData: gas.MetaData{ + MetaData: gosec.MetaData{ ID: id, What: "Use of ssh InsecureIgnoreHostKey should be audited", - Severity: gas.Medium, - Confidence: gas.High, + Severity: gosec.Medium, + Confidence: gosec.High, }, }, []ast.Node{(*ast.CallExpr)(nil)} } diff --git a/rules/subproc.go b/rules/subproc.go index d34cfb1..b214ed9 100644 --- a/rules/subproc.go +++ b/rules/subproc.go @@ -18,12 +18,12 @@ import ( "go/ast" "go/types" - "github.com/securego/gas" + "github.com/securego/gosec" ) type subprocess struct { - gas.MetaData - gas.CallList + gosec.MetaData + gosec.CallList } func (r *subprocess) ID() string { @@ -39,24 +39,24 @@ func (r *subprocess) ID() string { // is unsafe. For example: // // syscall.Exec("echo", "foobar" + tainted) -func (r *subprocess) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) { +func (r *subprocess) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) { if node := r.ContainsCallExpr(n, c); node != nil { for _, arg := range node.Args { 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, r.ID(), "Subprocess launched with variable", gas.Medium, gas.High), nil + if _, ok := obj.(*types.Var); ok && !gosec.TryResolve(ident, c) { + return gosec.NewIssue(c, n, r.ID(), "Subprocess launched with variable", gosec.Medium, gosec.High), nil } } } - return gas.NewIssue(c, n, r.ID(), "Subprocess launching should be audited", gas.Low, gas.High), nil + return gosec.NewIssue(c, n, r.ID(), "Subprocess launching should be audited", gosec.Low, gosec.High), nil } return nil, nil } // NewSubproc detects cases where we are forking out to an external process -func NewSubproc(id string, conf gas.Config) (gas.Rule, []ast.Node) { - rule := &subprocess{gas.MetaData{ID: id}, gas.NewCallList()} +func NewSubproc(id string, conf gosec.Config) (gosec.Rule, []ast.Node) { + rule := &subprocess{gosec.MetaData{ID: id}, gosec.NewCallList()} rule.Add("os/exec", "Command") rule.Add("syscall", "Exec") return rule, []ast.Node{(*ast.CallExpr)(nil)} diff --git a/rules/tempfiles.go b/rules/tempfiles.go index c2f587b..6963404 100644 --- a/rules/tempfiles.go +++ b/rules/tempfiles.go @@ -18,12 +18,12 @@ import ( "go/ast" "regexp" - "github.com/securego/gas" + "github.com/securego/gosec" ) type badTempFile struct { - gas.MetaData - calls gas.CallList + gosec.MetaData + calls gosec.CallList args *regexp.Regexp } @@ -31,27 +31,27 @@ func (t *badTempFile) ID() string { return t.MetaData.ID } -func (t *badTempFile) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err error) { +func (t *badTempFile) Match(n ast.Node, c *gosec.Context) (gi *gosec.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.ID(), t.What, t.Severity, t.Confidence), nil + if arg, e := gosec.GetString(node.Args[0]); t.args.MatchString(arg) && e == nil { + return gosec.NewIssue(c, n, t.ID(), t.What, t.Severity, t.Confidence), nil } } return nil, nil } // NewBadTempFile detects direct writes to predictable path in temporary directory -func NewBadTempFile(id string, conf gas.Config) (gas.Rule, []ast.Node) { - calls := gas.NewCallList() +func NewBadTempFile(id string, conf gosec.Config) (gosec.Rule, []ast.Node) { + calls := gosec.NewCallList() calls.Add("io/ioutil", "WriteFile") calls.Add("os", "Create") return &badTempFile{ calls: calls, args: regexp.MustCompile(`^/tmp/.*$|^/var/tmp/.*$`), - MetaData: gas.MetaData{ + MetaData: gosec.MetaData{ ID: id, - Severity: gas.Medium, - Confidence: gas.High, + Severity: gosec.Medium, + Confidence: gosec.High, What: "File creation in shared tmp directory without using ioutil.Tempfile", }, }, []ast.Node{(*ast.CallExpr)(nil)} diff --git a/rules/templates.go b/rules/templates.go index 45ea3c0..30a964b 100644 --- a/rules/templates.go +++ b/rules/templates.go @@ -17,23 +17,23 @@ package rules import ( "go/ast" - "github.com/securego/gas" + "github.com/securego/gosec" ) type templateCheck struct { - gas.MetaData - calls gas.CallList + gosec.MetaData + calls gosec.CallList } func (t *templateCheck) ID() string { return t.MetaData.ID } -func (t *templateCheck) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) { +func (t *templateCheck) Match(n ast.Node, c *gosec.Context) (*gosec.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.ID(), t.What, t.Severity, t.Confidence), nil + return gosec.NewIssue(c, n, t.ID(), t.What, t.Severity, t.Confidence), nil } } } @@ -42,19 +42,19 @@ func (t *templateCheck) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) { // 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(id string, conf gas.Config) (gas.Rule, []ast.Node) { +func NewTemplateCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) { - calls := gas.NewCallList() + calls := gosec.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{ + MetaData: gosec.MetaData{ ID: id, - Severity: gas.Medium, - Confidence: gas.Low, + Severity: gosec.Medium, + Confidence: gosec.Low, What: "this method will not auto-escape HTML. Verify data is well formed.", }, }, []ast.Node{(*ast.CallExpr)(nil)} diff --git a/rules/tls.go b/rules/tls.go index 62366bc..d4b7fa2 100644 --- a/rules/tls.go +++ b/rules/tls.go @@ -20,11 +20,11 @@ import ( "fmt" "go/ast" - "github.com/securego/gas" + "github.com/securego/gosec" ) type insecureConfigTLS struct { - gas.MetaData + gosec.MetaData MinVersion int16 MaxVersion int16 requiredType string @@ -44,14 +44,14 @@ func stringInSlice(a string, list []string) bool { return false } -func (t *insecureConfigTLS) processTLSCipherSuites(n ast.Node, c *gas.Context) *gas.Issue { +func (t *insecureConfigTLS) processTLSCipherSuites(n ast.Node, c *gosec.Context) *gosec.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) { err := fmt.Sprintf("TLS Bad Cipher Suite: %s", ident.Sel.Name) - return gas.NewIssue(c, ident, t.ID(), err, gas.High, gas.High) + return gosec.NewIssue(c, ident, t.ID(), err, gosec.High, gosec.High) } } } @@ -59,46 +59,46 @@ 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 *gosec.Context) *gosec.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" { - return gas.NewIssue(c, n, t.ID(), "TLS InsecureSkipVerify set true.", gas.High, gas.High) + return gosec.NewIssue(c, n, t.ID(), "TLS InsecureSkipVerify set true.", gosec.High, gosec.High) } } else { // TODO(tk): symbol tab look up to get the actual value - return gas.NewIssue(c, n, t.ID(), "TLS InsecureSkipVerify may be true.", gas.High, gas.Low) + return gosec.NewIssue(c, n, t.ID(), "TLS InsecureSkipVerify may be true.", gosec.High, gosec.Low) } case "PreferServerCipherSuites": if node, ok := n.Value.(*ast.Ident); ok { if node.Name == "false" { - return gas.NewIssue(c, n, t.ID(), "TLS PreferServerCipherSuites set false.", gas.Medium, gas.High) + return gosec.NewIssue(c, n, t.ID(), "TLS PreferServerCipherSuites set false.", gosec.Medium, gosec.High) } } else { // TODO(tk): symbol tab look up to get the actual value - return gas.NewIssue(c, n, t.ID(), "TLS PreferServerCipherSuites may be false.", gas.Medium, gas.Low) + return gosec.NewIssue(c, n, t.ID(), "TLS PreferServerCipherSuites may be false.", gosec.Medium, gosec.Low) } case "MinVersion": - if ival, ierr := gas.GetInt(n.Value); ierr == nil { + if ival, ierr := gosec.GetInt(n.Value); ierr == nil { if (int16)(ival) < t.MinVersion { - return gas.NewIssue(c, n, t.ID(), "TLS MinVersion too low.", gas.High, gas.High) + return gosec.NewIssue(c, n, t.ID(), "TLS MinVersion too low.", gosec.High, gosec.High) } // TODO(tk): symbol tab look up to get the actual value - return gas.NewIssue(c, n, t.ID(), "TLS MinVersion may be too low.", gas.High, gas.Low) + return gosec.NewIssue(c, n, t.ID(), "TLS MinVersion may be too low.", gosec.High, gosec.Low) } case "MaxVersion": - if ival, ierr := gas.GetInt(n.Value); ierr == nil { + if ival, ierr := gosec.GetInt(n.Value); ierr == nil { if (int16)(ival) < t.MaxVersion { - return gas.NewIssue(c, n, t.ID(), "TLS MaxVersion too low.", gas.High, gas.High) + return gosec.NewIssue(c, n, t.ID(), "TLS MaxVersion too low.", gosec.High, gosec.High) } // TODO(tk): symbol tab look up to get the actual value - return gas.NewIssue(c, n, t.ID(), "TLS MaxVersion may be too low.", gas.High, gas.Low) + return gosec.NewIssue(c, n, t.ID(), "TLS MaxVersion may be too low.", gosec.High, gosec.Low) } case "CipherSuites": @@ -112,7 +112,7 @@ func (t *insecureConfigTLS) processTLSConfVal(n *ast.KeyValueExpr, c *gas.Contex return nil } -func (t *insecureConfigTLS) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) { +func (t *insecureConfigTLS) Match(n ast.Node, c *gosec.Context) (*gosec.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 { diff --git a/rules/tls_config.go b/rules/tls_config.go index a756386..a629917 100644 --- a/rules/tls_config.go +++ b/rules/tls_config.go @@ -3,14 +3,14 @@ package rules import ( "go/ast" - "github.com/securego/gas" + "github.com/securego/gosec" ) // NewModernTLSCheck creates a check for Modern TLS ciphers // DO NOT EDIT - generated by tlsconfig tool -func NewModernTLSCheck(id string, conf gas.Config) (gas.Rule, []ast.Node) { +func NewModernTLSCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) { return &insecureConfigTLS{ - MetaData: gas.MetaData{ID: id}, + MetaData: gosec.MetaData{ID: id}, requiredType: "crypto/tls.Config", MinVersion: 0x0303, MaxVersion: 0x0303, @@ -31,9 +31,9 @@ func NewModernTLSCheck(id string, conf gas.Config) (gas.Rule, []ast.Node) { // NewIntermediateTLSCheck creates a check for Intermediate TLS ciphers // DO NOT EDIT - generated by tlsconfig tool -func NewIntermediateTLSCheck(id string, conf gas.Config) (gas.Rule, []ast.Node) { +func NewIntermediateTLSCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) { return &insecureConfigTLS{ - MetaData: gas.MetaData{ID: id}, + MetaData: gosec.MetaData{ID: id}, requiredType: "crypto/tls.Config", MinVersion: 0x0301, MaxVersion: 0x0303, @@ -74,9 +74,9 @@ func NewIntermediateTLSCheck(id string, conf gas.Config) (gas.Rule, []ast.Node) // NewOldTLSCheck creates a check for Old TLS ciphers // DO NOT EDIT - generated by tlsconfig tool -func NewOldTLSCheck(id string, conf gas.Config) (gas.Rule, []ast.Node) { +func NewOldTLSCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) { return &insecureConfigTLS{ - MetaData: gas.MetaData{ID: id}, + MetaData: gosec.MetaData{ID: id}, requiredType: "crypto/tls.Config", MinVersion: 0x0300, MaxVersion: 0x0303, diff --git a/rules/unsafe.go b/rules/unsafe.go index bb88aa6..f4a38be 100644 --- a/rules/unsafe.go +++ b/rules/unsafe.go @@ -17,11 +17,11 @@ package rules import ( "go/ast" - "github.com/securego/gas" + "github.com/securego/gosec" ) type usingUnsafe struct { - gas.MetaData + gosec.MetaData pkg string calls []string } @@ -30,24 +30,24 @@ func (r *usingUnsafe) ID() string { return r.MetaData.ID } -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.ID(), r.What, r.Severity, r.Confidence), nil +func (r *usingUnsafe) Match(n ast.Node, c *gosec.Context) (gi *gosec.Issue, err error) { + if _, matches := gosec.MatchCallByPackage(n, c, r.pkg, r.calls...); matches { + return gosec.NewIssue(c, n, r.ID(), r.What, r.Severity, r.Confidence), nil } return nil, nil } // NewUsingUnsafe rule detects the use of the unsafe package. This is only // really useful for auditing purposes. -func NewUsingUnsafe(id string, conf gas.Config) (gas.Rule, []ast.Node) { +func NewUsingUnsafe(id string, conf gosec.Config) (gosec.Rule, []ast.Node) { return &usingUnsafe{ pkg: "unsafe", calls: []string{"Alignof", "Offsetof", "Sizeof", "Pointer"}, - MetaData: gas.MetaData{ + MetaData: gosec.MetaData{ ID: id, What: "Use of unsafe calls should be audited", - Severity: gas.Low, - Confidence: gas.High, + Severity: gosec.Low, + Confidence: gosec.High, }, }, []ast.Node{(*ast.CallExpr)(nil)} } diff --git a/rules/weakcrypto.go b/rules/weakcrypto.go index 26b03df..db1ada7 100644 --- a/rules/weakcrypto.go +++ b/rules/weakcrypto.go @@ -17,11 +17,11 @@ package rules import ( "go/ast" - "github.com/securego/gas" + "github.com/securego/gosec" ) type usesWeakCryptography struct { - gas.MetaData + gosec.MetaData blacklist map[string][]string } @@ -29,27 +29,27 @@ func (r *usesWeakCryptography) ID() string { return r.MetaData.ID } -func (r *usesWeakCryptography) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) { +func (r *usesWeakCryptography) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) { for pkg, funcs := range r.blacklist { - if _, matched := gas.MatchCallByPackage(n, c, pkg, funcs...); matched { - return gas.NewIssue(c, n, r.ID(), r.What, r.Severity, r.Confidence), nil + if _, matched := gosec.MatchCallByPackage(n, c, pkg, funcs...); matched { + return gosec.NewIssue(c, n, r.ID(), r.What, r.Severity, r.Confidence), nil } } return nil, nil } // NewUsesWeakCryptography detects uses of des.* md5.* or rc4.* -func NewUsesWeakCryptography(id string, conf gas.Config) (gas.Rule, []ast.Node) { +func NewUsesWeakCryptography(id string, conf gosec.Config) (gosec.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{ blacklist: calls, - MetaData: gas.MetaData{ + MetaData: gosec.MetaData{ ID: id, - Severity: gas.Medium, - Confidence: gas.High, + Severity: gosec.Medium, + Confidence: gosec.High, What: "Use of weak cryptographic primitive", }, } diff --git a/testutils/pkg.go b/testutils/pkg.go index b74c211..ee85ac7 100644 --- a/testutils/pkg.go +++ b/testutils/pkg.go @@ -10,7 +10,7 @@ import ( "path" "strings" - "github.com/securego/gas" + "github.com/securego/gosec" "golang.org/x/tools/go/loader" ) @@ -33,7 +33,7 @@ type TestPackage struct { func NewTestPackage() *TestPackage { // Files must exist in $GOPATH sourceDir := path.Join(os.Getenv("GOPATH"), "src") - workingDir, err := ioutil.TempDir(sourceDir, "gas_test") + workingDir, err := ioutil.TempDir(sourceDir, "gosecs_test") if err != nil { return nil } @@ -97,7 +97,7 @@ func (p *TestPackage) Build() error { } // CreateContext builds a context out of supplied package context -func (p *TestPackage) CreateContext(filename string) *gas.Context { +func (p *TestPackage) CreateContext(filename string) *gosec.Context { if err := p.Build(); err != nil { log.Fatal(err) return nil @@ -109,13 +109,13 @@ func (p *TestPackage) CreateContext(filename string) *gas.Context { strip := fmt.Sprintf("%s%c", p.Path, os.PathSeparator) pkgFile = strings.TrimPrefix(pkgFile, strip) if pkgFile == filename { - ctx := &gas.Context{ + ctx := &gosec.Context{ FileSet: p.build.program.Fset, Root: file, - Config: gas.NewConfig(), + Config: gosec.NewConfig(), Info: &pkg.Info, Pkg: pkg.Pkg, - Imports: gas.NewImportTracker(), + Imports: gosec.NewImportTracker(), } ctx.Imports.TrackPackages(ctx.Pkg.Imports()...) return ctx diff --git a/testutils/visitor.go b/testutils/visitor.go index b2c6a50..775829b 100644 --- a/testutils/visitor.go +++ b/testutils/visitor.go @@ -3,14 +3,14 @@ package testutils import ( "go/ast" - "github.com/securego/gas" + "github.com/securego/gosec" ) // MockVisitor is useful for stubbing out ast.Visitor with callback // and looking for specific conditions to exist. type MockVisitor struct { - Context *gas.Context - Callback func(n ast.Node, ctx *gas.Context) bool + Context *gosec.Context + Callback func(n ast.Node, ctx *gosec.Context) bool } // NewMockVisitor creates a new empty struct, the Context and