diff --git a/Gopkg.lock b/Gopkg.lock index a37d7aeec1fa2..eddb6faafbf27 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -1,18 +1,6 @@ # This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. -[[projects]] - branch = "master" - digest = "1:b03d8c3ef961bcfbdc5ec25b2d667e10d91d5325d38707ca6655d81b8bb96a30" - name = "github.com/GoASTScanner/gas" - packages = [ - ".", - "rules", - ] - pruneopts = "UT" - revision = "a9de4d6c1589158e002cc336c495bf11fbf3ea06" - source = "github.com/golangci/gas" - [[projects]] branch = "master" digest = "1:da6b9c16fb5e97523f153981486c7541cf36543be2f246e258973d8e58a801dc" @@ -98,6 +86,14 @@ revision = "1adfc126b41513cc696b209667c8656ea7aac67c" version = "v1.0.0" +[[projects]] + digest = "1:bc38c7c481812e178d85160472e231c5e1c9a7f5845d67e23ee4e706933c10d8" + name = "github.com/golang/mock" + packages = ["gomock"] + pruneopts = "UT" + revision = "c34cdb4725f4c3844d095133c6e40e448b86589b" + version = "v1.1.1" + [[projects]] branch = "master" digest = "1:c173565780edcf5d43c5f983be0e9085266764465422d4ad230355abd2e0d252" @@ -144,6 +140,17 @@ pruneopts = "UT" revision = "2076e05ced53480baa8ba14a05b80a415bec9377" +[[projects]] + branch = "master" + digest = "1:bf573d0637989470dee90e11a6ea87b5de1ddb7a435334b80656b0df05b0630b" + name = "github.com/golangci/gosec" + packages = [ + ".", + "rules", + ] + pruneopts = "UT" + revision = "8afd9cbb6cfb34a3b4d4d5711bafdc6640ae892f" + [[projects]] branch = "master" digest = "1:bfaf14a1dd31e57f9b433739af5f0411558d9ba90566c7342c02da9a48ea8e75" @@ -450,6 +457,14 @@ pruneopts = "UT" revision = "4ec37c66abab2c7e02ae775328b2ff001c3f025a" +[[projects]] + branch = "master" + digest = "1:76ee51c3f468493aff39dbacc401e8831fbb765104cbf613b89bef01cf4bad70" + name = "golang.org/x/net" + packages = ["context"] + pruneopts = "UT" + revision = "8a410e7b638dca158bf9e766925842f6651ff828" + [[projects]] branch = "master" digest = "1:f188849a07aed244639654388dc775da034b17dab0890485e1e75c28e7a053ff" @@ -574,11 +589,10 @@ analyzer-name = "dep" analyzer-version = 1 input-imports = [ - "github.com/GoASTScanner/gas", - "github.com/GoASTScanner/gas/rules", "github.com/OpenPeeDeeP/depguard", "github.com/client9/misspell", "github.com/fatih/color", + "github.com/golang/mock/gomock", "github.com/golangci/check/cmd/structcheck", "github.com/golangci/check/cmd/varcheck", "github.com/golangci/go-misc/deadcode", @@ -586,6 +600,8 @@ "github.com/golangci/gocyclo/pkg/gocyclo", "github.com/golangci/gofmt/gofmt", "github.com/golangci/gofmt/goimports", + "github.com/golangci/gosec", + "github.com/golangci/gosec/rules", "github.com/golangci/govet", "github.com/golangci/ineffassign", "github.com/golangci/lint-1", diff --git a/Gopkg.toml b/Gopkg.toml index 58d844a6d45dc..a319946bca383 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -29,11 +29,6 @@ branch = "fix-crash-on-nil-constant" source = "github.com/golangci/unparam" -[[constraint]] - name = "github.com/GoASTScanner/gas" - branch = "master" - source = "github.com/golangci/gas" - [prune] go-tests = true unused-packages = true diff --git a/pkg/golinters/gas.go b/pkg/golinters/gas.go index 90f58db90679e..665e0ac77b009 100644 --- a/pkg/golinters/gas.go +++ b/pkg/golinters/gas.go @@ -8,10 +8,10 @@ import ( "log" "strconv" - "github.com/GoASTScanner/gas" - "github.com/GoASTScanner/gas/rules" "github.com/golangci/golangci-lint/pkg/lint/linter" "github.com/golangci/golangci-lint/pkg/result" + "github.com/golangci/gosec" + "github.com/golangci/gosec/rules" ) type Gosec struct{} @@ -25,10 +25,10 @@ func (Gosec) Desc() string { } func (lint Gosec) Run(ctx context.Context, lintCtx *linter.Context) ([]result.Issue, error) { - gasConfig := gas.NewConfig() + gasConfig := gosec.NewConfig() enabledRules := rules.Generate() logger := log.New(ioutil.Discard, "", 0) - analyzer := gas.NewAnalyzer(gasConfig, logger) + analyzer := gosec.NewAnalyzer(gasConfig, logger) analyzer.LoadRules(enabledRules.Builders()) analyzer.ProcessProgram(lintCtx.Program) diff --git a/vendor/github.com/GoASTScanner/gas/Dockerfile b/vendor/github.com/GoASTScanner/gas/Dockerfile deleted file mode 100644 index bbe12caad77fc..0000000000000 --- a/vendor/github.com/GoASTScanner/gas/Dockerfile +++ /dev/null @@ -1,8 +0,0 @@ -FROM golang:1.9.4-alpine3.7 - -ENV BIN=gas - -COPY build/*-linux-amd64 /go/bin/$BIN -COPY docker-entrypoint.sh /usr/local/bin - -ENTRYPOINT ["docker-entrypoint.sh"] diff --git a/vendor/github.com/GoASTScanner/gas/Makefile b/vendor/github.com/GoASTScanner/gas/Makefile deleted file mode 100644 index db55f0e14d817..0000000000000 --- a/vendor/github.com/GoASTScanner/gas/Makefile +++ /dev/null @@ -1,48 +0,0 @@ -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/ & -FMT_CMD = $(gofmt -s -l -w $(find . -type f -name '*.go' -not -path './vendor/*') | tee /dev/stderr) -IMAGE_REPO = docker.io - -default: - $(MAKE) bootstrap - $(MAKE) build - -test: bootstrap - test -z '$(FMT_CMD)' - go vet $(go list ./... | grep -v /vendor/) - golint -set_exit_status $(shell go list ./... | grep -v vendor) - gas ./... - ginkgo -r -v -bootstrap: - dep ensure -build: - go build -o $(BIN) ./cmd/gas/ -clean: - rm -rf build vendor - rm -f release image bootstrap $(BIN) -release: bootstrap -ifndef VERSION - $(error VERSION flag is not set. Run 'make release VERSION='.) -endif - @echo "Running build command..." - bash -c '\ - export GOOS=linux; export GOARCH=amd64; export CGO_ENABLED=0; $(BUILD_CMD) \ - wait \ - ' - touch release - -image: release - @echo "Building the Docker image..." - docker build -t $(IMAGE_REPO)/$(BIN):$(VERSION) . - docker tag $(IMAGE_REPO)/$(BIN):$(VERSION) $(IMAGE_REPO)/$(BIN):latest - touch image - -image-push: image - @echo "Pushing the Docker image..." - docker push $(IMAGE_REPO)/$(BIN):$(VERSION) - docker push $(IMAGE_REPO)/$(BIN):latest - -.PHONY: test build clean image-push - diff --git a/vendor/github.com/GoASTScanner/gas/rules/readfile.go b/vendor/github.com/GoASTScanner/gas/rules/readfile.go deleted file mode 100644 index d6c2186a8ecaa..0000000000000 --- a/vendor/github.com/GoASTScanner/gas/rules/readfile.go +++ /dev/null @@ -1,63 +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 rules - -import ( - "go/ast" - "go/types" - - "github.com/GoASTScanner/gas" -) - -type readfile struct { - gas.MetaData - gas.CallList -} - -// ID returns the identifier for this rule -func (r *readfile) ID() string { - return r.MetaData.ID -} - -// 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) { - 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 - } - } - } - } - return nil, nil -} - -// NewReadFile detects cases where we read files -func NewReadFile(id string, conf gas.Config) (gas.Rule, []ast.Node) { - rule := &readfile{ - CallList: gas.NewCallList(), - MetaData: gas.MetaData{ - ID: id, - What: "Potential file inclusion via variable", - Severity: gas.Medium, - Confidence: gas.High, - }, - } - rule.Add("io/ioutil", "ReadFile") - rule.Add("os", "Open") - return rule, []ast.Node{(*ast.CallExpr)(nil)} -} diff --git a/vendor/github.com/golang/mock/AUTHORS b/vendor/github.com/golang/mock/AUTHORS new file mode 100644 index 0000000000000..660b8ccc8ae00 --- /dev/null +++ b/vendor/github.com/golang/mock/AUTHORS @@ -0,0 +1,12 @@ +# This is the official list of GoMock authors for copyright purposes. +# This file is distinct from the CONTRIBUTORS files. +# See the latter for an explanation. + +# Names should be added to this file as +# Name or Organization +# The email address is not required for organizations. + +# Please keep the list sorted. + +Alex Reece +Google Inc. diff --git a/vendor/github.com/golang/mock/CONTRIBUTORS b/vendor/github.com/golang/mock/CONTRIBUTORS new file mode 100644 index 0000000000000..def849cab1bd4 --- /dev/null +++ b/vendor/github.com/golang/mock/CONTRIBUTORS @@ -0,0 +1,37 @@ +# This is the official list of people who can contribute (and typically +# have contributed) code to the gomock repository. +# The AUTHORS file lists the copyright holders; this file +# lists people. For example, Google employees are listed here +# but not in AUTHORS, because Google holds the copyright. +# +# The submission process automatically checks to make sure +# that people submitting code are listed in this file (by email address). +# +# Names should be added to this file only after verifying that +# the individual or the individual's organization has agreed to +# the appropriate Contributor License Agreement, found here: +# +# http://code.google.com/legal/individual-cla-v1.0.html +# http://code.google.com/legal/corporate-cla-v1.0.html +# +# The agreement for individuals can be filled out on the web. +# +# When adding J Random Contributor's name to this file, +# either J's name or J's organization's name should be +# added to the AUTHORS file, depending on whether the +# individual or corporate CLA was used. + +# Names should be added to this file like so: +# Name +# +# An entry with two email addresses specifies that the +# first address should be used in the submit logs and +# that the second address should be recognized as the +# same person when interacting with Rietveld. + +# Please keep the list sorted. + +Aaron Jacobs +Alex Reece +David Symonds +Ryan Barrett diff --git a/vendor/github.com/golang/mock/LICENSE b/vendor/github.com/golang/mock/LICENSE new file mode 100644 index 0000000000000..d645695673349 --- /dev/null +++ b/vendor/github.com/golang/mock/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/vendor/github.com/golang/mock/gomock/call.go b/vendor/github.com/golang/mock/gomock/call.go new file mode 100644 index 0000000000000..a3fa1ae419d14 --- /dev/null +++ b/vendor/github.com/golang/mock/gomock/call.go @@ -0,0 +1,428 @@ +// Copyright 2010 Google Inc. +// +// 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 gomock + +import ( + "fmt" + "reflect" + "strconv" + "strings" +) + +// Call represents an expected call to a mock. +type Call struct { + t TestReporter // for triggering test failures on invalid call setup + + receiver interface{} // the receiver of the method call + method string // the name of the method + methodType reflect.Type // the type of the method + args []Matcher // the args + origin string // file and line number of call setup + + preReqs []*Call // prerequisite calls + + // Expectations + minCalls, maxCalls int + + numCalls int // actual number made + + // actions are called when this Call is called. Each action gets the args and + // can set the return values by returning a non-nil slice. Actions run in the + // order they are created. + actions []func([]interface{}) []interface{} +} + +// newCall creates a *Call. It requires the method type in order to support +// unexported methods. +func newCall(t TestReporter, receiver interface{}, method string, methodType reflect.Type, args ...interface{}) *Call { + if h, ok := t.(testHelper); ok { + h.Helper() + } + + // TODO: check arity, types. + margs := make([]Matcher, len(args)) + for i, arg := range args { + if m, ok := arg.(Matcher); ok { + margs[i] = m + } else if arg == nil { + // Handle nil specially so that passing a nil interface value + // will match the typed nils of concrete args. + margs[i] = Nil() + } else { + margs[i] = Eq(arg) + } + } + + origin := callerInfo(3) + actions := []func([]interface{}) []interface{}{func([]interface{}) []interface{} { + // Synthesize the zero value for each of the return args' types. + rets := make([]interface{}, methodType.NumOut()) + for i := 0; i < methodType.NumOut(); i++ { + rets[i] = reflect.Zero(methodType.Out(i)).Interface() + } + return rets + }} + return &Call{t: t, receiver: receiver, method: method, methodType: methodType, + args: margs, origin: origin, minCalls: 1, maxCalls: 1, actions: actions} +} + +// AnyTimes allows the expectation to be called 0 or more times +func (c *Call) AnyTimes() *Call { + c.minCalls, c.maxCalls = 0, 1e8 // close enough to infinity + return c +} + +// MinTimes requires the call to occur at least n times. If AnyTimes or MaxTimes have not been called, MinTimes also +// sets the maximum number of calls to infinity. +func (c *Call) MinTimes(n int) *Call { + c.minCalls = n + if c.maxCalls == 1 { + c.maxCalls = 1e8 + } + return c +} + +// MaxTimes limits the number of calls to n times. If AnyTimes or MinTimes have not been called, MaxTimes also +// sets the minimum number of calls to 0. +func (c *Call) MaxTimes(n int) *Call { + c.maxCalls = n + if c.minCalls == 1 { + c.minCalls = 0 + } + return c +} + +// DoAndReturn declares the action to run when the call is matched. +// The return values from this function are returned by the mocked function. +// It takes an interface{} argument to support n-arity functions. +func (c *Call) DoAndReturn(f interface{}) *Call { + // TODO: Check arity and types here, rather than dying badly elsewhere. + v := reflect.ValueOf(f) + + c.addAction(func(args []interface{}) []interface{} { + vargs := make([]reflect.Value, len(args)) + ft := v.Type() + for i := 0; i < len(args); i++ { + if args[i] != nil { + vargs[i] = reflect.ValueOf(args[i]) + } else { + // Use the zero value for the arg. + vargs[i] = reflect.Zero(ft.In(i)) + } + } + vrets := v.Call(vargs) + rets := make([]interface{}, len(vrets)) + for i, ret := range vrets { + rets[i] = ret.Interface() + } + return rets + }) + return c +} + +// Do declares the action to run when the call is matched. The function's +// return values are ignored to retain backward compatibility. To use the +// return values call DoAndReturn. +// It takes an interface{} argument to support n-arity functions. +func (c *Call) Do(f interface{}) *Call { + // TODO: Check arity and types here, rather than dying badly elsewhere. + v := reflect.ValueOf(f) + + c.addAction(func(args []interface{}) []interface{} { + vargs := make([]reflect.Value, len(args)) + ft := v.Type() + for i := 0; i < len(args); i++ { + if args[i] != nil { + vargs[i] = reflect.ValueOf(args[i]) + } else { + // Use the zero value for the arg. + vargs[i] = reflect.Zero(ft.In(i)) + } + } + v.Call(vargs) + return nil + }) + return c +} + +// Return declares the values to be returned by the mocked function call. +func (c *Call) Return(rets ...interface{}) *Call { + if h, ok := c.t.(testHelper); ok { + h.Helper() + } + + mt := c.methodType + if len(rets) != mt.NumOut() { + c.t.Fatalf("wrong number of arguments to Return for %T.%v: got %d, want %d [%s]", + c.receiver, c.method, len(rets), mt.NumOut(), c.origin) + } + for i, ret := range rets { + if got, want := reflect.TypeOf(ret), mt.Out(i); got == want { + // Identical types; nothing to do. + } else if got == nil { + // Nil needs special handling. + switch want.Kind() { + case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice: + // ok + default: + c.t.Fatalf("argument %d to Return for %T.%v is nil, but %v is not nillable [%s]", + i, c.receiver, c.method, want, c.origin) + } + } else if got.AssignableTo(want) { + // Assignable type relation. Make the assignment now so that the generated code + // can return the values with a type assertion. + v := reflect.New(want).Elem() + v.Set(reflect.ValueOf(ret)) + rets[i] = v.Interface() + } else { + c.t.Fatalf("wrong type of argument %d to Return for %T.%v: %v is not assignable to %v [%s]", + i, c.receiver, c.method, got, want, c.origin) + } + } + + c.addAction(func([]interface{}) []interface{} { + return rets + }) + + return c +} + +// Times declares the exact number of times a function call is expected to be executed. +func (c *Call) Times(n int) *Call { + c.minCalls, c.maxCalls = n, n + return c +} + +// SetArg declares an action that will set the nth argument's value, +// indirected through a pointer. Or, in the case of a slice, SetArg +// will copy value's elements into the nth argument. +func (c *Call) SetArg(n int, value interface{}) *Call { + if h, ok := c.t.(testHelper); ok { + h.Helper() + } + + mt := c.methodType + // TODO: This will break on variadic methods. + // We will need to check those at invocation time. + if n < 0 || n >= mt.NumIn() { + c.t.Fatalf("SetArg(%d, ...) called for a method with %d args [%s]", + n, mt.NumIn(), c.origin) + } + // Permit setting argument through an interface. + // In the interface case, we don't (nay, can't) check the type here. + at := mt.In(n) + switch at.Kind() { + case reflect.Ptr: + dt := at.Elem() + if vt := reflect.TypeOf(value); !vt.AssignableTo(dt) { + c.t.Fatalf("SetArg(%d, ...) argument is a %v, not assignable to %v [%s]", + n, vt, dt, c.origin) + } + case reflect.Interface: + // nothing to do + case reflect.Slice: + // nothing to do + default: + c.t.Fatalf("SetArg(%d, ...) referring to argument of non-pointer non-interface non-slice type %v [%s]", + n, at, c.origin) + } + + c.addAction(func(args []interface{}) []interface{} { + v := reflect.ValueOf(value) + switch reflect.TypeOf(args[n]).Kind() { + case reflect.Slice: + setSlice(args[n], v) + default: + reflect.ValueOf(args[n]).Elem().Set(v) + } + return nil + }) + return c +} + +// isPreReq returns true if other is a direct or indirect prerequisite to c. +func (c *Call) isPreReq(other *Call) bool { + for _, preReq := range c.preReqs { + if other == preReq || preReq.isPreReq(other) { + return true + } + } + return false +} + +// After declares that the call may only match after preReq has been exhausted. +func (c *Call) After(preReq *Call) *Call { + if h, ok := c.t.(testHelper); ok { + h.Helper() + } + + if c == preReq { + c.t.Fatalf("A call isn't allowed to be its own prerequisite") + } + if preReq.isPreReq(c) { + c.t.Fatalf("Loop in call order: %v is a prerequisite to %v (possibly indirectly).", c, preReq) + } + + c.preReqs = append(c.preReqs, preReq) + return c +} + +// Returns true if the minimum number of calls have been made. +func (c *Call) satisfied() bool { + return c.numCalls >= c.minCalls +} + +// Returns true iff the maximum number of calls have been made. +func (c *Call) exhausted() bool { + return c.numCalls >= c.maxCalls +} + +func (c *Call) String() string { + args := make([]string, len(c.args)) + for i, arg := range c.args { + args[i] = arg.String() + } + arguments := strings.Join(args, ", ") + return fmt.Sprintf("%T.%v(%s) %s", c.receiver, c.method, arguments, c.origin) +} + +// Tests if the given call matches the expected call. +// If yes, returns nil. If no, returns error with message explaining why it does not match. +func (c *Call) matches(args []interface{}) error { + if !c.methodType.IsVariadic() { + if len(args) != len(c.args) { + return fmt.Errorf("Expected call at %s has the wrong number of arguments. Got: %d, want: %d", + c.origin, len(args), len(c.args)) + } + + for i, m := range c.args { + if !m.Matches(args[i]) { + return fmt.Errorf("Expected call at %s doesn't match the argument at index %s.\nGot: %v\nWant: %v", + c.origin, strconv.Itoa(i), args[i], m) + } + } + } else { + if len(c.args) < c.methodType.NumIn()-1 { + return fmt.Errorf("Expected call at %s has the wrong number of matchers. Got: %d, want: %d", + c.origin, len(c.args), c.methodType.NumIn()-1) + } + if len(c.args) != c.methodType.NumIn() && len(args) != len(c.args) { + return fmt.Errorf("Expected call at %s has the wrong number of arguments. Got: %d, want: %d", + c.origin, len(args), len(c.args)) + } + if len(args) < len(c.args)-1 { + return fmt.Errorf("Expected call at %s has the wrong number of arguments. Got: %d, want: greater than or equal to %d", + c.origin, len(args), len(c.args)-1) + } + + for i, m := range c.args { + if i < c.methodType.NumIn()-1 { + // Non-variadic args + if !m.Matches(args[i]) { + return fmt.Errorf("Expected call at %s doesn't match the argument at index %s.\nGot: %v\nWant: %v", + c.origin, strconv.Itoa(i), args[i], m) + } + continue + } + // The last arg has a possibility of a variadic argument, so let it branch + + // sample: Foo(a int, b int, c ...int) + if i < len(c.args) && i < len(args) { + if m.Matches(args[i]) { + // Got Foo(a, b, c) want Foo(matcherA, matcherB, gomock.Any()) + // Got Foo(a, b, c) want Foo(matcherA, matcherB, someSliceMatcher) + // Got Foo(a, b, c) want Foo(matcherA, matcherB, matcherC) + // Got Foo(a, b) want Foo(matcherA, matcherB) + // Got Foo(a, b, c, d) want Foo(matcherA, matcherB, matcherC, matcherD) + continue + } + } + + // The number of actual args don't match the number of matchers, + // or the last matcher is a slice and the last arg is not. + // If this function still matches it is because the last matcher + // matches all the remaining arguments or the lack of any. + // Convert the remaining arguments, if any, into a slice of the + // expected type. + vargsType := c.methodType.In(c.methodType.NumIn() - 1) + vargs := reflect.MakeSlice(vargsType, 0, len(args)-i) + for _, arg := range args[i:] { + vargs = reflect.Append(vargs, reflect.ValueOf(arg)) + } + if m.Matches(vargs.Interface()) { + // Got Foo(a, b, c, d, e) want Foo(matcherA, matcherB, gomock.Any()) + // Got Foo(a, b, c, d, e) want Foo(matcherA, matcherB, someSliceMatcher) + // Got Foo(a, b) want Foo(matcherA, matcherB, gomock.Any()) + // Got Foo(a, b) want Foo(matcherA, matcherB, someEmptySliceMatcher) + break + } + // Wrong number of matchers or not match. Fail. + // Got Foo(a, b) want Foo(matcherA, matcherB, matcherC, matcherD) + // Got Foo(a, b, c) want Foo(matcherA, matcherB, matcherC, matcherD) + // Got Foo(a, b, c, d) want Foo(matcherA, matcherB, matcherC, matcherD, matcherE) + // Got Foo(a, b, c, d, e) want Foo(matcherA, matcherB, matcherC, matcherD) + // Got Foo(a, b, c) want Foo(matcherA, matcherB) + return fmt.Errorf("Expected call at %s doesn't match the argument at index %s.\nGot: %v\nWant: %v", + c.origin, strconv.Itoa(i), args[i:], c.args[i]) + + } + } + + // Check that all prerequisite calls have been satisfied. + for _, preReqCall := range c.preReqs { + if !preReqCall.satisfied() { + return fmt.Errorf("Expected call at %s doesn't have a prerequisite call satisfied:\n%v\nshould be called before:\n%v", + c.origin, preReqCall, c) + } + } + + // Check that the call is not exhausted. + if c.exhausted() { + return fmt.Errorf("Expected call at %s has already been called the max number of times.", c.origin) + } + + return nil +} + +// dropPrereqs tells the expected Call to not re-check prerequisite calls any +// longer, and to return its current set. +func (c *Call) dropPrereqs() (preReqs []*Call) { + preReqs = c.preReqs + c.preReqs = nil + return +} + +func (c *Call) call(args []interface{}) []func([]interface{}) []interface{} { + c.numCalls++ + return c.actions +} + +// InOrder declares that the given calls should occur in order. +func InOrder(calls ...*Call) { + for i := 1; i < len(calls); i++ { + calls[i].After(calls[i-1]) + } +} + +func setSlice(arg interface{}, v reflect.Value) { + va := reflect.ValueOf(arg) + for i := 0; i < v.Len(); i++ { + va.Index(i).Set(v.Index(i)) + } +} + +func (c *Call) addAction(action func([]interface{}) []interface{}) { + c.actions = append(c.actions, action) +} diff --git a/vendor/github.com/golang/mock/gomock/callset.go b/vendor/github.com/golang/mock/gomock/callset.go new file mode 100644 index 0000000000000..c44a8a585b32e --- /dev/null +++ b/vendor/github.com/golang/mock/gomock/callset.go @@ -0,0 +1,108 @@ +// Copyright 2011 Google Inc. +// +// 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 gomock + +import ( + "bytes" + "fmt" +) + +// callSet represents a set of expected calls, indexed by receiver and method +// name. +type callSet struct { + // Calls that are still expected. + expected map[callSetKey][]*Call + // Calls that have been exhausted. + exhausted map[callSetKey][]*Call +} + +// callSetKey is the key in the maps in callSet +type callSetKey struct { + receiver interface{} + fname string +} + +func newCallSet() *callSet { + return &callSet{make(map[callSetKey][]*Call), make(map[callSetKey][]*Call)} +} + +// Add adds a new expected call. +func (cs callSet) Add(call *Call) { + key := callSetKey{call.receiver, call.method} + m := cs.expected + if call.exhausted() { + m = cs.exhausted + } + m[key] = append(m[key], call) +} + +// Remove removes an expected call. +func (cs callSet) Remove(call *Call) { + key := callSetKey{call.receiver, call.method} + calls := cs.expected[key] + for i, c := range calls { + if c == call { + // maintain order for remaining calls + cs.expected[key] = append(calls[:i], calls[i+1:]...) + cs.exhausted[key] = append(cs.exhausted[key], call) + break + } + } +} + +// FindMatch searches for a matching call. Returns error with explanation message if no call matched. +func (cs callSet) FindMatch(receiver interface{}, method string, args []interface{}) (*Call, error) { + key := callSetKey{receiver, method} + + // Search through the expected calls. + expected := cs.expected[key] + var callsErrors bytes.Buffer + for _, call := range expected { + err := call.matches(args) + if err != nil { + fmt.Fprintf(&callsErrors, "\n%v", err) + } else { + return call, nil + } + } + + // If we haven't found a match then search through the exhausted calls so we + // get useful error messages. + exhausted := cs.exhausted[key] + for _, call := range exhausted { + if err := call.matches(args); err != nil { + fmt.Fprintf(&callsErrors, "\n%v", err) + } + } + + if len(expected)+len(exhausted) == 0 { + fmt.Fprintf(&callsErrors, "there are no expected calls of the method %q for that receiver", method) + } + + return nil, fmt.Errorf(callsErrors.String()) +} + +// Failures returns the calls that are not satisfied. +func (cs callSet) Failures() []*Call { + failures := make([]*Call, 0, len(cs.expected)) + for _, calls := range cs.expected { + for _, call := range calls { + if !call.satisfied() { + failures = append(failures, call) + } + } + } + return failures +} diff --git a/vendor/github.com/golang/mock/gomock/controller.go b/vendor/github.com/golang/mock/gomock/controller.go new file mode 100644 index 0000000000000..a7b79188bc8ce --- /dev/null +++ b/vendor/github.com/golang/mock/gomock/controller.go @@ -0,0 +1,217 @@ +// Copyright 2010 Google Inc. +// +// 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. + +// GoMock - a mock framework for Go. +// +// Standard usage: +// (1) Define an interface that you wish to mock. +// type MyInterface interface { +// SomeMethod(x int64, y string) +// } +// (2) Use mockgen to generate a mock from the interface. +// (3) Use the mock in a test: +// func TestMyThing(t *testing.T) { +// mockCtrl := gomock.NewController(t) +// defer mockCtrl.Finish() +// +// mockObj := something.NewMockMyInterface(mockCtrl) +// mockObj.EXPECT().SomeMethod(4, "blah") +// // pass mockObj to a real object and play with it. +// } +// +// By default, expected calls are not enforced to run in any particular order. +// Call order dependency can be enforced by use of InOrder and/or Call.After. +// Call.After can create more varied call order dependencies, but InOrder is +// often more convenient. +// +// The following examples create equivalent call order dependencies. +// +// Example of using Call.After to chain expected call order: +// +// firstCall := mockObj.EXPECT().SomeMethod(1, "first") +// secondCall := mockObj.EXPECT().SomeMethod(2, "second").After(firstCall) +// mockObj.EXPECT().SomeMethod(3, "third").After(secondCall) +// +// Example of using InOrder to declare expected call order: +// +// gomock.InOrder( +// mockObj.EXPECT().SomeMethod(1, "first"), +// mockObj.EXPECT().SomeMethod(2, "second"), +// mockObj.EXPECT().SomeMethod(3, "third"), +// ) +// +// TODO: +// - Handle different argument/return types (e.g. ..., chan, map, interface). +package gomock + +import ( + "fmt" + "golang.org/x/net/context" + "reflect" + "runtime" + "sync" +) + +// A TestReporter is something that can be used to report test failures. +// It is satisfied by the standard library's *testing.T. +type TestReporter interface { + Errorf(format string, args ...interface{}) + Fatalf(format string, args ...interface{}) +} + +// A Controller represents the top-level control of a mock ecosystem. +// It defines the scope and lifetime of mock objects, as well as their expectations. +// It is safe to call Controller's methods from multiple goroutines. +type Controller struct { + mu sync.Mutex + t TestReporter + expectedCalls *callSet + finished bool +} + +func NewController(t TestReporter) *Controller { + return &Controller{ + t: t, + expectedCalls: newCallSet(), + } +} + +type cancelReporter struct { + t TestReporter + cancel func() +} + +func (r *cancelReporter) Errorf(format string, args ...interface{}) { r.t.Errorf(format, args...) } +func (r *cancelReporter) Fatalf(format string, args ...interface{}) { + defer r.cancel() + r.t.Fatalf(format, args...) +} + +// WithContext returns a new Controller and a Context, which is cancelled on any +// fatal failure. +func WithContext(ctx context.Context, t TestReporter) (*Controller, context.Context) { + ctx, cancel := context.WithCancel(ctx) + return NewController(&cancelReporter{t, cancel}), ctx +} + +func (ctrl *Controller) RecordCall(receiver interface{}, method string, args ...interface{}) *Call { + if h, ok := ctrl.t.(testHelper); ok { + h.Helper() + } + + recv := reflect.ValueOf(receiver) + for i := 0; i < recv.Type().NumMethod(); i++ { + if recv.Type().Method(i).Name == method { + return ctrl.RecordCallWithMethodType(receiver, method, recv.Method(i).Type(), args...) + } + } + ctrl.t.Fatalf("gomock: failed finding method %s on %T", method, receiver) + panic("unreachable") +} + +func (ctrl *Controller) RecordCallWithMethodType(receiver interface{}, method string, methodType reflect.Type, args ...interface{}) *Call { + if h, ok := ctrl.t.(testHelper); ok { + h.Helper() + } + + call := newCall(ctrl.t, receiver, method, methodType, args...) + + ctrl.mu.Lock() + defer ctrl.mu.Unlock() + ctrl.expectedCalls.Add(call) + + return call +} + +func (ctrl *Controller) Call(receiver interface{}, method string, args ...interface{}) []interface{} { + if h, ok := ctrl.t.(testHelper); ok { + h.Helper() + } + + // Nest this code so we can use defer to make sure the lock is released. + actions := func() []func([]interface{}) []interface{} { + ctrl.mu.Lock() + defer ctrl.mu.Unlock() + + expected, err := ctrl.expectedCalls.FindMatch(receiver, method, args) + if err != nil { + origin := callerInfo(2) + ctrl.t.Fatalf("Unexpected call to %T.%v(%v) at %s because: %s", receiver, method, args, origin, err) + } + + // Two things happen here: + // * the matching call no longer needs to check prerequite calls, + // * and the prerequite calls are no longer expected, so remove them. + preReqCalls := expected.dropPrereqs() + for _, preReqCall := range preReqCalls { + ctrl.expectedCalls.Remove(preReqCall) + } + + actions := expected.call(args) + if expected.exhausted() { + ctrl.expectedCalls.Remove(expected) + } + return actions + }() + + var rets []interface{} + for _, action := range actions { + if r := action(args); r != nil { + rets = r + } + } + + return rets +} + +func (ctrl *Controller) Finish() { + if h, ok := ctrl.t.(testHelper); ok { + h.Helper() + } + + ctrl.mu.Lock() + defer ctrl.mu.Unlock() + + if ctrl.finished { + ctrl.t.Fatalf("Controller.Finish was called more than once. It has to be called exactly once.") + } + ctrl.finished = true + + // If we're currently panicking, probably because this is a deferred call, + // pass through the panic. + if err := recover(); err != nil { + panic(err) + } + + // Check that all remaining expected calls are satisfied. + failures := ctrl.expectedCalls.Failures() + for _, call := range failures { + ctrl.t.Errorf("missing call(s) to %v", call) + } + if len(failures) != 0 { + ctrl.t.Fatalf("aborting test due to missing call(s)") + } +} + +func callerInfo(skip int) string { + if _, file, line, ok := runtime.Caller(skip + 1); ok { + return fmt.Sprintf("%s:%d", file, line) + } + return "unknown file" +} + +type testHelper interface { + TestReporter + Helper() +} diff --git a/vendor/github.com/golang/mock/gomock/matchers.go b/vendor/github.com/golang/mock/gomock/matchers.go new file mode 100644 index 0000000000000..e8b1ddccf03bb --- /dev/null +++ b/vendor/github.com/golang/mock/gomock/matchers.go @@ -0,0 +1,99 @@ +//go:generate mockgen -destination mock_matcher/mock_matcher.go github.com/golang/mock/gomock Matcher + +// Copyright 2010 Google Inc. +// +// 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 gomock + +import ( + "fmt" + "reflect" +) + +// A Matcher is a representation of a class of values. +// It is used to represent the valid or expected arguments to a mocked method. +type Matcher interface { + // Matches returns whether x is a match. + Matches(x interface{}) bool + + // String describes what the matcher matches. + String() string +} + +type anyMatcher struct{} + +func (anyMatcher) Matches(x interface{}) bool { + return true +} + +func (anyMatcher) String() string { + return "is anything" +} + +type eqMatcher struct { + x interface{} +} + +func (e eqMatcher) Matches(x interface{}) bool { + return reflect.DeepEqual(e.x, x) +} + +func (e eqMatcher) String() string { + return fmt.Sprintf("is equal to %v", e.x) +} + +type nilMatcher struct{} + +func (nilMatcher) Matches(x interface{}) bool { + if x == nil { + return true + } + + v := reflect.ValueOf(x) + switch v.Kind() { + case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, + reflect.Ptr, reflect.Slice: + return v.IsNil() + } + + return false +} + +func (nilMatcher) String() string { + return "is nil" +} + +type notMatcher struct { + m Matcher +} + +func (n notMatcher) Matches(x interface{}) bool { + return !n.m.Matches(x) +} + +func (n notMatcher) String() string { + // TODO: Improve this if we add a NotString method to the Matcher interface. + return "not(" + n.m.String() + ")" +} + +// Constructors +func Any() Matcher { return anyMatcher{} } +func Eq(x interface{}) Matcher { return eqMatcher{x} } +func Nil() Matcher { return nilMatcher{} } +func Not(x interface{}) Matcher { + if m, ok := x.(Matcher); ok { + return notMatcher{m} + } + return notMatcher{Eq(x)} +} diff --git a/vendor/github.com/GoASTScanner/gas/.gitignore b/vendor/github.com/golangci/gosec/.gitignore similarity index 98% rename from vendor/github.com/GoASTScanner/gas/.gitignore rename to vendor/github.com/golangci/gosec/.gitignore index cbdc5a71bcf8d..ee144d51b843e 100644 --- a/vendor/github.com/GoASTScanner/gas/.gitignore +++ b/vendor/github.com/golangci/gosec/.gitignore @@ -8,6 +8,7 @@ _obj _test vendor +dist # Architecture specific extensions/prefixes *.[568vq] diff --git a/vendor/github.com/golangci/gosec/.goreleaser.yml b/vendor/github.com/golangci/gosec/.goreleaser.yml new file mode 100644 index 0000000000000..3112dc8dedf45 --- /dev/null +++ b/vendor/github.com/golangci/gosec/.goreleaser.yml @@ -0,0 +1,17 @@ +builds: + - main : ./cmd/gosec/ + binary: gosec + goos: + - darwin + - linux + - windows + goarch: + - amd64 + ldflags: -X main.Version={{.Version}} -X main.GitTag={{.Tag}} -X main.BuildDate={{.Date}} + env: + - CGO_ENABLED=0 + +archive: + files: + - README.md + - LICENSE.txt diff --git a/vendor/github.com/GoASTScanner/gas/.travis.yml b/vendor/github.com/golangci/gosec/.travis.yml similarity index 84% rename from vendor/github.com/GoASTScanner/gas/.travis.yml rename to vendor/github.com/golangci/gosec/.travis.yml index 99640c0fc8809..6a6a96eb64837 100644 --- a/vendor/github.com/GoASTScanner/gas/.travis.yml +++ b/vendor/github.com/golangci/gosec/.travis.yml @@ -1,7 +1,6 @@ language: go go: - - 1.8 - 1.9 - "1.10" - tip @@ -12,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/GoASTScanner/gas/cmd/gas/... + - go get -u github.com/golangci/gosec/cmd/gosec/... - go get -v -t ./... - export PATH=$PATH:$HOME/gopath/bin diff --git a/vendor/github.com/golangci/gosec/Dockerfile b/vendor/github.com/golangci/gosec/Dockerfile new file mode 100644 index 0000000000000..8bdf4313f4e46 --- /dev/null +++ b/vendor/github.com/golangci/gosec/Dockerfile @@ -0,0 +1,10 @@ +FROM golang:1.10.3-alpine3.8 + +ENV BIN=gosec +ENV GOROOT=/usr/local/go +ENV GOPATH=/go + +COPY $BIN /go/bin/$BIN +COPY docker-entrypoint.sh /usr/local/bin + +ENTRYPOINT ["docker-entrypoint.sh"] diff --git a/vendor/github.com/GoASTScanner/gas/Gopkg.lock b/vendor/github.com/golangci/gosec/Gopkg.lock similarity index 66% rename from vendor/github.com/GoASTScanner/gas/Gopkg.lock rename to vendor/github.com/golangci/gosec/Gopkg.lock index 3887d0659a328..ff4f2ac7b894d 100644 --- a/vendor/github.com/GoASTScanner/gas/Gopkg.lock +++ b/vendor/github.com/golangci/gosec/Gopkg.lock @@ -2,17 +2,22 @@ [[projects]] + digest = "1:39170dcf72d0ac5933791daaf27a80782c24e9946cdc60fe98928d9429a9726d" name = "github.com/kisielk/gotool" packages = ["."] + pruneopts = "UT" revision = "0de1eaf82fa3f583ce21fde859f1e7e0c5e9b220" [[projects]] branch = "master" + digest = "1:bdb092d0984bf77804e133403f739ad84b16abaa256e21f5e7b88aabbb6d546b" name = "github.com/mozilla/tls-observatory" packages = ["constants"] + pruneopts = "UT" revision = "8791a200eb40f8625a152bfb8336171305f5f35c" [[projects]] + digest = "1:0a32435e3f12b75f2c0cd806c5b21fb92e29f70e5f76880dc852bba5e10f6585" name = "github.com/nbutton23/zxcvbn-go" packages = [ ".", @@ -23,11 +28,13 @@ "match", "matching", "scoring", - "utils/math" + "utils/math", ] + pruneopts = "UT" revision = "a22cb81b2ecdde8b68e9ffb8824731cbf88e1de4" [[projects]] + digest = "1:e54fe200d15850589f578095e5b23ed0afb8d44fb39122e63b5195cbd3858f30" name = "github.com/onsi/ginkgo" packages = [ ".", @@ -47,11 +54,13 @@ "reporters/stenographer", "reporters/stenographer/support/go-colorable", "reporters/stenographer/support/go-isatty", - "types" + "types", ] + pruneopts = "UT" revision = "11459a886d9cd66b319dac7ef1e917ee221372c9" [[projects]] + digest = "1:e340739c2403b0e6ee006e83c375754f44c1a483b695eff1b588acf8c4824925" name = "github.com/onsi/gomega" packages = [ ".", @@ -65,31 +74,39 @@ "matchers/support/goraph/edge", "matchers/support/goraph/node", "matchers/support/goraph/util", - "types" + "types", ] + pruneopts = "UT" revision = "dcabb60a477c2b6f456df65037cb6708210fbb02" [[projects]] branch = "master" + digest = "1:5b92d232e81c3e8eec282c92dcaa2e0e1ad3c23157be19a01b3e33f7e6e8d137" name = "github.com/ryanuber/go-glob" packages = ["."] + pruneopts = "UT" revision = "256dc444b735e061061cf46c809487313d5b0065" [[projects]] + digest = "1:499075870f4939e64e9d93c84c5fdf9b6253ec6e89c5dcb0a69f91292d6a2b30" name = "golang.org/x/net" packages = [ "html", "html/atom", - "html/charset" + "html/charset", ] + pruneopts = "UT" revision = "8351a756f30f1297fe94bbf4b767ec589c6ea6d0" [[projects]] + digest = "1:dae112b8ead03c5ae8106611d0788be212309815b1885ff1667bd3a41d509a4e" name = "golang.org/x/sys" packages = ["unix"] + pruneopts = "UT" revision = "164713f0dfcec4e80be8b53e1f0811f5f0d84578" [[projects]] + digest = "1:387e284158b231a5993cd01407562fc211f076a8904821db6993cf8dbf57b948" name = "golang.org/x/text" packages = [ "encoding", @@ -108,27 +125,41 @@ "language", "runes", "transform", - "unicode/cldr" + "unicode/cldr", ] + pruneopts = "UT" revision = "1cbadb444a806fd9430d14ad08967ed91da4fa0a" [[projects]] + digest = "1:96b9641eaaf0d03defe4e63d05e4711bf8066c543d4de838438244955811ff17" name = "golang.org/x/tools" packages = [ "go/ast/astutil", "go/buildutil", - "go/loader" + "go/loader", ] + pruneopts = "UT" revision = "e531a2a1c15f94033f6fa87666caeb19a688175f" [[projects]] + digest = "1:6570992c02a2137a20be83990a979b6fe892e20ecdc6b756449989b2a7efb8ae" name = "gopkg.in/yaml.v2" packages = ["."] + pruneopts = "UT" revision = "eb3733d160e74a9c7e442f435eb3bea458e1d19f" [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "706e049cd8b8db8705af09e7a375a999d01373a409beadc850c80d64de9849fd" + input-imports = [ + "github.com/kisielk/gotool", + "github.com/mozilla/tls-observatory/constants", + "github.com/nbutton23/zxcvbn-go", + "github.com/onsi/ginkgo", + "github.com/onsi/gomega", + "github.com/ryanuber/go-glob", + "golang.org/x/tools/go/loader", + "gopkg.in/yaml.v2", + ] solver-name = "gps-cdcl" solver-version = 1 diff --git a/vendor/github.com/GoASTScanner/gas/Gopkg.toml b/vendor/github.com/golangci/gosec/Gopkg.toml similarity index 100% rename from vendor/github.com/GoASTScanner/gas/Gopkg.toml rename to vendor/github.com/golangci/gosec/Gopkg.toml diff --git a/vendor/github.com/GoASTScanner/gas/LICENSE.txt b/vendor/github.com/golangci/gosec/LICENSE.txt similarity index 100% rename from vendor/github.com/GoASTScanner/gas/LICENSE.txt rename to vendor/github.com/golangci/gosec/LICENSE.txt diff --git a/vendor/github.com/golangci/gosec/Makefile b/vendor/github.com/golangci/gosec/Makefile new file mode 100644 index 0000000000000..1aca3df65683f --- /dev/null +++ b/vendor/github.com/golangci/gosec/Makefile @@ -0,0 +1,48 @@ +GIT_TAG?= $(shell git describe --always --tags) +BIN = gosec +FMT_CMD = $(gofmt -s -l -w $(find . -type f -name '*.go' -not -path './vendor/*') | tee /dev/stderr) +IMAGE_REPO = securego +BUILDFLAGS := '' +CGO_ENABLED = 0 + +default: + $(MAKE) bootstrap + $(MAKE) build + +bootstrap: + dep ensure + +test: bootstrap + test -z '$(FMT_CMD)' + go vet $(go list ./... | grep -v /vendor/) + golint -set_exit_status $(shell go list ./... | grep -v vendor) + gosec ./... + ginkgo -r -v + +build: + go build -o $(BIN) ./cmd/gosec/ + +clean: + rm -rf build vendor dist + rm -f release image bootstrap $(BIN) + +release: bootstrap + @echo "Releasing the gosec binary..." + goreleaser release + +build-linux: + CGO_ENABLED=$(CGO_ENABLED) GOOS=linux GOARCH=amd64 go build -ldflags $(BUILDFLAGS) -o $(BIN) ./cmd/gosec/ + +image: build-linux + @echo "Building the Docker image..." + docker build -t $(IMAGE_REPO)/$(BIN):$(GIT_TAG) . + docker tag $(IMAGE_REPO)/$(BIN):$(GIT_TAG) $(IMAGE_REPO)/$(BIN):latest + touch image + +image-push: image + @echo "Pushing the Docker image..." + docker push $(IMAGE_REPO)/$(BIN):$(GIT_TAG) + docker push $(IMAGE_REPO)/$(BIN):latest + +.PHONY: test build clean release image image-push + diff --git a/vendor/github.com/GoASTScanner/gas/README.md b/vendor/github.com/golangci/gosec/README.md similarity index 55% rename from vendor/github.com/GoASTScanner/gas/README.md rename to vendor/github.com/golangci/gosec/README.md index 5646d9b8908e3..f161f1159ff3e 100644 --- a/vendor/github.com/GoASTScanner/gas/README.md +++ b/vendor/github.com/golangci/gosec/README.md @@ -1,6 +1,6 @@ -## GAS - Go AST Scanner +## gosec -Golang Security Checker Inspects source code for security problems by scanning the Go AST. @@ -12,26 +12,25 @@ You may obtain a copy of the License [here](http://www.apache.org/licenses/LICEN ### Project status -[![Build Status](https://travis-ci.org/GoASTScanner/gas.svg?branch=master)](https://travis-ci.org/GoASTScanner/gas) -[![GoDoc](https://godoc.org/github.com/GoASTScanner/gas?status.svg)](https://godoc.org/github.com/GoASTScanner/gas) +[![Build Status](https://travis-ci.org/securego/gosec.svg?branch=master)](https://travis-ci.org/securego/gosec) +[![GoDoc](https://godoc.org/github.com/golangci/gosec?status.svg)](https://godoc.org/github.com/golangci/gosec) +[![Slack](http://securego.herokuapp.com/badge.svg)](http://securego.herokuapp.com) -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/...` +`$ go get github.com/golangci/gosec/cmd/gosec/...` ### Usage -Gas can be configured to only run a subset of rules, to exclude certain file +Gosec can be configured to only run a subset of rules, to exclude certain file paths, and produce reports in different formats. By default all rules will be run against the supplied input files. To recursively scan from the current directory you can supply './...' as the input argument. #### Selecting rules -By default Gas will run all rules against the supplied file paths. It is however possible to select a subset of rules to run via the '-include=' flag, +By default gosec will run all rules against the supplied file paths. It is however possible to select a subset of rules to run via the '-include=' flag, or to specify a set of rules to explicitly exclude using the '-exclude=' flag. ##### Available rules @@ -50,7 +49,8 @@ or to specify a set of rules to explicitly exclude using the '-exclude=' flag. - G302: Poor file permisions used with chmod - G303: Creating tempfile using a predictable path - G304: File path provided as taint input - - G401: Detect the usage of DES, RC4, or MD5 + - G305: File traversal when extracting zip archive + - G401: Detect the usage of DES, RC4, MD5 or SHA1 - G402: Look for bad TLS connection settings - G403: Ensure minimum RSA key length of 2048 bits - G404: Insecure random number source (rand) @@ -58,27 +58,28 @@ or to specify a set of rules to explicitly exclude using the '-exclude=' flag. - G502: Import blacklist: crypto/des - G503: Import blacklist: crypto/rc4 - G504: Import blacklist: net/http/cgi + - G505: Import blacklist: crypto/sha1 ``` # Run a specific set of rules -$ gas -include=G101,G203,G401 ./... +$ gosec -include=G101,G203,G401 ./... # Run everything except for rule G303 -$ gas -exclude=G303 ./... +$ gosec -exclude=G303 ./... ``` #### Excluding files: -Gas will ignore dependencies in your vendor directory any files +gosec will ignore dependencies in your vendor directory any files that are not considered build artifacts by the compiler (so test files). #### Annotating code -As with all automated detection tools there will be cases of false positives. In cases where Gas reports a failure that has been manually verified as being safe it is possible to annotate the code with a '#nosec' comment. +As with all automated detection tools there will be cases of false positives. In cases where gosec reports a failure that has been manually verified as being safe it is possible to annotate the code with a '#nosec' comment. -The annotation causes Gas to stop processing any further nodes within the -AST so can apply to a whole block or more granularly to a single expression. +The annotation causes gosec to stop processing any further nodes within the +AST so can apply to a whole block or more granularly to a single expression. ```go @@ -96,31 +97,33 @@ func main(){ ``` +When a specific false positive has been identified and verified as safe, you may wish to suppress only that single rule (or a specific set of rules) within a section of code, while continuing to scan for other problems. To do this, you can list the rule(s) to be suppressed within the `#nosec` annotation, e.g: `/* #nosec G401 */` or `// #nosec G201 G202 G203 ` + In some cases you may also want to revisit places where #nosec annotations have been used. To run the scanner and ignore any #nosec annotations you can do the following: ``` -$ gas -nosec=true ./... +$ gosec -nosec=true ./... ``` #### Build tags -Gas is able to pass your [Go build tags](https://golang.org/pkg/go/build/) to the analyzer. +gosec is able to pass your [Go build tags](https://golang.org/pkg/go/build/) to the analyzer. They can be provided as a comma separated list as follows: ``` -$ gas -tag debug,ignore ./... +$ gosec -tag debug,ignore ./... ``` ### Output formats -Gas currently supports text, json, yaml, csv and JUnit XML output formats. By default +gosec 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: ``` # Write output in json format to results.json -$ gas -fmt=json -out=results.json *.go +$ gosec -fmt=json -out=results.json *.go ``` ### Development @@ -143,40 +146,43 @@ make test #### Release Build -Gas can be released as follows: +Make sure you have installed the [goreleaser](https://github.com/goreleaser/goreleaser) tool and then you can release gosec as follows: -```bash -make release VERSION=2.0.0 +``` +git tag 1.0.0 +export GITHUB_TOKEN= +make release ``` -The released version of the tool is available in the `build` folder. The build information should be displayed in the usage text. +The released version of the tool is available in the `dist` folder. The build information should be displayed in the usage text. ``` -./build/gas-2.0.0-linux-amd64 -h - -GAS - Go AST Scanner +./dist/darwin_amd64/gosec -h +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: 2.0.0 -GIT TAG: 96489ff -BUILD DATE: 2018-02-21 - +VERSION: 1.0.0 +GIT TAG: 1.0.0 +BUILD DATE: 2018-04-27T12:41:38Z ``` +Note that all released archives are also uploaded to GitHub. + #### Docker image -You can execute a release and build the docker image as follows: +You can build the docker image as follows: ``` -make image VERSION=2.0.0 +make image ``` -Now you can run the gas tool in a container against your local workspace: +You can run the `gosec` tool in a container against your local Go project. You just have to mount the project in the +`GOPATH` of the container: ``` -docker run -it -v :/workspace gas /workspace +docker run -it -v $GOPATH/src/:/go/src/ securego/gosec /go/src/ ``` #### Generate TLS rule @@ -187,7 +193,7 @@ The configuration of TLS rule can be generated from [Mozilla's TLS ciphers recom First you need to install the generator tool: ``` -go get github.com/GoASTScanner/gas/cmd/tlsconfig/... +go get github.com/golangci/gosec/cmd/tlsconfig/... ``` You can invoke now the `go generate` in the root of the project: diff --git a/vendor/github.com/GoASTScanner/gas/analyzer.go b/vendor/github.com/golangci/gosec/analyzer.go similarity index 64% rename from vendor/github.com/GoASTScanner/gas/analyzer.go rename to vendor/github.com/golangci/gosec/analyzer.go index 5014db2982fd3..9ce2bc743b4b7 100644 --- a/vendor/github.com/GoASTScanner/gas/analyzer.go +++ b/vendor/github.com/golangci/gosec/analyzer.go @@ -14,8 +14,8 @@ // Modifications copyright (C) 2018 GolangCI -// 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" @@ -30,8 +30,6 @@ import ( "regexp" "strings" - "path/filepath" - "golang.org/x/tools/go/loader" ) @@ -57,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 @@ -76,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, @@ -91,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{ @@ -108,15 +106,12 @@ func (gas *Analyzer) Process(buildTags []string, packagePaths ...string) error { AllowErrors: true, } for _, packagePath := range packagePaths { - abspath, err := filepath.Abs(packagePath) + abspath, err := GetPkgAbsPath(packagePath) if err != nil { - 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 { @@ -136,37 +131,37 @@ func (gas *Analyzer) Process(buildTags []string, packagePaths ...string) error { return err } - gas.ProcessProgram(builtPackage) + gosec.ProcessProgram(builtPackage) return nil } // ProcessProgram kicks off the analysis process for a given program -func (gas *Analyzer) ProcessProgram(builtPackage *loader.Program) { +func (gosec *Analyzer) ProcessProgram(builtPackage *loader.Program) { for _, pkg := range builtPackage.InitialPackages() { - 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() } } } // 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})") @@ -189,27 +184,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 } } @@ -219,37 +214,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/vendor/github.com/GoASTScanner/gas/call_list.go b/vendor/github.com/golangci/gosec/call_list.go similarity index 99% rename from vendor/github.com/GoASTScanner/gas/call_list.go rename to vendor/github.com/golangci/gosec/call_list.go index e277950b48d5b..8370f8f42be00 100644 --- a/vendor/github.com/GoASTScanner/gas/call_list.go +++ b/vendor/github.com/golangci/gosec/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/vendor/github.com/GoASTScanner/gas/config.go b/vendor/github.com/golangci/gosec/config.go similarity index 97% rename from vendor/github.com/GoASTScanner/gas/config.go rename to vendor/github.com/golangci/gosec/config.go index 09b97d3ea3ce7..a19937f0e6109 100644 --- a/vendor/github.com/GoASTScanner/gas/config.go +++ b/vendor/github.com/golangci/gosec/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/vendor/github.com/GoASTScanner/gas/docker-entrypoint.sh b/vendor/github.com/golangci/gosec/docker-entrypoint.sh similarity index 100% rename from vendor/github.com/GoASTScanner/gas/docker-entrypoint.sh rename to vendor/github.com/golangci/gosec/docker-entrypoint.sh diff --git a/vendor/github.com/GoASTScanner/gas/helpers.go b/vendor/github.com/golangci/gosec/helpers.go similarity index 63% rename from vendor/github.com/GoASTScanner/gas/helpers.go rename to vendor/github.com/golangci/gosec/helpers.go index 8bd1f5c508364..638129b1dfae9 100644 --- a/vendor/github.com/GoASTScanner/gas/helpers.go +++ b/vendor/github.com/golangci/gosec/helpers.go @@ -12,14 +12,20 @@ // See the License for the specific language governing permissions and // limitations under the License. -package gas +package gosec import ( + "errors" "fmt" "go/ast" "go/token" "go/types" + "os" + "os/user" + "path/filepath" + "runtime" "strconv" + "strings" ) // MatchCallByPackage ensures that the specified package is imported, @@ -193,3 +199,115 @@ func GetLocation(n ast.Node, ctx *Context) (string, int) { fobj := ctx.FileSet.File(n.Pos()) return fobj.Name(), fobj.Line(n.Pos()) } + +// Gopath returns all GOPATHs +func Gopath() []string { + defaultGoPath := runtime.GOROOT() + if u, err := user.Current(); err == nil { + defaultGoPath = filepath.Join(u.HomeDir, "go") + } + path := Getenv("GOPATH", defaultGoPath) + paths := strings.Split(path, string(os.PathListSeparator)) + for idx, path := range paths { + if abs, err := filepath.Abs(path); err == nil { + paths[idx] = abs + } + } + return paths +} + +// Getenv returns the values of the environment variable, otherwise +//returns the default if variable is not set +func Getenv(key, userDefault string) string { + if val := os.Getenv(key); val != "" { + return val + } + return userDefault +} + +// GetPkgRelativePath returns the Go relative relative path derived +// form the given path +func GetPkgRelativePath(path string) (string, error) { + abspath, err := filepath.Abs(path) + if err != nil { + abspath = path + } + if strings.HasSuffix(abspath, ".go") { + abspath = filepath.Dir(abspath) + } + for _, base := range Gopath() { + projectRoot := filepath.FromSlash(fmt.Sprintf("%s/src/", base)) + if strings.HasPrefix(abspath, projectRoot) { + return strings.TrimPrefix(abspath, projectRoot), nil + } + } + return "", errors.New("no project relative path found") +} + +// GetPkgAbsPath returns the Go package absolute path derived from +// the given path +func GetPkgAbsPath(pkgPath string) (string, error) { + absPath, err := filepath.Abs(pkgPath) + if err != nil { + return "", err + } + if _, err := os.Stat(absPath); os.IsNotExist(err) { + return "", errors.New("no project absolute path found") + } + return absPath, nil +} + +// ConcatString recusively concatenates strings from a binary expression +func ConcatString(n *ast.BinaryExpr) (string, bool) { + var s string + // sub expressions are found in X object, Y object is always last BasicLit + if rightOperand, ok := n.Y.(*ast.BasicLit); ok { + if str, err := GetString(rightOperand); err == nil { + s = str + s + } + } else { + return "", false + } + if leftOperand, ok := n.X.(*ast.BinaryExpr); ok { + if recursion, ok := ConcatString(leftOperand); ok { + s = recursion + s + } + } else if leftOperand, ok := n.X.(*ast.BasicLit); ok { + if str, err := GetString(leftOperand); err == nil { + s = str + s + } + } else { + return "", false + } + return s, true +} + +// FindVarIdentities returns array of all variable identities in a given binary expression +func FindVarIdentities(n *ast.BinaryExpr, c *Context) ([]*ast.Ident, bool) { + identities := []*ast.Ident{} + // sub expressions are found in X object, Y object is always the last term + if rightOperand, ok := n.Y.(*ast.Ident); ok { + obj := c.Info.ObjectOf(rightOperand) + if _, ok := obj.(*types.Var); ok && !TryResolve(rightOperand, c) { + identities = append(identities, rightOperand) + } + } + if leftOperand, ok := n.X.(*ast.BinaryExpr); ok { + if leftIdentities, ok := FindVarIdentities(leftOperand, c); ok { + identities = append(identities, leftIdentities...) + } + } else { + if leftOperand, ok := n.X.(*ast.Ident); ok { + obj := c.Info.ObjectOf(leftOperand) + if _, ok := obj.(*types.Var); ok && !TryResolve(leftOperand, c) { + identities = append(identities, leftOperand) + } + } + } + + if len(identities) > 0 { + return identities, true + } + // if nil or error, return false + return nil, false +} diff --git a/vendor/github.com/GoASTScanner/gas/import_tracker.go b/vendor/github.com/golangci/gosec/import_tracker.go similarity index 99% rename from vendor/github.com/GoASTScanner/gas/import_tracker.go rename to vendor/github.com/golangci/gosec/import_tracker.go index 0f948fb670271..b56b65a606523 100644 --- a/vendor/github.com/GoASTScanner/gas/import_tracker.go +++ b/vendor/github.com/golangci/gosec/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/vendor/github.com/GoASTScanner/gas/issue.go b/vendor/github.com/golangci/gosec/issue.go similarity index 94% rename from vendor/github.com/GoASTScanner/gas/issue.go rename to vendor/github.com/golangci/gosec/issue.go index 5ec39bca032e2..40bfa3d431aaf 100644 --- a/vendor/github.com/GoASTScanner/gas/issue.go +++ b/vendor/github.com/golangci/gosec/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/vendor/github.com/GoASTScanner/gas/resolve.go b/vendor/github.com/golangci/gosec/resolve.go similarity index 99% rename from vendor/github.com/GoASTScanner/gas/resolve.go rename to vendor/github.com/golangci/gosec/resolve.go index d7c6dce7d401b..b563e7ddfd657 100644 --- a/vendor/github.com/GoASTScanner/gas/resolve.go +++ b/vendor/github.com/golangci/gosec/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/vendor/github.com/GoASTScanner/gas/rule.go b/vendor/github.com/golangci/gosec/rule.go similarity index 95% rename from vendor/github.com/GoASTScanner/gas/rule.go rename to vendor/github.com/golangci/gosec/rule.go index 95c65623f919e..415c7085b57f4 100644 --- a/vendor/github.com/GoASTScanner/gas/rule.go +++ b/vendor/github.com/golangci/gosec/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/vendor/github.com/golangci/gosec/rules/archive.go b/vendor/github.com/golangci/gosec/rules/archive.go new file mode 100644 index 0000000000000..0eafd088df4f5 --- /dev/null +++ b/vendor/github.com/golangci/gosec/rules/archive.go @@ -0,0 +1,60 @@ +package rules + +import ( + "go/ast" + "go/types" + + "github.com/golangci/gosec" +) + +type archive struct { + gosec.MetaData + calls gosec.CallList + argType string +} + +func (a *archive) ID() string { + return a.MetaData.ID +} + +// 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 *gosec.Context) (*gosec.Issue, error) { + if node := a.calls.ContainsCallExpr(n, c); node != nil { + for _, arg := range node.Args { + var argType types.Type + if selector, ok := arg.(*ast.SelectorExpr); ok { + argType = c.Info.TypeOf(selector.X) + } else if ident, ok := arg.(*ast.Ident); ok { + if ident.Obj != nil && ident.Obj.Kind == ast.Var { + decl := ident.Obj.Decl + if assign, ok := decl.(*ast.AssignStmt); ok { + if selector, ok := assign.Rhs[0].(*ast.SelectorExpr); ok { + argType = c.Info.TypeOf(selector.X) + } + } + } + } + + if argType != nil && argType.String() == a.argType { + return gosec.NewIssue(c, n, a.ID(), a.What, a.Severity, a.Confidence), nil + } + } + } + return nil, nil +} + +// NewArchive creates a new rule which detects the file traversal when extracting zip archives +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: gosec.MetaData{ + ID: id, + Severity: gosec.Medium, + Confidence: gosec.High, + What: "File traversal when extracting zip archive", + }, + }, []ast.Node{(*ast.CallExpr)(nil)} +} diff --git a/vendor/github.com/GoASTScanner/gas/rules/big.go b/vendor/github.com/golangci/gosec/rules/big.go similarity index 70% rename from vendor/github.com/GoASTScanner/gas/rules/big.go rename to vendor/github.com/golangci/gosec/rules/big.go index f4aeb3e790035..35a37ec086118 100644 --- a/vendor/github.com/GoASTScanner/gas/rules/big.go +++ b/vendor/github.com/golangci/gosec/rules/big.go @@ -17,11 +17,11 @@ package rules import ( "go/ast" - "github.com/GoASTScanner/gas" + "github.com/golangci/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/vendor/github.com/GoASTScanner/gas/rules/bind.go b/vendor/github.com/golangci/gosec/rules/bind.go similarity index 73% rename from vendor/github.com/GoASTScanner/gas/rules/bind.go rename to vendor/github.com/golangci/gosec/rules/bind.go index 1cd8bf26b7ce2..a53f82e599810 100644 --- a/vendor/github.com/GoASTScanner/gas/rules/bind.go +++ b/vendor/github.com/golangci/gosec/rules/bind.go @@ -18,13 +18,13 @@ import ( "go/ast" "regexp" - "github.com/GoASTScanner/gas" + "github.com/golangci/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/vendor/github.com/GoASTScanner/gas/rules/blacklist.go b/vendor/github.com/golangci/gosec/rules/blacklist.go similarity index 67% rename from vendor/github.com/GoASTScanner/gas/rules/blacklist.go rename to vendor/github.com/golangci/gosec/rules/blacklist.go index 92d8ed4ec8bb7..cf57f2c74031a 100644 --- a/vendor/github.com/GoASTScanner/gas/rules/blacklist.go +++ b/vendor/github.com/golangci/gosec/rules/blacklist.go @@ -18,11 +18,11 @@ import ( "go/ast" "strings" - "github.com/GoASTScanner/gas" + "github.com/golangci/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,41 +47,48 @@ 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)", }) } + +// NewBlacklistedImportSHA1 fails if SHA1 is imported +func NewBlacklistedImportSHA1(id string, conf gosec.Config) (gosec.Rule, []ast.Node) { + return NewBlacklistedImports(id, conf, map[string]string{ + "crypto/sha1": "Blacklisted import crypto/sha1: weak cryptographic primitive", + }) +} diff --git a/vendor/github.com/GoASTScanner/gas/rules/errors.go b/vendor/github.com/golangci/gosec/rules/errors.go similarity index 80% rename from vendor/github.com/GoASTScanner/gas/rules/errors.go rename to vendor/github.com/golangci/gosec/rules/errors.go index 03ededf6956eb..e7e7773c70e89 100644 --- a/vendor/github.com/GoASTScanner/gas/rules/errors.go +++ b/vendor/github.com/golangci/gosec/rules/errors.go @@ -18,19 +18,19 @@ import ( "go/ast" "go/types" - "github.com/GoASTScanner/gas" + "github.com/golangci/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/vendor/github.com/GoASTScanner/gas/rules/fileperms.go b/vendor/github.com/golangci/gosec/rules/fileperms.go similarity index 75% rename from vendor/github.com/GoASTScanner/gas/rules/fileperms.go rename to vendor/github.com/golangci/gosec/rules/fileperms.go index 6276c855a222b..7458bfec34b3a 100644 --- a/vendor/github.com/GoASTScanner/gas/rules/fileperms.go +++ b/vendor/github.com/golangci/gosec/rules/fileperms.go @@ -19,11 +19,11 @@ import ( "go/ast" "strconv" - "github.com/GoASTScanner/gas" + "github.com/golangci/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/vendor/github.com/GoASTScanner/gas/rules/hardcoded_credentials.go b/vendor/github.com/golangci/gosec/rules/hardcoded_credentials.go similarity index 83% rename from vendor/github.com/GoASTScanner/gas/rules/hardcoded_credentials.go rename to vendor/github.com/golangci/gosec/rules/hardcoded_credentials.go index 00407103d826f..2e0dd9a92573b 100644 --- a/vendor/github.com/GoASTScanner/gas/rules/hardcoded_credentials.go +++ b/vendor/github.com/golangci/gosec/rules/hardcoded_credentials.go @@ -19,12 +19,12 @@ import ( "regexp" "strconv" - "github.com/GoASTScanner/gas" - "github.com/nbutton23/zxcvbn-go" + zxcvbn "github.com/nbutton23/zxcvbn-go" + "github.com/golangci/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/vendor/github.com/GoASTScanner/gas/rules/rand.go b/vendor/github.com/golangci/gosec/rules/rand.go similarity index 72% rename from vendor/github.com/GoASTScanner/gas/rules/rand.go rename to vendor/github.com/golangci/gosec/rules/rand.go index c85f10f0b3792..c1254d37da67e 100644 --- a/vendor/github.com/GoASTScanner/gas/rules/rand.go +++ b/vendor/github.com/golangci/gosec/rules/rand.go @@ -17,11 +17,11 @@ package rules import ( "go/ast" - "github.com/GoASTScanner/gas" + "github.com/golangci/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/vendor/github.com/golangci/gosec/rules/readfile.go b/vendor/github.com/golangci/gosec/rules/readfile.go new file mode 100644 index 0000000000000..e32597b05e1b5 --- /dev/null +++ b/vendor/github.com/golangci/gosec/rules/readfile.go @@ -0,0 +1,106 @@ +// (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 ( + "go/ast" + "go/types" + + "github.com/golangci/gosec" +) + +type readfile struct { + gosec.MetaData + gosec.CallList + pathJoin gosec.CallList +} + +// ID returns the identifier for this rule +func (r *readfile) ID() string { + return r.MetaData.ID +} + +// isJoinFunc checks if there is a filepath.Join or other join function +func (r *readfile) isJoinFunc(n ast.Node, c *gosec.Context) bool { + if call := r.pathJoin.ContainsCallExpr(n, c); call != nil { + for _, arg := range call.Args { + // edge case: check if one of the args is a BinaryExpr + if binExp, ok := arg.(*ast.BinaryExpr); ok { + // iterate and resolve all found identites from the BinaryExpr + if _, ok := gosec.FindVarIdentities(binExp, c); ok { + return true + } + } + + // try and resolve identity + if ident, ok := arg.(*ast.Ident); ok { + obj := c.Info.ObjectOf(ident) + if _, ok := obj.(*types.Var); ok && !gosec.TryResolve(ident, c) { + return true + } + } + } +} + return false +} + +// Match inspects AST nodes to determine if the match the methods `os.Open` or `ioutil.ReadFile` +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 { + // handles path joining functions in Arg + // eg. os.Open(filepath.Join("/tmp/", file)) + if callExpr, ok := arg.(*ast.CallExpr); ok { + if r.isJoinFunc(callExpr, c) { + return gosec.NewIssue(c, n, r.ID(), r.What, r.Severity, r.Confidence), nil + } + } + // handles binary string concatenation eg. ioutil.Readfile("/tmp/" + file + "/blob") + if binExp, ok := arg.(*ast.BinaryExpr); ok { + // resolve all found identites from the BinaryExpr + if _, ok := gosec.FindVarIdentities(binExp, c); ok { + return gosec.NewIssue(c, n, r.ID(), r.What, r.Severity, r.Confidence), nil + } + } + + if ident, ok := arg.(*ast.Ident); ok { + obj := c.Info.ObjectOf(ident) + if _, ok := obj.(*types.Var); ok && !gosec.TryResolve(ident, c) { + return gosec.NewIssue(c, n, r.ID(), r.What, r.Severity, r.Confidence), nil + } + } + } + } + return nil, nil +} + +// NewReadFile detects cases where we read files +func NewReadFile(id string, conf gosec.Config) (gosec.Rule, []ast.Node) { + rule := &readfile{ + pathJoin: gosec.NewCallList(), + CallList: gosec.NewCallList(), + MetaData: gosec.MetaData{ + ID: id, + What: "Potential file inclusion via variable", + Severity: gosec.Medium, + Confidence: gosec.High, + }, + } + rule.pathJoin.Add("path/filepath", "Join") + rule.pathJoin.Add("path", "Join") + rule.Add("io/ioutil", "ReadFile") + rule.Add("os", "Open") + return rule, []ast.Node{(*ast.CallExpr)(nil)} +} diff --git a/vendor/github.com/GoASTScanner/gas/rules/rsa.go b/vendor/github.com/golangci/gosec/rules/rsa.go similarity index 69% rename from vendor/github.com/GoASTScanner/gas/rules/rsa.go rename to vendor/github.com/golangci/gosec/rules/rsa.go index 99c6e82b4cc32..860cb07f9dc76 100644 --- a/vendor/github.com/GoASTScanner/gas/rules/rsa.go +++ b/vendor/github.com/golangci/gosec/rules/rsa.go @@ -18,12 +18,12 @@ import ( "fmt" "go/ast" - "github.com/GoASTScanner/gas" + "github.com/golangci/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/vendor/github.com/GoASTScanner/gas/rules/rulelist.go b/vendor/github.com/golangci/gosec/rules/rulelist.go similarity index 89% rename from vendor/github.com/GoASTScanner/gas/rules/rulelist.go rename to vendor/github.com/golangci/gosec/rules/rulelist.go index f6f21af7a9138..8ea937a6a49f5 100644 --- a/vendor/github.com/GoASTScanner/gas/rules/rulelist.go +++ b/vendor/github.com/golangci/gosec/rules/rulelist.go @@ -14,24 +14,22 @@ package rules -import ( - "github.com/GoASTScanner/gas" -) +import "github.com/golangci/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 } @@ -79,9 +77,10 @@ func Generate(filters ...RuleFilter) RuleList { {"G302", "Poor file permisions used when creation file or using chmod", NewFilePerms}, {"G303", "Creating tempfile using a predictable path", NewBadTempFile}, {"G304", "File path provided as taint input", NewReadFile}, + {"G305", "File path traversal when extracting zip archive", NewArchive}, // crypto - {"G401", "Detect the usage of DES, RC4, or MD5", NewUsesWeakCryptography}, + {"G401", "Detect the usage of DES, RC4, MD5 or SHA1", 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}, @@ -91,6 +90,7 @@ func Generate(filters ...RuleFilter) RuleList { {"G502", "Import blacklist: crypto/des", NewBlacklistedImportDES}, {"G503", "Import blacklist: crypto/rc4", NewBlacklistedImportRC4}, {"G504", "Import blacklist: net/http/cgi", NewBlacklistedImportCGI}, + {"G505", "Import blacklist: crypto/sha1", NewBlacklistedImportSHA1}, } ruleMap := make(map[string]RuleDefinition) diff --git a/vendor/github.com/GoASTScanner/gas/rules/sql.go b/vendor/github.com/golangci/gosec/rules/sql.go similarity index 58% rename from vendor/github.com/GoASTScanner/gas/rules/sql.go rename to vendor/github.com/golangci/gosec/rules/sql.go index a76f58067352b..14201386cceb2 100644 --- a/vendor/github.com/GoASTScanner/gas/rules/sql.go +++ b/vendor/github.com/golangci/gosec/rules/sql.go @@ -18,11 +18,11 @@ import ( "go/ast" "regexp" - "github.com/GoASTScanner/gas" + "github.com/golangci/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,38 +98,69 @@ func NewSQLStrConcat(id string, conf gas.Config) (gas.Rule, []ast.Node) { type sqlStrFormat struct { sqlStatement - calls gas.CallList + calls gosec.CallList + noIssue 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) { + + // argIndex changes the function argument which gets matched to the regex + argIndex := 0 // 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 the function is fmt.Fprintf, search for SQL statement in Args[1] instead + if sel, ok := node.Fun.(*ast.SelectorExpr); ok { + if sel.Sel.Name == "Fprintf" { + // if os.Stderr or os.Stdout is in Arg[0], mark as no issue + if arg, ok := node.Args[0].(*ast.SelectorExpr); ok { + if ident, ok := arg.X.(*ast.Ident); ok { + if s.noIssue.Contains(ident.Name, arg.Sel.Name) { + return nil, nil + } + } + } + // the function is Fprintf so set argIndex = 1 + argIndex = 1 + } + } + // concats callexpr arg strings together if needed before regex evaluation + if argExpr, ok := node.Args[argIndex].(*ast.BinaryExpr); ok { + if fullStr, ok := gosec.ConcatString(argExpr); ok { + if s.MatchPatterns(fullStr) { + return gosec.NewIssue(c, n, s.ID(), s.What, s.Severity, s.Confidence), + nil + } + } + } + + if arg, e := gosec.GetString(node.Args[argIndex]); 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(), + noIssue: 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", }, }, } - rule.calls.AddAll("fmt", "Sprint", "Sprintf", "Sprintln") + rule.calls.AddAll("fmt", "Sprint", "Sprintf", "Sprintln", "Fprintf") + rule.noIssue.AddAll("os", "Stdout", "Stderr") return rule, []ast.Node{(*ast.CallExpr)(nil)} } diff --git a/vendor/github.com/GoASTScanner/gas/rules/ssh.go b/vendor/github.com/golangci/gosec/rules/ssh.go similarity index 51% rename from vendor/github.com/GoASTScanner/gas/rules/ssh.go rename to vendor/github.com/golangci/gosec/rules/ssh.go index f4f18cc3ca5c3..dfab3dd30412d 100644 --- a/vendor/github.com/GoASTScanner/gas/rules/ssh.go +++ b/vendor/github.com/golangci/gosec/rules/ssh.go @@ -3,11 +3,11 @@ package rules import ( "go/ast" - "github.com/GoASTScanner/gas" + "github.com/golangci/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/vendor/github.com/GoASTScanner/gas/rules/subproc.go b/vendor/github.com/golangci/gosec/rules/subproc.go similarity index 70% rename from vendor/github.com/GoASTScanner/gas/rules/subproc.go rename to vendor/github.com/golangci/gosec/rules/subproc.go index 8c0f675b589be..f2735da6d9c5d 100644 --- a/vendor/github.com/GoASTScanner/gas/rules/subproc.go +++ b/vendor/github.com/golangci/gosec/rules/subproc.go @@ -18,12 +18,12 @@ import ( "go/ast" "go/types" - "github.com/GoASTScanner/gas" + "github.com/golangci/gosec" ) type subprocess struct { - gas.MetaData - gas.CallList + gosec.MetaData + gosec.CallList } func (r *subprocess) ID() string { @@ -39,25 +39,26 @@ 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("os/exec", "CommandContext") rule.Add("syscall", "Exec") return rule, []ast.Node{(*ast.CallExpr)(nil)} } diff --git a/vendor/github.com/GoASTScanner/gas/rules/tempfiles.go b/vendor/github.com/golangci/gosec/rules/tempfiles.go similarity index 71% rename from vendor/github.com/GoASTScanner/gas/rules/tempfiles.go rename to vendor/github.com/golangci/gosec/rules/tempfiles.go index 664f774bd1054..b14640cc9a19b 100644 --- a/vendor/github.com/GoASTScanner/gas/rules/tempfiles.go +++ b/vendor/github.com/golangci/gosec/rules/tempfiles.go @@ -18,12 +18,12 @@ import ( "go/ast" "regexp" - "github.com/GoASTScanner/gas" + "github.com/golangci/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/vendor/github.com/GoASTScanner/gas/rules/templates.go b/vendor/github.com/golangci/gosec/rules/templates.go similarity index 77% rename from vendor/github.com/GoASTScanner/gas/rules/templates.go rename to vendor/github.com/golangci/gosec/rules/templates.go index 66c37d6cb1f79..a45141eace60d 100644 --- a/vendor/github.com/GoASTScanner/gas/rules/templates.go +++ b/vendor/github.com/golangci/gosec/rules/templates.go @@ -17,23 +17,23 @@ package rules import ( "go/ast" - "github.com/GoASTScanner/gas" + "github.com/golangci/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/vendor/github.com/GoASTScanner/gas/rules/tls.go b/vendor/github.com/golangci/gosec/rules/tls.go similarity index 69% rename from vendor/github.com/GoASTScanner/gas/rules/tls.go rename to vendor/github.com/golangci/gosec/rules/tls.go index c437930bdc765..b518581d1708c 100644 --- a/vendor/github.com/GoASTScanner/gas/rules/tls.go +++ b/vendor/github.com/golangci/gosec/rules/tls.go @@ -20,11 +20,11 @@ import ( "fmt" "go/ast" - "github.com/GoASTScanner/gas" + "github.com/golangci/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/vendor/github.com/GoASTScanner/gas/rules/tls_config.go b/vendor/github.com/golangci/gosec/rules/tls_config.go similarity index 92% rename from vendor/github.com/GoASTScanner/gas/rules/tls_config.go rename to vendor/github.com/golangci/gosec/rules/tls_config.go index 7242513433620..bfb241be8f072 100644 --- a/vendor/github.com/GoASTScanner/gas/rules/tls_config.go +++ b/vendor/github.com/golangci/gosec/rules/tls_config.go @@ -3,14 +3,14 @@ package rules import ( "go/ast" - "github.com/GoASTScanner/gas" + "github.com/golangci/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/vendor/github.com/GoASTScanner/gas/rules/unsafe.go b/vendor/github.com/golangci/gosec/rules/unsafe.go similarity index 71% rename from vendor/github.com/GoASTScanner/gas/rules/unsafe.go rename to vendor/github.com/golangci/gosec/rules/unsafe.go index 8742dbc3905d8..1498ee45d2e43 100644 --- a/vendor/github.com/GoASTScanner/gas/rules/unsafe.go +++ b/vendor/github.com/golangci/gosec/rules/unsafe.go @@ -17,11 +17,11 @@ package rules import ( "go/ast" - "github.com/GoASTScanner/gas" + "github.com/golangci/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/vendor/github.com/GoASTScanner/gas/rules/weakcrypto.go b/vendor/github.com/golangci/gosec/rules/weakcrypto.go similarity index 72% rename from vendor/github.com/GoASTScanner/gas/rules/weakcrypto.go rename to vendor/github.com/golangci/gosec/rules/weakcrypto.go index 2fb96867b9241..fa2273f40eebd 100644 --- a/vendor/github.com/GoASTScanner/gas/rules/weakcrypto.go +++ b/vendor/github.com/golangci/gosec/rules/weakcrypto.go @@ -17,11 +17,11 @@ package rules import ( "go/ast" - "github.com/GoASTScanner/gas" + "github.com/golangci/gosec" ) type usesWeakCryptography struct { - gas.MetaData + gosec.MetaData blacklist map[string][]string } @@ -29,27 +29,28 @@ 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/sha1"] = []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/vendor/golang.org/x/net/AUTHORS b/vendor/golang.org/x/net/AUTHORS new file mode 100644 index 0000000000000..15167cd746c56 --- /dev/null +++ b/vendor/golang.org/x/net/AUTHORS @@ -0,0 +1,3 @@ +# This source code refers to The Go Authors for copyright purposes. +# The master list of authors is in the main Go distribution, +# visible at http://tip.golang.org/AUTHORS. diff --git a/vendor/golang.org/x/net/CONTRIBUTORS b/vendor/golang.org/x/net/CONTRIBUTORS new file mode 100644 index 0000000000000..1c4577e968061 --- /dev/null +++ b/vendor/golang.org/x/net/CONTRIBUTORS @@ -0,0 +1,3 @@ +# This source code was written by the Go contributors. +# The master list of contributors is in the main Go distribution, +# visible at http://tip.golang.org/CONTRIBUTORS. diff --git a/vendor/golang.org/x/net/LICENSE b/vendor/golang.org/x/net/LICENSE new file mode 100644 index 0000000000000..6a66aea5eafe0 --- /dev/null +++ b/vendor/golang.org/x/net/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/golang.org/x/net/PATENTS b/vendor/golang.org/x/net/PATENTS new file mode 100644 index 0000000000000..733099041f84f --- /dev/null +++ b/vendor/golang.org/x/net/PATENTS @@ -0,0 +1,22 @@ +Additional IP Rights Grant (Patents) + +"This implementation" means the copyrightable works distributed by +Google as part of the Go project. + +Google hereby grants to You a perpetual, worldwide, non-exclusive, +no-charge, royalty-free, irrevocable (except as stated in this section) +patent license to make, have made, use, offer to sell, sell, import, +transfer and otherwise run, modify and propagate the contents of this +implementation of Go, where such license applies only to those patent +claims, both currently owned or controlled by Google and acquired in +the future, licensable by Google that are necessarily infringed by this +implementation of Go. This grant does not include claims that would be +infringed only as a consequence of further modification of this +implementation. If you or your agent or exclusive licensee institute or +order or agree to the institution of patent litigation against any +entity (including a cross-claim or counterclaim in a lawsuit) alleging +that this implementation of Go or any code incorporated within this +implementation of Go constitutes direct or contributory patent +infringement, or inducement of patent infringement, then any patent +rights granted to you under this License for this implementation of Go +shall terminate as of the date such litigation is filed. diff --git a/vendor/golang.org/x/net/context/context.go b/vendor/golang.org/x/net/context/context.go new file mode 100644 index 0000000000000..a3c021d3f88e9 --- /dev/null +++ b/vendor/golang.org/x/net/context/context.go @@ -0,0 +1,56 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package context defines the Context type, which carries deadlines, +// cancelation signals, and other request-scoped values across API boundaries +// and between processes. +// As of Go 1.7 this package is available in the standard library under the +// name context. https://golang.org/pkg/context. +// +// Incoming requests to a server should create a Context, and outgoing calls to +// servers should accept a Context. The chain of function calls between must +// propagate the Context, optionally replacing it with a modified copy created +// using WithDeadline, WithTimeout, WithCancel, or WithValue. +// +// Programs that use Contexts should follow these rules to keep interfaces +// consistent across packages and enable static analysis tools to check context +// propagation: +// +// Do not store Contexts inside a struct type; instead, pass a Context +// explicitly to each function that needs it. The Context should be the first +// parameter, typically named ctx: +// +// func DoSomething(ctx context.Context, arg Arg) error { +// // ... use ctx ... +// } +// +// Do not pass a nil Context, even if a function permits it. Pass context.TODO +// if you are unsure about which Context to use. +// +// Use context Values only for request-scoped data that transits processes and +// APIs, not for passing optional parameters to functions. +// +// The same Context may be passed to functions running in different goroutines; +// Contexts are safe for simultaneous use by multiple goroutines. +// +// See http://blog.golang.org/context for example code for a server that uses +// Contexts. +package context // import "golang.org/x/net/context" + +// Background returns a non-nil, empty Context. It is never canceled, has no +// values, and has no deadline. It is typically used by the main function, +// initialization, and tests, and as the top-level Context for incoming +// requests. +func Background() Context { + return background +} + +// TODO returns a non-nil, empty Context. Code should use context.TODO when +// it's unclear which Context to use or it is not yet available (because the +// surrounding function has not yet been extended to accept a Context +// parameter). TODO is recognized by static analysis tools that determine +// whether Contexts are propagated correctly in a program. +func TODO() Context { + return todo +} diff --git a/vendor/golang.org/x/net/context/go17.go b/vendor/golang.org/x/net/context/go17.go new file mode 100644 index 0000000000000..d20f52b7de93f --- /dev/null +++ b/vendor/golang.org/x/net/context/go17.go @@ -0,0 +1,72 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build go1.7 + +package context + +import ( + "context" // standard library's context, as of Go 1.7 + "time" +) + +var ( + todo = context.TODO() + background = context.Background() +) + +// Canceled is the error returned by Context.Err when the context is canceled. +var Canceled = context.Canceled + +// DeadlineExceeded is the error returned by Context.Err when the context's +// deadline passes. +var DeadlineExceeded = context.DeadlineExceeded + +// WithCancel returns a copy of parent with a new Done channel. The returned +// context's Done channel is closed when the returned cancel function is called +// or when the parent context's Done channel is closed, whichever happens first. +// +// Canceling this context releases resources associated with it, so code should +// call cancel as soon as the operations running in this Context complete. +func WithCancel(parent Context) (ctx Context, cancel CancelFunc) { + ctx, f := context.WithCancel(parent) + return ctx, CancelFunc(f) +} + +// WithDeadline returns a copy of the parent context with the deadline adjusted +// to be no later than d. If the parent's deadline is already earlier than d, +// WithDeadline(parent, d) is semantically equivalent to parent. The returned +// context's Done channel is closed when the deadline expires, when the returned +// cancel function is called, or when the parent context's Done channel is +// closed, whichever happens first. +// +// Canceling this context releases resources associated with it, so code should +// call cancel as soon as the operations running in this Context complete. +func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc) { + ctx, f := context.WithDeadline(parent, deadline) + return ctx, CancelFunc(f) +} + +// WithTimeout returns WithDeadline(parent, time.Now().Add(timeout)). +// +// Canceling this context releases resources associated with it, so code should +// call cancel as soon as the operations running in this Context complete: +// +// func slowOperationWithTimeout(ctx context.Context) (Result, error) { +// ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond) +// defer cancel() // releases resources if slowOperation completes before timeout elapses +// return slowOperation(ctx) +// } +func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) { + return WithDeadline(parent, time.Now().Add(timeout)) +} + +// WithValue returns a copy of parent in which the value associated with key is +// val. +// +// Use context Values only for request-scoped data that transits processes and +// APIs, not for passing optional parameters to functions. +func WithValue(parent Context, key interface{}, val interface{}) Context { + return context.WithValue(parent, key, val) +} diff --git a/vendor/golang.org/x/net/context/go19.go b/vendor/golang.org/x/net/context/go19.go new file mode 100644 index 0000000000000..d88bd1db127dd --- /dev/null +++ b/vendor/golang.org/x/net/context/go19.go @@ -0,0 +1,20 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build go1.9 + +package context + +import "context" // standard library's context, as of Go 1.7 + +// A Context carries a deadline, a cancelation signal, and other values across +// API boundaries. +// +// Context's methods may be called by multiple goroutines simultaneously. +type Context = context.Context + +// A CancelFunc tells an operation to abandon its work. +// A CancelFunc does not wait for the work to stop. +// After the first call, subsequent calls to a CancelFunc do nothing. +type CancelFunc = context.CancelFunc diff --git a/vendor/golang.org/x/net/context/pre_go17.go b/vendor/golang.org/x/net/context/pre_go17.go new file mode 100644 index 0000000000000..0f35592df5188 --- /dev/null +++ b/vendor/golang.org/x/net/context/pre_go17.go @@ -0,0 +1,300 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !go1.7 + +package context + +import ( + "errors" + "fmt" + "sync" + "time" +) + +// An emptyCtx is never canceled, has no values, and has no deadline. It is not +// struct{}, since vars of this type must have distinct addresses. +type emptyCtx int + +func (*emptyCtx) Deadline() (deadline time.Time, ok bool) { + return +} + +func (*emptyCtx) Done() <-chan struct{} { + return nil +} + +func (*emptyCtx) Err() error { + return nil +} + +func (*emptyCtx) Value(key interface{}) interface{} { + return nil +} + +func (e *emptyCtx) String() string { + switch e { + case background: + return "context.Background" + case todo: + return "context.TODO" + } + return "unknown empty Context" +} + +var ( + background = new(emptyCtx) + todo = new(emptyCtx) +) + +// Canceled is the error returned by Context.Err when the context is canceled. +var Canceled = errors.New("context canceled") + +// DeadlineExceeded is the error returned by Context.Err when the context's +// deadline passes. +var DeadlineExceeded = errors.New("context deadline exceeded") + +// WithCancel returns a copy of parent with a new Done channel. The returned +// context's Done channel is closed when the returned cancel function is called +// or when the parent context's Done channel is closed, whichever happens first. +// +// Canceling this context releases resources associated with it, so code should +// call cancel as soon as the operations running in this Context complete. +func WithCancel(parent Context) (ctx Context, cancel CancelFunc) { + c := newCancelCtx(parent) + propagateCancel(parent, c) + return c, func() { c.cancel(true, Canceled) } +} + +// newCancelCtx returns an initialized cancelCtx. +func newCancelCtx(parent Context) *cancelCtx { + return &cancelCtx{ + Context: parent, + done: make(chan struct{}), + } +} + +// propagateCancel arranges for child to be canceled when parent is. +func propagateCancel(parent Context, child canceler) { + if parent.Done() == nil { + return // parent is never canceled + } + if p, ok := parentCancelCtx(parent); ok { + p.mu.Lock() + if p.err != nil { + // parent has already been canceled + child.cancel(false, p.err) + } else { + if p.children == nil { + p.children = make(map[canceler]bool) + } + p.children[child] = true + } + p.mu.Unlock() + } else { + go func() { + select { + case <-parent.Done(): + child.cancel(false, parent.Err()) + case <-child.Done(): + } + }() + } +} + +// parentCancelCtx follows a chain of parent references until it finds a +// *cancelCtx. This function understands how each of the concrete types in this +// package represents its parent. +func parentCancelCtx(parent Context) (*cancelCtx, bool) { + for { + switch c := parent.(type) { + case *cancelCtx: + return c, true + case *timerCtx: + return c.cancelCtx, true + case *valueCtx: + parent = c.Context + default: + return nil, false + } + } +} + +// removeChild removes a context from its parent. +func removeChild(parent Context, child canceler) { + p, ok := parentCancelCtx(parent) + if !ok { + return + } + p.mu.Lock() + if p.children != nil { + delete(p.children, child) + } + p.mu.Unlock() +} + +// A canceler is a context type that can be canceled directly. The +// implementations are *cancelCtx and *timerCtx. +type canceler interface { + cancel(removeFromParent bool, err error) + Done() <-chan struct{} +} + +// A cancelCtx can be canceled. When canceled, it also cancels any children +// that implement canceler. +type cancelCtx struct { + Context + + done chan struct{} // closed by the first cancel call. + + mu sync.Mutex + children map[canceler]bool // set to nil by the first cancel call + err error // set to non-nil by the first cancel call +} + +func (c *cancelCtx) Done() <-chan struct{} { + return c.done +} + +func (c *cancelCtx) Err() error { + c.mu.Lock() + defer c.mu.Unlock() + return c.err +} + +func (c *cancelCtx) String() string { + return fmt.Sprintf("%v.WithCancel", c.Context) +} + +// cancel closes c.done, cancels each of c's children, and, if +// removeFromParent is true, removes c from its parent's children. +func (c *cancelCtx) cancel(removeFromParent bool, err error) { + if err == nil { + panic("context: internal error: missing cancel error") + } + c.mu.Lock() + if c.err != nil { + c.mu.Unlock() + return // already canceled + } + c.err = err + close(c.done) + for child := range c.children { + // NOTE: acquiring the child's lock while holding parent's lock. + child.cancel(false, err) + } + c.children = nil + c.mu.Unlock() + + if removeFromParent { + removeChild(c.Context, c) + } +} + +// WithDeadline returns a copy of the parent context with the deadline adjusted +// to be no later than d. If the parent's deadline is already earlier than d, +// WithDeadline(parent, d) is semantically equivalent to parent. The returned +// context's Done channel is closed when the deadline expires, when the returned +// cancel function is called, or when the parent context's Done channel is +// closed, whichever happens first. +// +// Canceling this context releases resources associated with it, so code should +// call cancel as soon as the operations running in this Context complete. +func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc) { + if cur, ok := parent.Deadline(); ok && cur.Before(deadline) { + // The current deadline is already sooner than the new one. + return WithCancel(parent) + } + c := &timerCtx{ + cancelCtx: newCancelCtx(parent), + deadline: deadline, + } + propagateCancel(parent, c) + d := deadline.Sub(time.Now()) + if d <= 0 { + c.cancel(true, DeadlineExceeded) // deadline has already passed + return c, func() { c.cancel(true, Canceled) } + } + c.mu.Lock() + defer c.mu.Unlock() + if c.err == nil { + c.timer = time.AfterFunc(d, func() { + c.cancel(true, DeadlineExceeded) + }) + } + return c, func() { c.cancel(true, Canceled) } +} + +// A timerCtx carries a timer and a deadline. It embeds a cancelCtx to +// implement Done and Err. It implements cancel by stopping its timer then +// delegating to cancelCtx.cancel. +type timerCtx struct { + *cancelCtx + timer *time.Timer // Under cancelCtx.mu. + + deadline time.Time +} + +func (c *timerCtx) Deadline() (deadline time.Time, ok bool) { + return c.deadline, true +} + +func (c *timerCtx) String() string { + return fmt.Sprintf("%v.WithDeadline(%s [%s])", c.cancelCtx.Context, c.deadline, c.deadline.Sub(time.Now())) +} + +func (c *timerCtx) cancel(removeFromParent bool, err error) { + c.cancelCtx.cancel(false, err) + if removeFromParent { + // Remove this timerCtx from its parent cancelCtx's children. + removeChild(c.cancelCtx.Context, c) + } + c.mu.Lock() + if c.timer != nil { + c.timer.Stop() + c.timer = nil + } + c.mu.Unlock() +} + +// WithTimeout returns WithDeadline(parent, time.Now().Add(timeout)). +// +// Canceling this context releases resources associated with it, so code should +// call cancel as soon as the operations running in this Context complete: +// +// func slowOperationWithTimeout(ctx context.Context) (Result, error) { +// ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond) +// defer cancel() // releases resources if slowOperation completes before timeout elapses +// return slowOperation(ctx) +// } +func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) { + return WithDeadline(parent, time.Now().Add(timeout)) +} + +// WithValue returns a copy of parent in which the value associated with key is +// val. +// +// Use context Values only for request-scoped data that transits processes and +// APIs, not for passing optional parameters to functions. +func WithValue(parent Context, key interface{}, val interface{}) Context { + return &valueCtx{parent, key, val} +} + +// A valueCtx carries a key-value pair. It implements Value for that key and +// delegates all other calls to the embedded Context. +type valueCtx struct { + Context + key, val interface{} +} + +func (c *valueCtx) String() string { + return fmt.Sprintf("%v.WithValue(%#v, %#v)", c.Context, c.key, c.val) +} + +func (c *valueCtx) Value(key interface{}) interface{} { + if c.key == key { + return c.val + } + return c.Context.Value(key) +} diff --git a/vendor/golang.org/x/net/context/pre_go19.go b/vendor/golang.org/x/net/context/pre_go19.go new file mode 100644 index 0000000000000..b105f80be4fe2 --- /dev/null +++ b/vendor/golang.org/x/net/context/pre_go19.go @@ -0,0 +1,109 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !go1.9 + +package context + +import "time" + +// A Context carries a deadline, a cancelation signal, and other values across +// API boundaries. +// +// Context's methods may be called by multiple goroutines simultaneously. +type Context interface { + // Deadline returns the time when work done on behalf of this context + // should be canceled. Deadline returns ok==false when no deadline is + // set. Successive calls to Deadline return the same results. + Deadline() (deadline time.Time, ok bool) + + // Done returns a channel that's closed when work done on behalf of this + // context should be canceled. Done may return nil if this context can + // never be canceled. Successive calls to Done return the same value. + // + // WithCancel arranges for Done to be closed when cancel is called; + // WithDeadline arranges for Done to be closed when the deadline + // expires; WithTimeout arranges for Done to be closed when the timeout + // elapses. + // + // Done is provided for use in select statements: + // + // // Stream generates values with DoSomething and sends them to out + // // until DoSomething returns an error or ctx.Done is closed. + // func Stream(ctx context.Context, out chan<- Value) error { + // for { + // v, err := DoSomething(ctx) + // if err != nil { + // return err + // } + // select { + // case <-ctx.Done(): + // return ctx.Err() + // case out <- v: + // } + // } + // } + // + // See http://blog.golang.org/pipelines for more examples of how to use + // a Done channel for cancelation. + Done() <-chan struct{} + + // Err returns a non-nil error value after Done is closed. Err returns + // Canceled if the context was canceled or DeadlineExceeded if the + // context's deadline passed. No other values for Err are defined. + // After Done is closed, successive calls to Err return the same value. + Err() error + + // Value returns the value associated with this context for key, or nil + // if no value is associated with key. Successive calls to Value with + // the same key returns the same result. + // + // Use context values only for request-scoped data that transits + // processes and API boundaries, not for passing optional parameters to + // functions. + // + // A key identifies a specific value in a Context. Functions that wish + // to store values in Context typically allocate a key in a global + // variable then use that key as the argument to context.WithValue and + // Context.Value. A key can be any type that supports equality; + // packages should define keys as an unexported type to avoid + // collisions. + // + // Packages that define a Context key should provide type-safe accessors + // for the values stores using that key: + // + // // Package user defines a User type that's stored in Contexts. + // package user + // + // import "golang.org/x/net/context" + // + // // User is the type of value stored in the Contexts. + // type User struct {...} + // + // // key is an unexported type for keys defined in this package. + // // This prevents collisions with keys defined in other packages. + // type key int + // + // // userKey is the key for user.User values in Contexts. It is + // // unexported; clients use user.NewContext and user.FromContext + // // instead of using this key directly. + // var userKey key = 0 + // + // // NewContext returns a new Context that carries value u. + // func NewContext(ctx context.Context, u *User) context.Context { + // return context.WithValue(ctx, userKey, u) + // } + // + // // FromContext returns the User value stored in ctx, if any. + // func FromContext(ctx context.Context) (*User, bool) { + // u, ok := ctx.Value(userKey).(*User) + // return u, ok + // } + Value(key interface{}) interface{} +} + +// A CancelFunc tells an operation to abandon its work. +// A CancelFunc does not wait for the work to stop. +// After the first call, subsequent calls to a CancelFunc do nothing. +type CancelFunc func()