aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/securego
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2020-07-04 11:12:55 +0200
committerDmitry Vyukov <dvyukov@google.com>2020-07-04 15:05:30 +0200
commitc7d7f10bdff703e4a3c0414e8a33d4e45c91eb35 (patch)
tree0dff0ee1f98dbfa3ad8776112053a450d176592b /vendor/github.com/securego
parent9573094ce235bd9afe88f5da27a47dd6bcc1e13b (diff)
go.mod: vendor golangci-lint
Diffstat (limited to 'vendor/github.com/securego')
-rw-r--r--vendor/github.com/securego/gosec/v2/.gitignore35
-rw-r--r--vendor/github.com/securego/gosec/v2/.goreleaser.yml20
-rw-r--r--vendor/github.com/securego/gosec/v2/Dockerfile14
-rw-r--r--vendor/github.com/securego/gosec/v2/LICENSE.txt154
-rw-r--r--vendor/github.com/securego/gosec/v2/Makefile71
-rw-r--r--vendor/github.com/securego/gosec/v2/README.md326
-rw-r--r--vendor/github.com/securego/gosec/v2/action.yml19
-rw-r--r--vendor/github.com/securego/gosec/v2/analyzer.go378
-rw-r--r--vendor/github.com/securego/gosec/v2/call_list.go109
-rw-r--r--vendor/github.com/securego/gosec/v2/config.go125
-rw-r--r--vendor/github.com/securego/gosec/v2/errors.go33
-rw-r--r--vendor/github.com/securego/gosec/v2/go.mod19
-rw-r--r--vendor/github.com/securego/gosec/v2/go.sum82
-rw-r--r--vendor/github.com/securego/gosec/v2/helpers.go435
-rw-r--r--vendor/github.com/securego/gosec/v2/import_tracker.go75
-rw-r--r--vendor/github.com/securego/gosec/v2/install.sh372
-rw-r--r--vendor/github.com/securego/gosec/v2/issue.go177
-rw-r--r--vendor/github.com/securego/gosec/v2/renovate.json7
-rw-r--r--vendor/github.com/securego/gosec/v2/resolve.go95
-rw-r--r--vendor/github.com/securego/gosec/v2/rule.go59
-rw-r--r--vendor/github.com/securego/gosec/v2/rules/archive.go60
-rw-r--r--vendor/github.com/securego/gosec/v2/rules/bad_defer.go69
-rw-r--r--vendor/github.com/securego/gosec/v2/rules/bind.go83
-rw-r--r--vendor/github.com/securego/gosec/v2/rules/blacklist.go94
-rw-r--r--vendor/github.com/securego/gosec/v2/rules/decompression-bomb.go109
-rw-r--r--vendor/github.com/securego/gosec/v2/rules/errors.go119
-rw-r--r--vendor/github.com/securego/gosec/v2/rules/fileperms.go111
-rw-r--r--vendor/github.com/securego/gosec/v2/rules/hardcoded_credentials.go173
-rw-r--r--vendor/github.com/securego/gosec/v2/rules/implicit_aliasing.go116
-rw-r--r--vendor/github.com/securego/gosec/v2/rules/integer_overflow.go89
-rw-r--r--vendor/github.com/securego/gosec/v2/rules/pprof.go42
-rw-r--r--vendor/github.com/securego/gosec/v2/rules/rand.go55
-rw-r--r--vendor/github.com/securego/gosec/v2/rules/readfile.go106
-rw-r--r--vendor/github.com/securego/gosec/v2/rules/rsa.go58
-rw-r--r--vendor/github.com/securego/gosec/v2/rules/rulelist.go116
-rw-r--r--vendor/github.com/securego/gosec/v2/rules/sql.go219
-rw-r--r--vendor/github.com/securego/gosec/v2/rules/ssh.go38
-rw-r--r--vendor/github.com/securego/gosec/v2/rules/ssrf.go66
-rw-r--r--vendor/github.com/securego/gosec/v2/rules/subproc.go85
-rw-r--r--vendor/github.com/securego/gosec/v2/rules/tempfiles.go58
-rw-r--r--vendor/github.com/securego/gosec/v2/rules/templates.go61
-rw-r--r--vendor/github.com/securego/gosec/v2/rules/tls.go130
-rw-r--r--vendor/github.com/securego/gosec/v2/rules/tls_config.go88
-rw-r--r--vendor/github.com/securego/gosec/v2/rules/unsafe.go53
-rw-r--r--vendor/github.com/securego/gosec/v2/rules/weakcrypto.go58
45 files changed, 4861 insertions, 0 deletions
diff --git a/vendor/github.com/securego/gosec/v2/.gitignore b/vendor/github.com/securego/gosec/v2/.gitignore
new file mode 100644
index 000000000..f282cda24
--- /dev/null
+++ b/vendor/github.com/securego/gosec/v2/.gitignore
@@ -0,0 +1,35 @@
+# transient files
+/image
+
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+*.swp
+/gosec
+
+# Folders
+_obj
+_test
+vendor
+dist
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
+*.test
+*.prof
+
+.DS_Store
+
+.vscode
diff --git a/vendor/github.com/securego/gosec/v2/.goreleaser.yml b/vendor/github.com/securego/gosec/v2/.goreleaser.yml
new file mode 100644
index 000000000..4f8fc4128
--- /dev/null
+++ b/vendor/github.com/securego/gosec/v2/.goreleaser.yml
@@ -0,0 +1,20 @@
+---
+project_name: gosec
+
+release:
+ github:
+ owner: securego
+ name: gosec
+
+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
diff --git a/vendor/github.com/securego/gosec/v2/Dockerfile b/vendor/github.com/securego/gosec/v2/Dockerfile
new file mode 100644
index 000000000..a874697e9
--- /dev/null
+++ b/vendor/github.com/securego/gosec/v2/Dockerfile
@@ -0,0 +1,14 @@
+ARG GO_VERSION
+FROM golang:${GO_VERSION}-alpine AS builder
+RUN apk add --update --no-cache ca-certificates make git curl gcc libc-dev
+RUN mkdir -p /build
+WORKDIR /build
+COPY . /build/
+RUN go mod download
+RUN make build-linux
+
+FROM golang:${GO_VERSION}-alpine
+RUN apk add --update --no-cache ca-certificates git gcc libc-dev
+ENV GO111MODULE on
+COPY --from=builder /build/gosec /bin/gosec
+ENTRYPOINT ["/bin/gosec"]
diff --git a/vendor/github.com/securego/gosec/v2/LICENSE.txt b/vendor/github.com/securego/gosec/v2/LICENSE.txt
new file mode 100644
index 000000000..1756c7821
--- /dev/null
+++ b/vendor/github.com/securego/gosec/v2/LICENSE.txt
@@ -0,0 +1,154 @@
+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:
+
+You must give any other recipients of the Work or Derivative Works a copy of
+this License; and You must cause any modified files to carry prominent notices
+stating that You changed the files; and 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 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
diff --git a/vendor/github.com/securego/gosec/v2/Makefile b/vendor/github.com/securego/gosec/v2/Makefile
new file mode 100644
index 000000000..217651c43
--- /dev/null
+++ b/vendor/github.com/securego/gosec/v2/Makefile
@@ -0,0 +1,71 @@
+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 := '-w -s'
+CGO_ENABLED = 0
+GO := GO111MODULE=on go
+GO_NOMOD :=GO111MODULE=off go
+GOPATH ?= $(shell $(GO) env GOPATH)
+GOBIN ?= $(GOPATH)/bin
+GOLINT ?= $(GOBIN)/golint
+GOSEC ?= $(GOBIN)/gosec
+GINKGO ?= $(GOBIN)/ginkgo
+GO_VERSION = 1.14
+
+default:
+ $(MAKE) build
+
+install-test-deps:
+ $(GO_NOMOD) get -u github.com/onsi/ginkgo/ginkgo
+ $(GO_NOMOD) get -u golang.org/x/crypto/ssh
+ $(GO_NOMOD) get -u github.com/lib/pq
+
+test: install-test-deps build fmt lint sec
+ $(GINKGO) -r -v
+
+fmt:
+ @echo "FORMATTING"
+ @FORMATTED=`$(GO) fmt ./...`
+ @([[ ! -z "$(FORMATTED)" ]] && printf "Fixed unformatted files:\n$(FORMATTED)") || true
+
+lint:
+ @echo "LINTING"
+ $(GO_NOMOD) get -u golang.org/x/lint/golint
+ $(GOLINT) -set_exit_status ./...
+ @echo "VETTING"
+ $(GO) vet ./...
+
+sec:
+ @echo "SECURITY SCANNING"
+ ./$(BIN) ./...
+
+test-coverage: install-test-deps
+ go test -race -coverprofile=coverage.txt -covermode=atomic
+
+build:
+ go build -o $(BIN) ./cmd/gosec/
+
+clean:
+ rm -rf build vendor dist coverage.txt
+ rm -f release image $(BIN)
+
+release:
+ @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:
+ @echo "Building the Docker image..."
+ docker build -t $(IMAGE_REPO)/$(BIN):$(GIT_TAG) --build-arg GO_VERSION=$(GO_VERSION) .
+ 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/securego/gosec/v2/README.md b/vendor/github.com/securego/gosec/v2/README.md
new file mode 100644
index 000000000..52be73423
--- /dev/null
+++ b/vendor/github.com/securego/gosec/v2/README.md
@@ -0,0 +1,326 @@
+
+# gosec - Golang Security Checker
+
+Inspects source code for security problems by scanning the Go AST.
+
+<img src="https://securego.io/img/gosec.png" width="320">
+
+## License
+
+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 [here](http://www.apache.org/licenses/LICENSE-2.0).
+
+## Project status
+
+[![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/3218/badge)](https://bestpractices.coreinfrastructure.org/projects/3218)
+[![Build Status](https://github.com/securego/gosec/workflows/CI/badge.svg)](https://github.com/securego/gosec/actions?query=workflows%3ACI)
+[![Coverage Status](https://codecov.io/gh/securego/gosec/branch/master/graph/badge.svg)](https://codecov.io/gh/securego/gosec)
+[![GoReport](https://goreportcard.com/badge/github.com/securego/gosec)](https://goreportcard.com/badge/github.com/securego/gosec)
+[![GoDoc](https://godoc.org/github.com/securego/gosec?status.svg)](https://godoc.org/github.com/securego/gosec)
+[![Docs](https://readthedocs.org/projects/docs/badge/?version=latest)](https://securego.io/)
+[![Downloads](https://img.shields.io/github/downloads/securego/gosec/total.svg)](https://github.com/securego/gosec/releases)
+[![Docker Pulls](https://img.shields.io/docker/pulls/securego/gosec.svg)](https://hub.docker.com/r/securego/gosec/tags)
+[![Slack](http://securego.herokuapp.com/badge.svg)](http://securego.herokuapp.com)
+
+## Install
+
+### CI Installation
+
+```bash
+# binary will be $GOPATH/bin/gosec
+curl -sfL https://raw.githubusercontent.com/securego/gosec/master/install.sh | sh -s -- -b $GOPATH/bin vX.Y.Z
+
+# or install it into ./bin/
+curl -sfL https://raw.githubusercontent.com/securego/gosec/master/install.sh | sh -s vX.Y.Z
+
+# In alpine linux (as it does not come with curl by default)
+wget -O - -q https://raw.githubusercontent.com/securego/gosec/master/install.sh | sh -s vX.Y.Z
+
+# If you want to use the checksums provided on the "Releases" page
+# then you will have to download a tar.gz file for your operating system instead of a binary file
+wget https://github.com/securego/gosec/releases/download/vX.Y.Z/gosec_vX.Y.Z_OS.tar.gz
+
+# The file will be in the current folder where you run the command
+# and you can check the checksum like this
+echo "<check sum from the check sum file> gosec_vX.Y.Z_OS.tar.gz" | sha256sum -c -
+
+gosec --help
+```
+### GitHub Action
+
+You can run `gosec` as a GitHub action as follows:
+
+```yaml
+name: Run Gosec
+on:
+ push:
+ branches:
+ - master
+ pull_request:
+ branches:
+ - master
+jobs:
+ tests:
+ runs-on: ubuntu-latest
+ env:
+ GO111MODULE: on
+ steps:
+ - name: Checkout Source
+ uses: actions/checkout@v2
+ - name: Run Gosec Security Scanner
+ uses: securego/gosec@master
+ with:
+ args: ./...
+```
+
+### Local Installation
+
+```bash
+go get github.com/securego/gosec/cmd/gosec
+```
+
+## Usage
+
+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.
+
+
+### Available rules
+
+- G101: Look for hard coded credentials
+- G102: Bind to all interfaces
+- G103: Audit the use of unsafe block
+- G104: Audit errors not checked
+- G106: Audit the use of ssh.InsecureIgnoreHostKey
+- G107: Url provided to HTTP request as taint input
+- G108: Profiling endpoint automatically exposed on /debug/pprof
+- G109: Potential Integer overflow made by strconv.Atoi result conversion to int16/32
+- G110: Potential DoS vulnerability via decompression bomb
+- G201: SQL query construction using format string
+- G202: SQL query construction using string concatenation
+- G203: Use of unescaped data in HTML templates
+- G204: Audit use of command execution
+- G301: Poor file permissions used when creating a directory
+- G302: Poor file permissions used with chmod
+- G303: Creating tempfile using a predictable path
+- G304: File path provided as taint input
+- G305: File traversal when extracting zip archive
+- G306: Poor file permissions used when writing to a new file
+- G307: Deferring a method which returns an error
+- 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)
+- G501: Import blacklist: crypto/md5
+- G502: Import blacklist: crypto/des
+- G503: Import blacklist: crypto/rc4
+- G504: Import blacklist: net/http/cgi
+- G505: Import blacklist: crypto/sha1
+- G601: Implicit memory aliasing of items from a range statement
+
+### Retired rules
+
+- G105: Audit the use of math/big.Int.Exp - [CVE is fixed](https://github.com/golang/go/issues/15184)
+
+### Selecting rules
+
+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.
+
+```bash
+# Run a specific set of rules
+$ gosec -include=G101,G203,G401 ./...
+
+# Run everything except for rule G303
+$ gosec -exclude=G303 ./...
+```
+### CWE Mapping
+
+Every issue detected by `gosec` is mapped to a [CWE (Common Weakness Enumeration)](http://cwe.mitre.org/data/index.html) which describes in more generic terms the vulnerability. The exact mapping can be found [here](https://github.com/securego/gosec/blob/53be8dd8644ee48802114178cff6eb7e29757414/issue.go#L49).
+
+### Configuration
+
+A number of global settings can be provided in a configuration file as follows:
+
+```JSON
+{
+ "global": {
+ "nosec": "enabled",
+ "audit": "enabled"
+ }
+}
+```
+
+- `nosec`: this setting will overwrite all `#nosec` directives defined throughout the code base
+- `audit`: runs in audit mode which enables addition checks that for normal code analysis might be too nosy
+
+```bash
+# Run with a global configuration file
+$ gosec -conf config.json .
+```
+Also some rules accept configuration. For instance on rule `G104`, it is possible to define packages along with a list
+of functions which will be skipped when auditing the not checked errors:
+
+```JSON
+{
+ "G104": {
+ "io/ioutil": ["WriteFile"]
+ }
+}
+```
+
+You can also configure the hard-coded credentials rule `G101` with additional patters, or adjust the entropy threshold:
+
+```JSON
+{
+ "G101": {
+ "pattern": "(?i)passwd|pass|password|pwd|secret|private_key|token",
+ "ingnore_entropy": false,
+ "entropy_threshold": "80.0",
+ "per_char_threshold": "3.0",
+ "trucate": "32"
+ }
+}
+```
+
+### Dependencies
+
+gosec will fetch automatically the dependencies of the code which is being analyzed when go module is turned on (e.g.` GO111MODULE=on`). If this is not the case,
+the dependencies need to be explicitly downloaded by running the `go get -d` command before the scan.
+
+### Excluding test files and folders
+
+gosec will ignore test files across all packages and any dependencies in your vendor directory.
+
+The scanning of test files can be enabled with the following flag:
+
+```bash
+
+gosec -tests ./...
+```
+
+Also additional folders can be excluded as follows:
+
+```bash
+ gosec -exclude-dir=rules -exclude-dir=cmd ./...
+```
+
+### Annotating code
+
+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 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
+
+import "md5" // #nosec
+
+
+func main(){
+
+ /* #nosec */
+ if x > y {
+ h := md5.New() // this will also be ignored
+ }
+
+}
+
+```
+
+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:
+
+```bash
+gosec -nosec=true ./...
+```
+
+### Build tags
+
+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:
+
+```bash
+gosec -tag debug,ignore ./...
+```
+
+### Output formats
+
+gosec currently supports `text`, `json`, `yaml`, `csv`, `sonarqube`, `JUnit XML`, `html` and `golint` 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:
+
+```bash
+# Write output in json format to results.json
+$ gosec -fmt=json -out=results.json *.go
+```
+
+## Development
+
+### Build
+
+You can build the binary with:
+```bash
+make
+```
+
+### Tests
+
+You can run all unit tests using:
+```bash
+make test
+```
+
+### Release
+
+You can create a release by tagging the version as follows:
+
+``` bash
+git tag v1.0.0 -m "Release version v1.0.0"
+git push origin v1.0.0
+```
+
+The GitHub [release workflow](.github/workflows/release.yml) triggers immediately after the tag is pushed upstream. This flow will
+release the binaries using the [goreleaser](https://goreleaser.com/actions/) action and then it will build and publish the docker image into Docker Hub.
+
+### Docker image
+
+You can also build locally the docker image by using the command:
+
+```bash
+make image
+```
+
+You can run the `gosec` tool in a container against your local Go project. You only have to mount the project
+into a volume as follows:
+
+```bash
+docker run -it -v <YOUR PROJECT PATH>/<PROJECT>:/<PROJECT> securego/gosec /<PROJECT>/...
+```
+
+### Generate TLS rule
+
+The configuration of TLS rule can be generated from [Mozilla's TLS ciphers recommendation](https://statics.tls.security.mozilla.org/server-side-tls-conf.json).
+
+First you need to install the generator tool:
+
+```bash
+go get github.com/securego/gosec/cmd/tlsconfig/...
+```
+
+You can invoke now the `go generate` in the root of the project:
+
+```bash
+go generate ./...
+```
+
+This will generate the `rules/tls_config.go` file which will contain the current ciphers recommendation from Mozilla.
diff --git a/vendor/github.com/securego/gosec/v2/action.yml b/vendor/github.com/securego/gosec/v2/action.yml
new file mode 100644
index 000000000..aab6c8039
--- /dev/null
+++ b/vendor/github.com/securego/gosec/v2/action.yml
@@ -0,0 +1,19 @@
+name: 'Gosec Security Checker'
+description: 'Runs the gosec security checker'
+author: '@ccojocar'
+
+inputs:
+ args:
+ description: 'Arguments for gosec'
+ required: true
+ default: '-h'
+
+runs:
+ using: 'docker'
+ image: 'docker://securego/gosec'
+ args:
+ - ${{ inputs.args }}
+
+branding:
+ icon: 'shield'
+ color: 'blue'
diff --git a/vendor/github.com/securego/gosec/v2/analyzer.go b/vendor/github.com/securego/gosec/v2/analyzer.go
new file mode 100644
index 000000000..ca4440c20
--- /dev/null
+++ b/vendor/github.com/securego/gosec/v2/analyzer.go
@@ -0,0 +1,378 @@
+// (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 gosec holds the central scanning logic used by gosec security scanner
+package gosec
+
+import (
+ "fmt"
+ "go/ast"
+ "go/build"
+ "go/token"
+ "go/types"
+ "log"
+ "os"
+ "path"
+ "path/filepath"
+ "reflect"
+ "regexp"
+ "strconv"
+
+ "strings"
+
+ "golang.org/x/tools/go/packages"
+)
+
+// LoadMode controls the amount of details to return when loading the packages
+const LoadMode = packages.NeedName |
+ packages.NeedFiles |
+ packages.NeedCompiledGoFiles |
+ packages.NeedImports |
+ packages.NeedTypes |
+ packages.NeedTypesSizes |
+ packages.NeedTypesInfo |
+ packages.NeedSyntax
+
+// The Context is populated with data parsed from the source code as it is scanned.
+// It is passed through to all rule functions as they are called. Rules may use
+// this data in conjunction withe the encountered AST node.
+type Context struct {
+ FileSet *token.FileSet
+ Comments ast.CommentMap
+ Info *types.Info
+ Pkg *types.Package
+ PkgFiles []*ast.File
+ Root *ast.File
+ Config Config
+ Imports *ImportTracker
+ Ignores []map[string]bool
+ PassedValues map[string]interface{}
+}
+
+// Metrics used when reporting information about a scanning run.
+type Metrics struct {
+ NumFiles int `json:"files"`
+ NumLines int `json:"lines"`
+ NumNosec int `json:"nosec"`
+ NumFound int `json:"found"`
+}
+
+// Analyzer object is the main object of gosec. It has methods traverse an AST
+// and invoke the correct checking rules as on each node as required.
+type Analyzer struct {
+ ignoreNosec bool
+ ruleset RuleSet
+ context *Context
+ config Config
+ logger *log.Logger
+ issues []*Issue
+ stats *Metrics
+ errors map[string][]Error // keys are file paths; values are the golang errors in those files
+ tests bool
+}
+
+// NewAnalyzer builds a new analyzer.
+func NewAnalyzer(conf Config, tests bool, logger *log.Logger) *Analyzer {
+ ignoreNoSec := false
+ if enabled, err := conf.IsGlobalEnabled(Nosec); err == nil {
+ ignoreNoSec = enabled
+ }
+ if logger == nil {
+ logger = log.New(os.Stderr, "[gosec]", log.LstdFlags)
+ }
+ return &Analyzer{
+ ignoreNosec: ignoreNoSec,
+ ruleset: make(RuleSet),
+ context: &Context{},
+ config: conf,
+ logger: logger,
+ issues: make([]*Issue, 0, 16),
+ stats: &Metrics{},
+ errors: make(map[string][]Error),
+ tests: tests,
+ }
+}
+
+// SetConfig upates the analyzer configuration
+func (gosec *Analyzer) SetConfig(conf Config) {
+ gosec.config = conf
+}
+
+// Config returns the current configuration
+func (gosec *Analyzer) Config() Config {
+ return gosec.config
+}
+
+// LoadRules instantiates all the rules to be used when analyzing source
+// packages
+func (gosec *Analyzer) LoadRules(ruleDefinitions map[string]RuleBuilder) {
+ for id, def := range ruleDefinitions {
+ r, nodes := def(id, gosec.config)
+ gosec.ruleset.Register(r, nodes...)
+ }
+}
+
+// Process kicks off the analysis process for a given package
+func (gosec *Analyzer) Process(buildTags []string, packagePaths ...string) error {
+ config := gosec.pkgConfig(buildTags)
+ for _, pkgPath := range packagePaths {
+ pkgs, err := gosec.load(pkgPath, config)
+ if err != nil {
+ gosec.AppendError(pkgPath, err)
+ }
+ for _, pkg := range pkgs {
+ if pkg.Name != "" {
+ err := gosec.ParseErrors(pkg)
+ if err != nil {
+ return fmt.Errorf("parsing errors in pkg %q: %v", pkg.Name, err)
+ }
+ gosec.Check(pkg)
+ }
+ }
+ }
+ sortErrors(gosec.errors)
+ return nil
+}
+
+func (gosec *Analyzer) pkgConfig(buildTags []string) *packages.Config {
+ flags := []string{}
+ if len(buildTags) > 0 {
+ tagsFlag := "-tags=" + strings.Join(buildTags, " ")
+ flags = append(flags, tagsFlag)
+ }
+ return &packages.Config{
+ Mode: LoadMode,
+ BuildFlags: flags,
+ Tests: gosec.tests,
+ }
+}
+
+func (gosec *Analyzer) load(pkgPath string, conf *packages.Config) ([]*packages.Package, error) {
+ abspath, err := GetPkgAbsPath(pkgPath)
+ if err != nil {
+ gosec.logger.Printf("Skipping: %s. Path doesn't exist.", abspath)
+ return []*packages.Package{}, nil
+ }
+
+ gosec.logger.Println("Import directory:", abspath)
+ basePackage, err := build.Default.ImportDir(pkgPath, build.ImportComment)
+ if err != nil {
+ return []*packages.Package{}, fmt.Errorf("importing dir %q: %v", pkgPath, err)
+ }
+
+ var packageFiles []string
+ for _, filename := range basePackage.GoFiles {
+ packageFiles = append(packageFiles, path.Join(pkgPath, filename))
+ }
+ for _, filename := range basePackage.CgoFiles {
+ packageFiles = append(packageFiles, path.Join(pkgPath, filename))
+ }
+
+ if gosec.tests {
+ testsFiles := []string{}
+ testsFiles = append(testsFiles, basePackage.TestGoFiles...)
+ testsFiles = append(testsFiles, basePackage.XTestGoFiles...)
+ for _, filename := range testsFiles {
+ packageFiles = append(packageFiles, path.Join(pkgPath, filename))
+ }
+ }
+
+ pkgs, err := packages.Load(conf, packageFiles...)
+ if err != nil {
+ return []*packages.Package{}, fmt.Errorf("loading files from package %q: %v", pkgPath, err)
+ }
+ return pkgs, nil
+}
+
+// Check runs analysis on the given package
+func (gosec *Analyzer) Check(pkg *packages.Package) {
+ gosec.logger.Println("Checking package:", pkg.Name)
+ for _, file := range pkg.Syntax {
+ checkedFile := pkg.Fset.File(file.Pos()).Name()
+ // Skip the no-Go file from analysis (e.g. a Cgo files is expanded in 3 different files
+ // stored in the cache which do not need to by analyzed)
+ if filepath.Ext(checkedFile) != ".go" {
+ continue
+ }
+ gosec.logger.Println("Checking file:", checkedFile)
+ gosec.context.FileSet = pkg.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.TypesInfo
+ gosec.context.Pkg = pkg.Types
+ gosec.context.PkgFiles = pkg.Syntax
+ gosec.context.Imports = NewImportTracker()
+ gosec.context.Imports.TrackFile(file)
+ gosec.context.PassedValues = make(map[string]interface{})
+ ast.Walk(gosec, file)
+ gosec.stats.NumFiles++
+ gosec.stats.NumLines += pkg.Fset.File(file.Pos()).LineCount()
+ }
+}
+
+// ParseErrors parses the errors from given package
+func (gosec *Analyzer) ParseErrors(pkg *packages.Package) error {
+ if len(pkg.Errors) == 0 {
+ return nil
+ }
+ for _, pkgErr := range pkg.Errors {
+ parts := strings.Split(pkgErr.Pos, ":")
+ file := parts[0]
+ var err error
+ var line int
+ if len(parts) > 1 {
+ if line, err = strconv.Atoi(parts[1]); err != nil {
+ return fmt.Errorf("parsing line: %v", err)
+ }
+ }
+ var column int
+ if len(parts) > 2 {
+ if column, err = strconv.Atoi(parts[2]); err != nil {
+ return fmt.Errorf("parsing column: %v", err)
+ }
+ }
+ msg := strings.TrimSpace(pkgErr.Msg)
+ newErr := NewError(line, column, msg)
+ if errSlice, ok := gosec.errors[file]; ok {
+ gosec.errors[file] = append(errSlice, *newErr)
+ } else {
+ errSlice = []Error{}
+ gosec.errors[file] = append(errSlice, *newErr)
+ }
+ }
+ return nil
+}
+
+// AppendError appends an error to the file errors
+func (gosec *Analyzer) AppendError(file string, err error) {
+ // Do not report the error for empty packages (e.g. files excluded from build with a tag)
+ r := regexp.MustCompile(`no buildable Go source files in`)
+ if r.MatchString(err.Error()) {
+ return
+ }
+ errors := []Error{}
+ if ferrs, ok := gosec.errors[file]; ok {
+ errors = ferrs
+ }
+ ferr := NewError(0, 0, err.Error())
+ errors = append(errors, *ferr)
+ gosec.errors[file] = errors
+}
+
+// ignore a node (and sub-tree) if it is tagged with a nosec tag comment
+func (gosec *Analyzer) ignore(n ast.Node) ([]string, bool) {
+ if groups, ok := gosec.context.Comments[n]; ok && !gosec.ignoreNosec {
+
+ // Checks if an alternative for #nosec is set and, if not, uses the default.
+ noSecDefaultTag := "#nosec"
+ noSecAlternativeTag, err := gosec.config.GetGlobal(NoSecAlternative)
+ if err != nil {
+ noSecAlternativeTag = noSecDefaultTag
+ }
+
+ for _, group := range groups {
+
+ foundDefaultTag := strings.Contains(group.Text(), noSecDefaultTag)
+ foundAlternativeTag := strings.Contains(group.Text(), noSecAlternativeTag)
+
+ if foundDefaultTag || foundAlternativeTag {
+ gosec.stats.NumNosec++
+
+ // Pull out the specific rules that are listed to be ignored.
+ re := regexp.MustCompile(`(G\d{3})`)
+ matches := re.FindAllStringSubmatch(group.Text(), -1)
+
+ // If no specific rules were given, ignore everything.
+ if len(matches) == 0 {
+ return nil, true
+ }
+
+ // Find the rule IDs to ignore.
+ var ignores []string
+ for _, v := range matches {
+ ignores = append(ignores, v[1])
+ }
+ return ignores, false
+ }
+ }
+ }
+ return nil, false
+}
+
+// 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 (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(gosec.context.Ignores) > 0 {
+ gosec.context.Ignores = gosec.context.Ignores[1:]
+ }
+ return gosec
+ }
+
+ // Get any new rule exclusions.
+ ignoredRules, ignoreAll := gosec.ignore(n)
+ if ignoreAll {
+ return nil
+ }
+
+ // Now create the union of exclusions.
+ ignores := map[string]bool{}
+ if len(gosec.context.Ignores) > 0 {
+ for k, v := range gosec.context.Ignores[0] {
+ ignores[k] = v
+ }
+ }
+
+ for _, v := range ignoredRules {
+ ignores[v] = true
+ }
+
+ // Push the new set onto the stack.
+ gosec.context.Ignores = append([]map[string]bool{ignores}, gosec.context.Ignores...)
+
+ // Track aliased and initialization imports
+ gosec.context.Imports.TrackImport(n)
+
+ for _, rule := range gosec.ruleset.RegisteredFor(n) {
+ if _, ok := ignores[rule.ID()]; ok {
+ continue
+ }
+ issue, err := rule.Match(n, gosec.context)
+ if err != nil {
+ file, line := GetLocation(n, gosec.context)
+ file = path.Base(file)
+ gosec.logger.Printf("Rule error: %v => %s (%s:%d)\n", reflect.TypeOf(rule), err, file, line)
+ }
+ if issue != nil {
+ gosec.issues = append(gosec.issues, issue)
+ gosec.stats.NumFound++
+ }
+ }
+ return gosec
+}
+
+// Report returns the current issues discovered and the metrics about the scan
+func (gosec *Analyzer) Report() ([]*Issue, *Metrics, map[string][]Error) {
+ return gosec.issues, gosec.stats, gosec.errors
+}
+
+// Reset clears state such as context, issues and metrics from the configured analyzer
+func (gosec *Analyzer) Reset() {
+ gosec.context = &Context{}
+ gosec.issues = make([]*Issue, 0, 16)
+ gosec.stats = &Metrics{}
+ gosec.ruleset = NewRuleSet()
+}
diff --git a/vendor/github.com/securego/gosec/v2/call_list.go b/vendor/github.com/securego/gosec/v2/call_list.go
new file mode 100644
index 000000000..115c6c88e
--- /dev/null
+++ b/vendor/github.com/securego/gosec/v2/call_list.go
@@ -0,0 +1,109 @@
+//
+// 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 gosec
+
+import (
+ "go/ast"
+ "strings"
+)
+
+const vendorPath = "vendor/"
+
+type set map[string]bool
+
+// CallList is used to check for usage of specific packages
+// and functions.
+type CallList map[string]set
+
+// NewCallList creates a new empty CallList
+func NewCallList() CallList {
+ return make(CallList)
+}
+
+// AddAll will add several calls to the call list at once
+func (c CallList) AddAll(selector string, idents ...string) {
+ for _, ident := range idents {
+ c.Add(selector, ident)
+ }
+}
+
+// Add a selector and call to the call list
+func (c CallList) Add(selector, ident string) {
+ if _, ok := c[selector]; !ok {
+ c[selector] = make(set)
+ }
+ c[selector][ident] = true
+}
+
+// Contains returns true if the package and function are
+/// members of this call list.
+func (c CallList) Contains(selector, ident string) bool {
+ if idents, ok := c[selector]; ok {
+ _, found := idents[ident]
+ return found
+ }
+ return false
+}
+
+// ContainsPointer returns true if a pointer to the selector type or the type
+// itself is a members of this call list.
+func (c CallList) ContainsPointer(selector, indent string) bool {
+ if strings.HasPrefix(selector, "*") {
+ if c.Contains(selector, indent) {
+ return true
+ }
+ s := strings.TrimPrefix(selector, "*")
+ return c.Contains(s, indent)
+ }
+ return false
+}
+
+// ContainsPkgCallExpr resolves the call expression name and type, and then further looks
+// up the package path for that type. Finally, it determines if the call exists within the call list
+func (c CallList) ContainsPkgCallExpr(n ast.Node, ctx *Context, stripVendor bool) *ast.CallExpr {
+ selector, ident, err := GetCallInfo(n, ctx)
+ if err != nil {
+ return nil
+ }
+
+ // Use only explicit path (optionally strip vendor path prefix) to reduce conflicts
+ path, ok := GetImportPath(selector, ctx)
+ if !ok {
+ return nil
+ }
+ if stripVendor {
+ if vendorIdx := strings.Index(path, vendorPath); vendorIdx >= 0 {
+ path = path[vendorIdx+len(vendorPath):]
+ }
+ }
+ if !c.Contains(path, ident) {
+ return nil
+ }
+
+ return n.(*ast.CallExpr)
+}
+
+// ContainsCallExpr resolves the call expression name and type, and then determines
+// if the call exists with the call list
+func (c CallList) ContainsCallExpr(n ast.Node, ctx *Context) *ast.CallExpr {
+ selector, ident, err := GetCallInfo(n, ctx)
+ if err != nil {
+ return nil
+ }
+ if !c.Contains(selector, ident) && !c.ContainsPointer(selector, ident) {
+ return nil
+ }
+
+ return n.(*ast.CallExpr)
+}
diff --git a/vendor/github.com/securego/gosec/v2/config.go b/vendor/github.com/securego/gosec/v2/config.go
new file mode 100644
index 000000000..5b7f73936
--- /dev/null
+++ b/vendor/github.com/securego/gosec/v2/config.go
@@ -0,0 +1,125 @@
+package gosec
+
+import (
+ "bytes"
+ "encoding/json"
+ "fmt"
+ "io"
+ "io/ioutil"
+)
+
+const (
+ // Globals are applicable to all rules and used for general
+ // configuration settings for gosec.
+ Globals = "global"
+)
+
+// GlobalOption defines the name of the global options
+type GlobalOption string
+
+const (
+ // Nosec global option for #nosec directive
+ Nosec GlobalOption = "nosec"
+ // Audit global option which indicates that gosec runs in audit mode
+ Audit GlobalOption = "audit"
+ // NoSecAlternative global option alternative for #nosec directive
+ NoSecAlternative GlobalOption = "#nosec"
+)
+
+// Config is used to provide configuration and customization to each of the rules.
+type Config map[string]interface{}
+
+// NewConfig initializes a new configuration instance. The configuration data then
+// needs to be loaded via c.ReadFrom(strings.NewReader("config data"))
+// or from a *os.File.
+func NewConfig() Config {
+ cfg := make(Config)
+ cfg[Globals] = make(map[GlobalOption]string)
+ return cfg
+}
+
+func (c Config) keyToGlobalOptions(key string) GlobalOption {
+ return GlobalOption(key)
+}
+
+func (c Config) convertGlobals() {
+ if globals, ok := c[Globals]; ok {
+ if settings, ok := globals.(map[string]interface{}); ok {
+ validGlobals := map[GlobalOption]string{}
+ for k, v := range settings {
+ validGlobals[c.keyToGlobalOptions(k)] = fmt.Sprintf("%v", v)
+ }
+ c[Globals] = validGlobals
+ }
+ }
+}
+
+// ReadFrom implements the io.ReaderFrom interface. This
+// should be used with io.Reader to load configuration from
+//file or from string etc.
+func (c Config) ReadFrom(r io.Reader) (int64, error) {
+ data, err := ioutil.ReadAll(r)
+ if err != nil {
+ return int64(len(data)), err
+ }
+ if err = json.Unmarshal(data, &c); err != nil {
+ return int64(len(data)), err
+ }
+ c.convertGlobals()
+ return int64(len(data)), nil
+}
+
+// WriteTo implements the io.WriteTo interface. This should
+// be used to save or print out the configuration information.
+func (c Config) WriteTo(w io.Writer) (int64, error) {
+ data, err := json.Marshal(c)
+ if err != nil {
+ return int64(len(data)), err
+ }
+ return io.Copy(w, bytes.NewReader(data))
+}
+
+// Get returns the configuration section for the supplied key
+func (c Config) Get(section string) (interface{}, error) {
+ settings, found := c[section]
+ if !found {
+ return nil, fmt.Errorf("Section %s not in configuration", section)
+ }
+ return settings, nil
+}
+
+// Set section in the configuration to specified value
+func (c Config) Set(section string, value interface{}) {
+ c[section] = value
+}
+
+// GetGlobal returns value associated with global configuration option
+func (c Config) GetGlobal(option GlobalOption) (string, error) {
+ if globals, ok := c[Globals]; ok {
+ if settings, ok := globals.(map[GlobalOption]string); ok {
+ if value, ok := settings[option]; ok {
+ return value, nil
+ }
+ return "", fmt.Errorf("global setting for %s not found", option)
+ }
+ }
+ return "", fmt.Errorf("no global config options found")
+}
+
+// SetGlobal associates a value with a global configuration option
+func (c Config) SetGlobal(option GlobalOption, value string) {
+ if globals, ok := c[Globals]; ok {
+ if settings, ok := globals.(map[GlobalOption]string); ok {
+ settings[option] = value
+ }
+ }
+}
+
+// IsGlobalEnabled checks if a global option is enabled
+func (c Config) IsGlobalEnabled(option GlobalOption) (bool, error) {
+ value, err := c.GetGlobal(option)
+ if err != nil {
+ return false, err
+ }
+ return (value == "true" || value == "enabled"), nil
+}
diff --git a/vendor/github.com/securego/gosec/v2/errors.go b/vendor/github.com/securego/gosec/v2/errors.go
new file mode 100644
index 000000000..a27aa5821
--- /dev/null
+++ b/vendor/github.com/securego/gosec/v2/errors.go
@@ -0,0 +1,33 @@
+package gosec
+
+import (
+ "sort"
+)
+
+// Error is used when there are golang errors while parsing the AST
+type Error struct {
+ Line int `json:"line"`
+ Column int `json:"column"`
+ Err string `json:"error"`
+}
+
+// NewError creates Error object
+func NewError(line, column int, err string) *Error {
+ return &Error{
+ Line: line,
+ Column: column,
+ Err: err,
+ }
+}
+
+// sortErros sorts the golang erros by line
+func sortErrors(allErrors map[string][]Error) {
+ for _, errors := range allErrors {
+ sort.Slice(errors, func(i, j int) bool {
+ if errors[i].Line == errors[j].Line {
+ return errors[i].Column <= errors[j].Column
+ }
+ return errors[i].Line < errors[j].Line
+ })
+ }
+}
diff --git a/vendor/github.com/securego/gosec/v2/go.mod b/vendor/github.com/securego/gosec/v2/go.mod
new file mode 100644
index 000000000..edfa3434c
--- /dev/null
+++ b/vendor/github.com/securego/gosec/v2/go.mod
@@ -0,0 +1,19 @@
+module github.com/securego/gosec/v2
+
+require (
+ github.com/davecgh/go-spew v1.1.1 // indirect
+ github.com/golang/protobuf v1.3.2 // indirect
+ github.com/gookit/color v1.2.4
+ github.com/kr/pretty v0.1.0 // indirect
+ github.com/mozilla/tls-observatory v0.0.0-20200317151703-4fa42e1c2dee
+ github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d
+ github.com/onsi/ginkgo v1.12.0
+ github.com/onsi/gomega v1.9.0
+ github.com/stretchr/testify v1.4.0 // indirect
+ golang.org/x/text v0.3.2 // indirect
+ golang.org/x/tools v0.0.0-20200331202046-9d5940d49312
+ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
+ gopkg.in/yaml.v2 v2.2.8
+)
+
+go 1.14
diff --git a/vendor/github.com/securego/gosec/v2/go.sum b/vendor/github.com/securego/gosec/v2/go.sum
new file mode 100644
index 000000000..fff56a309
--- /dev/null
+++ b/vendor/github.com/securego/gosec/v2/go.sum
@@ -0,0 +1,82 @@
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
+github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/gookit/color v1.2.4 h1:xOYBan3Fwlrqj1M1UN2TlHOCRiek3bGzWf/vPnJ1roE=
+github.com/gookit/color v1.2.4/go.mod h1:AhIE+pS6D4Ql0SQWbBeXPHw7gY0/sjHoA4s/n1KB7xg=
+github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
+github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/mozilla/tls-observatory v0.0.0-20200317151703-4fa42e1c2dee h1:1xJ+Xi9lYWLaaP4yB67ah0+548CD3110mCPWhVVjFkI=
+github.com/mozilla/tls-observatory v0.0.0-20200317151703-4fa42e1c2dee/go.mod h1:SrKMQvPiws7F7iqYp8/TX+IhxCYhzr6N/1yb8cwHsGk=
+github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d h1:AREM5mwr4u1ORQBMvzfzBgpsctsbQikCVpvC+tX285E=
+github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU=
+github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.12.0 h1:Iw5WCbBcaAAd0fpRb1c9r5YCylv4XDoCSigm1zLevwU=
+github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
+github.com/onsi/gomega v1.7.1 h1:K0jcRCwNQM3vFGh1ppMtDh/+7ApJrjldlX8fA0jDTLQ=
+github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
+github.com/onsi/gomega v1.9.0 h1:R1uwffexN6Pr340GtYRIdZmAiN4J+iw6WG4wog1DUXg=
+github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ=
+golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200226121028-0de0cce0169b h1:0mm1VjtFUOIlE1SbDlwjYaDxZVDP2S5ou6y0gSgXHu8=
+golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e h1:N7DeIrjYszNmSW409R3frPPwglRwMkXSBzwVbkOjLLA=
+golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20200331202046-9d5940d49312 h1:2PHG+Ia3gK1K2kjxZnSylizb//eyaMG8gDFbOG7wLV8=
+golang.org/x/tools v0.0.0-20200331202046-9d5940d49312/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
+gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
+gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
+gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
+gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
diff --git a/vendor/github.com/securego/gosec/v2/helpers.go b/vendor/github.com/securego/gosec/v2/helpers.go
new file mode 100644
index 000000000..40dc8e9c3
--- /dev/null
+++ b/vendor/github.com/securego/gosec/v2/helpers.go
@@ -0,0 +1,435 @@
+// (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 gosec
+
+import (
+ "errors"
+ "fmt"
+ "go/ast"
+ "go/token"
+ "go/types"
+ "os"
+ "os/user"
+ "path/filepath"
+ "regexp"
+ "runtime"
+ "strconv"
+ "strings"
+)
+
+// MatchCallByPackage ensures that the specified package is imported,
+// adjusts the name for any aliases and ignores cases that are
+// initialization only imports.
+//
+// Usage:
+// node, matched := MatchCallByPackage(n, ctx, "math/rand", "Read")
+//
+func MatchCallByPackage(n ast.Node, c *Context, pkg string, names ...string) (*ast.CallExpr, bool) {
+
+ importedName, found := GetImportedName(pkg, c)
+ if !found {
+ return nil, false
+ }
+
+ if callExpr, ok := n.(*ast.CallExpr); ok {
+ packageName, callName, err := GetCallInfo(callExpr, c)
+ if err != nil {
+ return nil, false
+ }
+ if packageName == importedName {
+ for _, name := range names {
+ if callName == name {
+ return callExpr, true
+ }
+ }
+ }
+ }
+ return nil, false
+}
+
+// MatchCompLit will match an ast.CompositeLit based on the supplied type
+func MatchCompLit(n ast.Node, ctx *Context, required string) *ast.CompositeLit {
+ if complit, ok := n.(*ast.CompositeLit); ok {
+ typeOf := ctx.Info.TypeOf(complit)
+ if typeOf.String() == required {
+ return complit
+ }
+ }
+ return nil
+}
+
+// GetInt will read and return an integer value from an ast.BasicLit
+func GetInt(n ast.Node) (int64, error) {
+ if node, ok := n.(*ast.BasicLit); ok && node.Kind == token.INT {
+ return strconv.ParseInt(node.Value, 0, 64)
+ }
+ return 0, fmt.Errorf("Unexpected AST node type: %T", n)
+}
+
+// GetFloat will read and return a float value from an ast.BasicLit
+func GetFloat(n ast.Node) (float64, error) {
+ if node, ok := n.(*ast.BasicLit); ok && node.Kind == token.FLOAT {
+ return strconv.ParseFloat(node.Value, 64)
+ }
+ return 0.0, fmt.Errorf("Unexpected AST node type: %T", n)
+}
+
+// GetChar will read and return a char value from an ast.BasicLit
+func GetChar(n ast.Node) (byte, error) {
+ if node, ok := n.(*ast.BasicLit); ok && node.Kind == token.CHAR {
+ return node.Value[0], nil
+ }
+ return 0, fmt.Errorf("Unexpected AST node type: %T", n)
+}
+
+// GetString will read and return a string value from an ast.BasicLit
+func GetString(n ast.Node) (string, error) {
+ if node, ok := n.(*ast.BasicLit); ok && node.Kind == token.STRING {
+ return strconv.Unquote(node.Value)
+ }
+ return "", fmt.Errorf("Unexpected AST node type: %T", n)
+}
+
+// GetCallObject returns the object and call expression and associated
+// object for a given AST node. nil, nil will be returned if the
+// object cannot be resolved.
+func GetCallObject(n ast.Node, ctx *Context) (*ast.CallExpr, types.Object) {
+ switch node := n.(type) {
+ case *ast.CallExpr:
+ switch fn := node.Fun.(type) {
+ case *ast.Ident:
+ return node, ctx.Info.Uses[fn]
+ case *ast.SelectorExpr:
+ return node, ctx.Info.Uses[fn.Sel]
+ }
+ }
+ return nil, nil
+}
+
+// GetCallInfo returns the package or type and name associated with a
+// call expression.
+func GetCallInfo(n ast.Node, ctx *Context) (string, string, error) {
+ switch node := n.(type) {
+ case *ast.CallExpr:
+ switch fn := node.Fun.(type) {
+ case *ast.SelectorExpr:
+ switch expr := fn.X.(type) {
+ case *ast.Ident:
+ if expr.Obj != nil && expr.Obj.Kind == ast.Var {
+ t := ctx.Info.TypeOf(expr)
+ if t != nil {
+ return t.String(), fn.Sel.Name, nil
+ }
+ return "undefined", fn.Sel.Name, fmt.Errorf("missing type info")
+ }
+ return expr.Name, fn.Sel.Name, nil
+ case *ast.SelectorExpr:
+ if expr.Sel != nil {
+ t := ctx.Info.TypeOf(expr.Sel)
+ if t != nil {
+ return t.String(), fn.Sel.Name, nil
+ }
+ return "undefined", fn.Sel.Name, fmt.Errorf("missing type info")
+ }
+ case *ast.CallExpr:
+ switch call := expr.Fun.(type) {
+ case *ast.Ident:
+ if call.Name == "new" {
+ t := ctx.Info.TypeOf(expr.Args[0])
+ if t != nil {
+ return t.String(), fn.Sel.Name, nil
+ }
+ return "undefined", fn.Sel.Name, fmt.Errorf("missing type info")
+ }
+ if call.Obj != nil {
+ switch decl := call.Obj.Decl.(type) {
+ case *ast.FuncDecl:
+ ret := decl.Type.Results
+ if ret != nil && len(ret.List) > 0 {
+ ret1 := ret.List[0]
+ if ret1 != nil {
+ t := ctx.Info.TypeOf(ret1.Type)
+ if t != nil {
+ return t.String(), fn.Sel.Name, nil
+ }
+ return "undefined", fn.Sel.Name, fmt.Errorf("missing type info")
+ }
+ }
+ }
+ }
+
+ }
+ }
+ case *ast.Ident:
+ return ctx.Pkg.Name(), fn.Name, nil
+ }
+ }
+
+ return "", "", fmt.Errorf("unable to determine call info")
+}
+
+// GetCallStringArgsValues returns the values of strings arguments if they can be resolved
+func GetCallStringArgsValues(n ast.Node, ctx *Context) []string {
+ values := []string{}
+ switch node := n.(type) {
+ case *ast.CallExpr:
+ for _, arg := range node.Args {
+ switch param := arg.(type) {
+ case *ast.BasicLit:
+ value, err := GetString(param)
+ if err == nil {
+ values = append(values, value)
+ }
+ case *ast.Ident:
+ values = append(values, GetIdentStringValues(param)...)
+ }
+ }
+ }
+ return values
+}
+
+// GetIdentStringValues return the string values of an Ident if they can be resolved
+func GetIdentStringValues(ident *ast.Ident) []string {
+ values := []string{}
+ obj := ident.Obj
+ if obj != nil {
+ switch decl := obj.Decl.(type) {
+ case *ast.ValueSpec:
+ for _, v := range decl.Values {
+ value, err := GetString(v)
+ if err == nil {
+ values = append(values, value)
+ }
+ }
+ case *ast.AssignStmt:
+ for _, v := range decl.Rhs {
+ value, err := GetString(v)
+ if err == nil {
+ values = append(values, value)
+ }
+ }
+ }
+
+ }
+ return values
+}
+
+// GetImportedName returns the name used for the package within the
+// code. It will resolve aliases and ignores initialization only imports.
+func GetImportedName(path string, ctx *Context) (string, bool) {
+ importName, imported := ctx.Imports.Imported[path]
+ if !imported {
+ return "", false
+ }
+
+ if _, initonly := ctx.Imports.InitOnly[path]; initonly {
+ return "", false
+ }
+
+ if alias, ok := ctx.Imports.Aliased[path]; ok {
+ importName = alias
+ }
+ return importName, true
+}
+
+// GetImportPath resolves the full import path of an identifier based on
+// the imports in the current context.
+func GetImportPath(name string, ctx *Context) (string, bool) {
+ for path := range ctx.Imports.Imported {
+ if imported, ok := GetImportedName(path, ctx); ok && imported == name {
+ return path, true
+ }
+ }
+ return "", false
+}
+
+// GetLocation returns the filename and line number of an ast.Node
+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 recursively 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
+}
+
+// PackagePaths returns a slice with all packages path at given root directory
+func PackagePaths(root string, excludes []*regexp.Regexp) ([]string, error) {
+ if strings.HasSuffix(root, "...") {
+ root = root[0 : len(root)-3]
+ } else {
+ return []string{root}, nil
+ }
+ paths := map[string]bool{}
+ err := filepath.Walk(root, func(path string, f os.FileInfo, err error) error {
+ if filepath.Ext(path) == ".go" {
+ path = filepath.Dir(path)
+ if isExcluded(path, excludes) {
+ return nil
+ }
+ paths[path] = true
+ }
+ return nil
+ })
+ if err != nil {
+ return []string{}, err
+ }
+
+ result := []string{}
+ for path := range paths {
+ result = append(result, path)
+ }
+ return result, nil
+}
+
+// isExcluded checks if a string matches any of the exclusion regexps
+func isExcluded(str string, excludes []*regexp.Regexp) bool {
+ if excludes == nil {
+ return false
+ }
+ for _, exclude := range excludes {
+ if exclude != nil && exclude.MatchString(str) {
+ return true
+ }
+ }
+ return false
+}
+
+// ExcludedDirsRegExp builds the regexps for a list of excluded dirs provided as strings
+func ExcludedDirsRegExp(excludedDirs []string) []*regexp.Regexp {
+ var exps []*regexp.Regexp
+ for _, excludedDir := range excludedDirs {
+ str := fmt.Sprintf(`([\\/])?%s([\\/])?`, excludedDir)
+ r := regexp.MustCompile(str)
+ exps = append(exps, r)
+ }
+ return exps
+}
+
+// RootPath returns the absolute root path of a scan
+func RootPath(root string) (string, error) {
+ if strings.HasSuffix(root, "...") {
+ root = root[0 : len(root)-3]
+ }
+ return filepath.Abs(root)
+}
diff --git a/vendor/github.com/securego/gosec/v2/import_tracker.go b/vendor/github.com/securego/gosec/v2/import_tracker.go
new file mode 100644
index 000000000..cbb8c5518
--- /dev/null
+++ b/vendor/github.com/securego/gosec/v2/import_tracker.go
@@ -0,0 +1,75 @@
+// 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 gosec
+
+import (
+ "go/ast"
+ "go/types"
+ "strings"
+)
+
+// ImportTracker is used to normalize the packages that have been imported
+// by a source file. It is able to differentiate between plain imports, aliased
+// imports and init only imports.
+type ImportTracker struct {
+ Imported map[string]string
+ Aliased map[string]string
+ InitOnly map[string]bool
+}
+
+// NewImportTracker creates an empty Import tracker instance
+func NewImportTracker() *ImportTracker {
+ return &ImportTracker{
+ make(map[string]string),
+ make(map[string]string),
+ make(map[string]bool),
+ }
+}
+
+// TrackFile track all the imports used by the supplied file
+func (t *ImportTracker) TrackFile(file *ast.File) {
+ for _, imp := range file.Imports {
+ path := strings.Trim(imp.Path.Value, `"`)
+ parts := strings.Split(path, "/")
+ if len(parts) > 0 {
+ name := parts[len(parts)-1]
+ t.Imported[path] = name
+ }
+ }
+}
+
+// TrackPackages tracks all the imports used by the supplied packages
+func (t *ImportTracker) TrackPackages(pkgs ...*types.Package) {
+ for _, pkg := range pkgs {
+ t.Imported[pkg.Path()] = pkg.Name()
+ }
+}
+
+// TrackImport tracks imports and handles the 'unsafe' import
+func (t *ImportTracker) TrackImport(n ast.Node) {
+ if imported, ok := n.(*ast.ImportSpec); ok {
+ path := strings.Trim(imported.Path.Value, `"`)
+ if imported.Name != nil {
+ if imported.Name.Name == "_" {
+ // Initialization only import
+ t.InitOnly[path] = true
+ } else {
+ // Aliased import
+ t.Aliased[path] = imported.Name.Name
+ }
+ }
+ if path == "unsafe" {
+ t.Imported[path] = path
+ }
+ }
+}
diff --git a/vendor/github.com/securego/gosec/v2/install.sh b/vendor/github.com/securego/gosec/v2/install.sh
new file mode 100644
index 000000000..37bed0a2e
--- /dev/null
+++ b/vendor/github.com/securego/gosec/v2/install.sh
@@ -0,0 +1,372 @@
+#!/bin/sh
+set -e
+# Code generated by godownloader on 2020-03-02T13:35:13Z. DO NOT EDIT.
+#
+
+usage() {
+ this=$1
+ cat <<EOF
+$this: download go binaries for securego/gosec
+
+Usage: $this [-b] bindir [-d] [tag]
+ -b sets bindir or installation directory, Defaults to ./bin
+ -d turns on debug logging
+ [tag] is a tag from
+ https://github.com/securego/gosec/releases
+ If tag is missing, then the latest will be used.
+
+ Generated by godownloader
+ https://github.com/goreleaser/godownloader
+
+EOF
+ exit 2
+}
+
+parse_args() {
+ #BINDIR is ./bin unless set be ENV
+ # over-ridden by flag below
+
+ BINDIR=${BINDIR:-./bin}
+ while getopts "b:dh?x" arg; do
+ case "$arg" in
+ b) BINDIR="$OPTARG" ;;
+ d) log_set_priority 10 ;;
+ h | \?) usage "$0" ;;
+ x) set -x ;;
+ esac
+ done
+ shift $((OPTIND - 1))
+ TAG=$1
+}
+# this function wraps all the destructive operations
+# if a curl|bash cuts off the end of the script due to
+# network, either nothing will happen or will syntax error
+# out preventing half-done work
+execute() {
+ tmpdir=$(mktemp -d)
+ log_debug "downloading files into ${tmpdir}"
+ http_download "${tmpdir}/${TARBALL}" "${TARBALL_URL}"
+ http_download "${tmpdir}/${CHECKSUM}" "${CHECKSUM_URL}"
+ hash_sha256_verify "${tmpdir}/${TARBALL}" "${tmpdir}/${CHECKSUM}"
+ srcdir="${tmpdir}"
+ (cd "${tmpdir}" && untar "${TARBALL}")
+ test ! -d "${BINDIR}" && install -d "${BINDIR}"
+ for binexe in $BINARIES; do
+ if [ "$OS" = "windows" ]; then
+ binexe="${binexe}.exe"
+ fi
+ install "${srcdir}/${binexe}" "${BINDIR}/"
+ log_info "installed ${BINDIR}/${binexe}"
+ done
+ rm -rf "${tmpdir}"
+}
+get_binaries() {
+ case "$PLATFORM" in
+ darwin/amd64) BINARIES="gosec" ;;
+ linux/amd64) BINARIES="gosec" ;;
+ windows/amd64) BINARIES="gosec" ;;
+ *)
+ log_crit "platform $PLATFORM is not supported. Make sure this script is up-to-date and file request at https://github.com/${PREFIX}/issues/new"
+ exit 1
+ ;;
+ esac
+}
+tag_to_version() {
+ if [ -z "${TAG}" ]; then
+ log_info "checking GitHub for latest tag"
+ else
+ log_info "checking GitHub for tag '${TAG}'"
+ fi
+ REALTAG=$(github_release "$OWNER/$REPO" "${TAG}") && true
+ if test -z "$REALTAG"; then
+ log_crit "unable to find '${TAG}' - use 'latest' or see https://github.com/${PREFIX}/releases for details"
+ exit 1
+ fi
+ # if version starts with 'v', remove it
+ TAG="$REALTAG"
+ VERSION=${TAG#v}
+}
+adjust_format() {
+ # change format (tar.gz or zip) based on OS
+ true
+}
+adjust_os() {
+ # adjust archive name based on OS
+ true
+}
+adjust_arch() {
+ # adjust archive name based on ARCH
+ true
+}
+
+cat /dev/null <<EOF
+------------------------------------------------------------------------
+https://github.com/client9/shlib - portable posix shell functions
+Public domain - http://unlicense.org
+https://github.com/client9/shlib/blob/master/LICENSE.md
+but credit (and pull requests) appreciated.
+------------------------------------------------------------------------
+EOF
+is_command() {
+ command -v "$1" >/dev/null
+}
+echoerr() {
+ echo "$@" 1>&2
+}
+log_prefix() {
+ echo "$0"
+}
+_logp=6
+log_set_priority() {
+ _logp="$1"
+}
+log_priority() {
+ if test -z "$1"; then
+ echo "$_logp"
+ return
+ fi
+ [ "$1" -le "$_logp" ]
+}
+log_tag() {
+ case $1 in
+ 0) echo "emerg" ;;
+ 1) echo "alert" ;;
+ 2) echo "crit" ;;
+ 3) echo "err" ;;
+ 4) echo "warning" ;;
+ 5) echo "notice" ;;
+ 6) echo "info" ;;
+ 7) echo "debug" ;;
+ *) echo "$1" ;;
+ esac
+}
+log_debug() {
+ log_priority 7 || return 0
+ echoerr "$(log_prefix)" "$(log_tag 7)" "$@"
+}
+log_info() {
+ log_priority 6 || return 0
+ echoerr "$(log_prefix)" "$(log_tag 6)" "$@"
+}
+log_err() {
+ log_priority 3 || return 0
+ echoerr "$(log_prefix)" "$(log_tag 3)" "$@"
+}
+log_crit() {
+ log_priority 2 || return 0
+ echoerr "$(log_prefix)" "$(log_tag 2)" "$@"
+}
+uname_os() {
+ os=$(uname -s | tr '[:upper:]' '[:lower:]')
+ case "$os" in
+ cygwin_nt*) os="windows" ;;
+ mingw*) os="windows" ;;
+ msys_nt*) os="windows" ;;
+ esac
+ echo "$os"
+}
+uname_arch() {
+ arch=$(uname -m)
+ case $arch in
+ x86_64) arch="amd64" ;;
+ x86) arch="386" ;;
+ i686) arch="386" ;;
+ i386) arch="386" ;;
+ aarch64) arch="arm64" ;;
+ armv5*) arch="armv5" ;;
+ armv6*) arch="armv6" ;;
+ armv7*) arch="armv7" ;;
+ esac
+ echo ${arch}
+}
+uname_os_check() {
+ os=$(uname_os)
+ case "$os" in
+ darwin) return 0 ;;
+ dragonfly) return 0 ;;
+ freebsd) return 0 ;;
+ linux) return 0 ;;
+ android) return 0 ;;
+ nacl) return 0 ;;
+ netbsd) return 0 ;;
+ openbsd) return 0 ;;
+ plan9) return 0 ;;
+ solaris) return 0 ;;
+ windows) return 0 ;;
+ esac
+ log_crit "uname_os_check '$(uname -s)' got converted to '$os' which is not a GOOS value. Please file bug at https://github.com/client9/shlib"
+ return 1
+}
+uname_arch_check() {
+ arch=$(uname_arch)
+ case "$arch" in
+ 386) return 0 ;;
+ amd64) return 0 ;;
+ arm64) return 0 ;;
+ armv5) return 0 ;;
+ armv6) return 0 ;;
+ armv7) return 0 ;;
+ ppc64) return 0 ;;
+ ppc64le) return 0 ;;
+ mips) return 0 ;;
+ mipsle) return 0 ;;
+ mips64) return 0 ;;
+ mips64le) return 0 ;;
+ s390x) return 0 ;;
+ amd64p32) return 0 ;;
+ esac
+ log_crit "uname_arch_check '$(uname -m)' got converted to '$arch' which is not a GOARCH value. Please file bug report at https://github.com/client9/shlib"
+ return 1
+}
+untar() {
+ tarball=$1
+ case "${tarball}" in
+ *.tar.gz | *.tgz) tar --no-same-owner -xzf "${tarball}" ;;
+ *.tar) tar --no-same-owner -xf "${tarball}" ;;
+ *.zip) unzip "${tarball}" ;;
+ *)
+ log_err "untar unknown archive format for ${tarball}"
+ return 1
+ ;;
+ esac
+}
+http_download_curl() {
+ local_file=$1
+ source_url=$2
+ header=$3
+ if [ -z "$header" ]; then
+ code=$(curl -w '%{http_code}' -sL -o "$local_file" "$source_url")
+ else
+ code=$(curl -w '%{http_code}' -sL -H "$header" -o "$local_file" "$source_url")
+ fi
+ if [ "$code" != "200" ]; then
+ log_debug "http_download_curl received HTTP status $code"
+ return 1
+ fi
+ return 0
+}
+http_download_wget() {
+ local_file=$1
+ source_url=$2
+ header=$3
+ if [ -z "$header" ]; then
+ wget -q -O "$local_file" "$source_url"
+ else
+ wget -q --header "$header" -O "$local_file" "$source_url"
+ fi
+}
+http_download() {
+ log_debug "http_download $2"
+ if is_command curl; then
+ http_download_curl "$@"
+ return
+ elif is_command wget; then
+ http_download_wget "$@"
+ return
+ fi
+ log_crit "http_download unable to find wget or curl"
+ return 1
+}
+http_copy() {
+ tmp=$(mktemp)
+ http_download "${tmp}" "$1" "$2" || return 1
+ body=$(cat "$tmp")
+ rm -f "${tmp}"
+ echo "$body"
+}
+github_release() {
+ owner_repo=$1
+ version=$2
+ test -z "$version" && version="latest"
+ giturl="https://github.com/${owner_repo}/releases/${version}"
+ json=$(http_copy "$giturl" "Accept:application/json")
+ test -z "$json" && return 1
+ version=$(echo "$json" | tr -s '\n' ' ' | sed 's/.*"tag_name":"//' | sed 's/".*//')
+ test -z "$version" && return 1
+ echo "$version"
+}
+hash_sha256() {
+ TARGET=${1:-/dev/stdin}
+ if is_command gsha256sum; then
+ hash=$(gsha256sum "$TARGET") || return 1
+ echo "$hash" | cut -d ' ' -f 1
+ elif is_command sha256sum; then
+ hash=$(sha256sum "$TARGET") || return 1
+ echo "$hash" | cut -d ' ' -f 1
+ elif is_command shasum; then
+ hash=$(shasum -a 256 "$TARGET" 2>/dev/null) || return 1
+ echo "$hash" | cut -d ' ' -f 1
+ elif is_command openssl; then
+ hash=$(openssl -dst openssl dgst -sha256 "$TARGET") || return 1
+ echo "$hash" | cut -d ' ' -f a
+ else
+ log_crit "hash_sha256 unable to find command to compute sha-256 hash"
+ return 1
+ fi
+}
+hash_sha256_verify() {
+ TARGET=$1
+ checksums=$2
+ if [ -z "$checksums" ]; then
+ log_err "hash_sha256_verify checksum file not specified in arg2"
+ return 1
+ fi
+ BASENAME=${TARGET##*/}
+ want=$(grep "${BASENAME}" "${checksums}" 2>/dev/null | tr '\t' ' ' | cut -d ' ' -f 1)
+ if [ -z "$want" ]; then
+ log_err "hash_sha256_verify unable to find checksum for '${TARGET}' in '${checksums}'"
+ return 1
+ fi
+ got=$(hash_sha256 "$TARGET")
+ if [ "$want" != "$got" ]; then
+ log_err "hash_sha256_verify checksum for '$TARGET' did not verify ${want} vs $got"
+ return 1
+ fi
+}
+cat /dev/null <<EOF
+------------------------------------------------------------------------
+End of functions from https://github.com/client9/shlib
+------------------------------------------------------------------------
+EOF
+
+PROJECT_NAME="gosec"
+OWNER=securego
+REPO="gosec"
+BINARY=gosec
+FORMAT=tar.gz
+OS=$(uname_os)
+ARCH=$(uname_arch)
+PREFIX="$OWNER/$REPO"
+
+# use in logging routines
+log_prefix() {
+ echo "$PREFIX"
+}
+PLATFORM="${OS}/${ARCH}"
+GITHUB_DOWNLOAD=https://github.com/${OWNER}/${REPO}/releases/download
+
+uname_os_check "$OS"
+uname_arch_check "$ARCH"
+
+parse_args "$@"
+
+get_binaries
+
+tag_to_version
+
+adjust_format
+
+adjust_os
+
+adjust_arch
+
+log_info "found version: ${VERSION} for ${TAG}/${OS}/${ARCH}"
+
+NAME=${PROJECT_NAME}_${VERSION}_${OS}_${ARCH}
+TARBALL=${NAME}.${FORMAT}
+TARBALL_URL=${GITHUB_DOWNLOAD}/${TAG}/${TARBALL}
+CHECKSUM=${PROJECT_NAME}_${VERSION}_checksums.txt
+CHECKSUM_URL=${GITHUB_DOWNLOAD}/${TAG}/${CHECKSUM}
+
+
+execute
diff --git a/vendor/github.com/securego/gosec/v2/issue.go b/vendor/github.com/securego/gosec/v2/issue.go
new file mode 100644
index 000000000..28ad726ba
--- /dev/null
+++ b/vendor/github.com/securego/gosec/v2/issue.go
@@ -0,0 +1,177 @@
+// (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 gosec
+
+import (
+ "encoding/json"
+ "fmt"
+ "go/ast"
+ "os"
+ "strconv"
+)
+
+// Score type used by severity and confidence values
+type Score int
+
+const (
+ // Low severity or confidence
+ Low Score = iota
+ // Medium severity or confidence
+ Medium
+ // High severity or confidence
+ High
+)
+
+// Cwe id and url
+type Cwe struct {
+ ID string
+ URL string
+}
+
+// GetCwe creates a cwe object for a given RuleID
+func GetCwe(id string) Cwe {
+ return Cwe{ID: id, URL: fmt.Sprintf("https://cwe.mitre.org/data/definitions/%s.html", id)}
+}
+
+// IssueToCWE maps gosec rules to CWEs
+var IssueToCWE = map[string]Cwe{
+ "G101": GetCwe("798"),
+ "G102": GetCwe("200"),
+ "G103": GetCwe("242"),
+ "G104": GetCwe("703"),
+ "G106": GetCwe("322"),
+ "G107": GetCwe("88"),
+ "G109": GetCwe("190"),
+ "G110": GetCwe("409"),
+ "G201": GetCwe("89"),
+ "G202": GetCwe("89"),
+ "G203": GetCwe("79"),
+ "G204": GetCwe("78"),
+ "G301": GetCwe("276"),
+ "G302": GetCwe("276"),
+ "G303": GetCwe("377"),
+ "G304": GetCwe("22"),
+ "G305": GetCwe("22"),
+ "G401": GetCwe("326"),
+ "G402": GetCwe("295"),
+ "G403": GetCwe("310"),
+ "G404": GetCwe("338"),
+ "G501": GetCwe("327"),
+ "G502": GetCwe("327"),
+ "G503": GetCwe("327"),
+ "G504": GetCwe("327"),
+ "G505": GetCwe("327"),
+}
+
+// Issue is returned 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)
+ Cwe Cwe `json:"cwe"` // Cwe associated with RuleID
+ RuleID string `json:"rule_id"` // Human readable explanation
+ What string `json:"details"` // Human readable explanation
+ File string `json:"file"` // File name we found it in
+ Code string `json:"code"` // Impacted code line
+ Line string `json:"line"` // Line number in file
+ Col string `json:"column"` // Column number in line
+}
+
+// FileLocation point out the file path and line number in file
+func (i Issue) FileLocation() string {
+ return fmt.Sprintf("%s:%s", i.File, i.Line)
+}
+
+// MetaData is embedded in all gosec rules. The Severity, Confidence and What message
+// will be passed through to reported issues.
+type MetaData struct {
+ ID string
+ Severity Score
+ Confidence Score
+ What string
+}
+
+// MarshalJSON is used convert a Score object into a JSON representation
+func (c Score) MarshalJSON() ([]byte, error) {
+ return json.Marshal(c.String())
+}
+
+// String converts a Score into a string
+func (c Score) String() string {
+ switch c {
+ case High:
+ return "HIGH"
+ case Medium:
+ return "MEDIUM"
+ case Low:
+ return "LOW"
+ }
+ return "UNDEFINED"
+}
+
+func codeSnippet(file *os.File, start int64, end int64, n ast.Node) (string, error) {
+ if n == nil {
+ return "", fmt.Errorf("Invalid AST node provided")
+ }
+
+ size := (int)(end - start) // Go bug, os.File.Read should return int64 ...
+ _, err := file.Seek(start, 0) // #nosec
+ if err != nil {
+ return "", fmt.Errorf("move to the beginning of file: %v", err)
+ }
+
+ buf := make([]byte, size)
+ if nread, err := file.Read(buf); err != nil || nread != size {
+ return "", fmt.Errorf("Unable to read code")
+ }
+ return string(buf), nil
+}
+
+// NewIssue creates a new Issue
+func NewIssue(ctx *Context, node ast.Node, ruleID, desc string, severity Score, confidence Score) *Issue {
+ var code string
+ fobj := ctx.FileSet.File(node.Pos())
+ name := fobj.Name()
+
+ start, end := fobj.Line(node.Pos()), fobj.Line(node.End())
+ line := strconv.Itoa(start)
+ if start != end {
+ line = fmt.Sprintf("%d-%d", start, end)
+ }
+
+ col := strconv.Itoa(fobj.Position(node.Pos()).Column)
+
+ // #nosec
+ if file, err := os.Open(fobj.Name()); err == nil {
+ defer file.Close()
+ s := (int64)(fobj.Position(node.Pos()).Offset) // Go bug, should be int64
+ e := (int64)(fobj.Position(node.End()).Offset) // Go bug, should be int64
+ code, err = codeSnippet(file, s, e, node)
+ if err != nil {
+ code = err.Error()
+ }
+ }
+
+ return &Issue{
+ File: name,
+ Line: line,
+ Col: col,
+ RuleID: ruleID,
+ What: desc,
+ Confidence: confidence,
+ Severity: severity,
+ Code: code,
+ Cwe: IssueToCWE[ruleID],
+ }
+}
diff --git a/vendor/github.com/securego/gosec/v2/renovate.json b/vendor/github.com/securego/gosec/v2/renovate.json
new file mode 100644
index 000000000..92327e12d
--- /dev/null
+++ b/vendor/github.com/securego/gosec/v2/renovate.json
@@ -0,0 +1,7 @@
+{
+ "extends": [
+ "config:semverAllMonthly",
+ ":enableVulnerabilityAlertsWithLabel(vulnerablity)",
+ ":docker"
+ ]
+}
diff --git a/vendor/github.com/securego/gosec/v2/resolve.go b/vendor/github.com/securego/gosec/v2/resolve.go
new file mode 100644
index 000000000..cdc287e8e
--- /dev/null
+++ b/vendor/github.com/securego/gosec/v2/resolve.go
@@ -0,0 +1,95 @@
+// (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 gosec
+
+import "go/ast"
+
+func resolveIdent(n *ast.Ident, c *Context) bool {
+ if n.Obj == nil || n.Obj.Kind != ast.Var {
+ return true
+ }
+ if node, ok := n.Obj.Decl.(ast.Node); ok {
+ return TryResolve(node, c)
+ }
+ return false
+}
+
+func resolveValueSpec(n *ast.ValueSpec, c *Context) bool {
+ if len(n.Values) == 0 {
+ return false
+ }
+ for _, value := range n.Values {
+ if !TryResolve(value, c) {
+ return false
+ }
+ }
+ return true
+}
+
+func resolveAssign(n *ast.AssignStmt, c *Context) bool {
+ if len(n.Rhs) == 0 {
+ return false
+ }
+ for _, arg := range n.Rhs {
+ if !TryResolve(arg, c) {
+ return false
+ }
+ }
+ return true
+}
+
+func resolveCompLit(n *ast.CompositeLit, c *Context) bool {
+ if len(n.Elts) == 0 {
+ return false
+ }
+ for _, arg := range n.Elts {
+ if !TryResolve(arg, c) {
+ return false
+ }
+ }
+ return true
+}
+
+func resolveBinExpr(n *ast.BinaryExpr, c *Context) bool {
+ return (TryResolve(n.X, c) && TryResolve(n.Y, c))
+}
+
+func resolveCallExpr(n *ast.CallExpr, c *Context) bool {
+ // TODO(tkelsey): next step, full function resolution
+ return false
+}
+
+// TryResolve will attempt, given a subtree starting at some AST node, to resolve
+// all values contained within to a known constant. It is used to check for any
+// unknown values in compound expressions.
+func TryResolve(n ast.Node, c *Context) bool {
+ switch node := n.(type) {
+ case *ast.BasicLit:
+ return true
+ case *ast.CompositeLit:
+ return resolveCompLit(node, c)
+ case *ast.Ident:
+ return resolveIdent(node, c)
+ case *ast.ValueSpec:
+ return resolveValueSpec(node, c)
+ case *ast.AssignStmt:
+ return resolveAssign(node, c)
+ case *ast.CallExpr:
+ return resolveCallExpr(node, c)
+ case *ast.BinaryExpr:
+ return resolveBinExpr(node, c)
+ }
+ return false
+}
diff --git a/vendor/github.com/securego/gosec/v2/rule.go b/vendor/github.com/securego/gosec/v2/rule.go
new file mode 100644
index 000000000..fbba089bb
--- /dev/null
+++ b/vendor/github.com/securego/gosec/v2/rule.go
@@ -0,0 +1,59 @@
+// 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 gosec
+
+import (
+ "go/ast"
+ "reflect"
+)
+
+// The Rule interface used by all rules supported by gosec.
+type Rule interface {
+ ID() string
+ Match(ast.Node, *Context) (*Issue, error)
+}
+
+// RuleBuilder is used to register a rule definition with the analyzer
+type RuleBuilder func(id string, c Config) (Rule, []ast.Node)
+
+// A RuleSet maps lists of rules to the type of AST node they should be run on.
+// The analyzer will only invoke rules contained in the list associated with the
+// type of AST node it is currently visiting.
+type RuleSet map[reflect.Type][]Rule
+
+// NewRuleSet constructs a new RuleSet
+func NewRuleSet() RuleSet {
+ return make(RuleSet)
+}
+
+// Register adds a trigger for the supplied rule for the the
+// specified ast nodes.
+func (r RuleSet) Register(rule Rule, nodes ...ast.Node) {
+ for _, n := range nodes {
+ t := reflect.TypeOf(n)
+ if rules, ok := r[t]; ok {
+ r[t] = append(rules, rule)
+ } else {
+ r[t] = []Rule{rule}
+ }
+ }
+}
+
+// RegisteredFor will return all rules that are registered for a
+// specified ast node.
+func (r RuleSet) RegisteredFor(n ast.Node) []Rule {
+ if rules, found := r[reflect.TypeOf(n)]; found {
+ return rules
+ }
+ return []Rule{}
+}
diff --git a/vendor/github.com/securego/gosec/v2/rules/archive.go b/vendor/github.com/securego/gosec/v2/rules/archive.go
new file mode 100644
index 000000000..ca7a46e0b
--- /dev/null
+++ b/vendor/github.com/securego/gosec/v2/rules/archive.go
@@ -0,0 +1,60 @@
+package rules
+
+import (
+ "go/ast"
+ "go/types"
+
+ "github.com/securego/gosec/v2"
+)
+
+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.ContainsPkgCallExpr(n, c, false); 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/securego/gosec/v2/rules/bad_defer.go b/vendor/github.com/securego/gosec/v2/rules/bad_defer.go
new file mode 100644
index 000000000..3c358806f
--- /dev/null
+++ b/vendor/github.com/securego/gosec/v2/rules/bad_defer.go
@@ -0,0 +1,69 @@
+package rules
+
+import (
+ "fmt"
+ "go/ast"
+ "strings"
+
+ "github.com/securego/gosec/v2"
+)
+
+type deferType struct {
+ typ string
+ methods []string
+}
+
+type badDefer struct {
+ gosec.MetaData
+ types []deferType
+}
+
+func (r *badDefer) ID() string {
+ return r.MetaData.ID
+}
+
+func normalize(typ string) string {
+ return strings.TrimPrefix(typ, "*")
+}
+
+func contains(methods []string, method string) bool {
+ for _, m := range methods {
+ if m == method {
+ return true
+ }
+ }
+ return false
+}
+
+func (r *badDefer) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
+ if deferStmt, ok := n.(*ast.DeferStmt); ok {
+ for _, deferTyp := range r.types {
+ if typ, method, err := gosec.GetCallInfo(deferStmt.Call, c); err == nil {
+ if normalize(typ) == deferTyp.typ && contains(deferTyp.methods, method) {
+ return gosec.NewIssue(c, n, r.ID(), fmt.Sprintf(r.What, typ, method), r.Severity, r.Confidence), nil
+ }
+ }
+ }
+
+ }
+
+ return nil, nil
+}
+
+// NewDeferredClosing detects unsafe defer of error returning methods
+func NewDeferredClosing(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
+ return &badDefer{
+ types: []deferType{
+ {
+ typ: "os.File",
+ methods: []string{"Close"},
+ },
+ },
+ MetaData: gosec.MetaData{
+ ID: id,
+ Severity: gosec.Medium,
+ Confidence: gosec.High,
+ What: "Deferring unsafe method %q on type %q",
+ },
+ }, []ast.Node{(*ast.DeferStmt)(nil)}
+}
diff --git a/vendor/github.com/securego/gosec/v2/rules/bind.go b/vendor/github.com/securego/gosec/v2/rules/bind.go
new file mode 100644
index 000000000..8f6af067a
--- /dev/null
+++ b/vendor/github.com/securego/gosec/v2/rules/bind.go
@@ -0,0 +1,83 @@
+// (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"
+ "regexp"
+
+ "github.com/securego/gosec/v2"
+)
+
+// Looks for net.Listen("0.0.0.0") or net.Listen(":8080")
+type bindsToAllNetworkInterfaces struct {
+ gosec.MetaData
+ calls gosec.CallList
+ pattern *regexp.Regexp
+}
+
+func (r *bindsToAllNetworkInterfaces) ID() string {
+ return r.MetaData.ID
+}
+
+func (r *bindsToAllNetworkInterfaces) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
+ callExpr := r.calls.ContainsPkgCallExpr(n, c, false)
+ if callExpr == nil {
+ return nil, nil
+ }
+ if len(callExpr.Args) > 1 {
+ arg := callExpr.Args[1]
+ if bl, ok := arg.(*ast.BasicLit); ok {
+ if arg, err := gosec.GetString(bl); err == nil {
+ if r.pattern.MatchString(arg) {
+ return gosec.NewIssue(c, n, r.ID(), r.What, r.Severity, r.Confidence), nil
+ }
+ }
+ } else if ident, ok := arg.(*ast.Ident); ok {
+ values := gosec.GetIdentStringValues(ident)
+ for _, value := range values {
+ if r.pattern.MatchString(value) {
+ return gosec.NewIssue(c, n, r.ID(), r.What, r.Severity, r.Confidence), nil
+ }
+ }
+ }
+ } else if len(callExpr.Args) > 0 {
+ values := gosec.GetCallStringArgsValues(callExpr.Args[0], c)
+ for _, value := range values {
+ if r.pattern.MatchString(value) {
+ return gosec.NewIssue(c, n, r.ID(), r.What, r.Severity, r.Confidence), nil
+ }
+ }
+ }
+ return nil, nil
+}
+
+// NewBindsToAllNetworkInterfaces detects socket connections that are setup to
+// listen on all network interfaces.
+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: gosec.MetaData{
+ ID: id,
+ Severity: gosec.Medium,
+ Confidence: gosec.High,
+ What: "Binds to all network interfaces",
+ },
+ }, []ast.Node{(*ast.CallExpr)(nil)}
+}
diff --git a/vendor/github.com/securego/gosec/v2/rules/blacklist.go b/vendor/github.com/securego/gosec/v2/rules/blacklist.go
new file mode 100644
index 000000000..9bb73381f
--- /dev/null
+++ b/vendor/github.com/securego/gosec/v2/rules/blacklist.go
@@ -0,0 +1,94 @@
+// (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"
+ "strings"
+
+ "github.com/securego/gosec/v2"
+)
+
+type blacklistedImport struct {
+ gosec.MetaData
+ Blacklisted map[string]string
+}
+
+func unquote(original string) string {
+ copy := strings.TrimSpace(original)
+ copy = strings.TrimLeft(copy, `"`)
+ return strings.TrimRight(copy, `"`)
+}
+
+func (r *blacklistedImport) ID() string {
+ return r.MetaData.ID
+}
+
+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 gosec.NewIssue(c, node, r.ID(), description, r.Severity, r.Confidence), nil
+ }
+ }
+ return nil, nil
+}
+
+// NewBlacklistedImports reports when a blacklisted import is being used.
+// Typically when a deprecated technology is being used.
+func NewBlacklistedImports(id string, conf gosec.Config, blacklist map[string]string) (gosec.Rule, []ast.Node) {
+ return &blacklistedImport{
+ MetaData: gosec.MetaData{
+ ID: id,
+ Severity: gosec.Medium,
+ Confidence: gosec.High,
+ },
+ Blacklisted: blacklist,
+ }, []ast.Node{(*ast.ImportSpec)(nil)}
+}
+
+// NewBlacklistedImportMD5 fails if MD5 is imported
+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 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 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 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/securego/gosec/v2/rules/decompression-bomb.go b/vendor/github.com/securego/gosec/v2/rules/decompression-bomb.go
new file mode 100644
index 000000000..bfc589763
--- /dev/null
+++ b/vendor/github.com/securego/gosec/v2/rules/decompression-bomb.go
@@ -0,0 +1,109 @@
+// (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 (
+ "fmt"
+ "go/ast"
+
+ "github.com/securego/gosec/v2"
+)
+
+type decompressionBombCheck struct {
+ gosec.MetaData
+ readerCalls gosec.CallList
+ copyCalls gosec.CallList
+}
+
+func (d *decompressionBombCheck) ID() string {
+ return d.MetaData.ID
+}
+
+func containsReaderCall(node ast.Node, ctx *gosec.Context, list gosec.CallList) bool {
+ if list.ContainsPkgCallExpr(node, ctx, false) != nil {
+ return true
+ }
+ // Resolve type info of ident (for *archive/zip.File.Open)
+ s, idt, _ := gosec.GetCallInfo(node, ctx)
+ return list.Contains(s, idt)
+}
+
+func (d *decompressionBombCheck) Match(node ast.Node, ctx *gosec.Context) (*gosec.Issue, error) {
+ var readerVarObj map[*ast.Object]struct{}
+
+ // To check multiple lines, ctx.PassedValues is used to store temporary data.
+ if _, ok := ctx.PassedValues[d.ID()]; !ok {
+ readerVarObj = make(map[*ast.Object]struct{})
+ ctx.PassedValues[d.ID()] = readerVarObj
+ } else if pv, ok := ctx.PassedValues[d.ID()].(map[*ast.Object]struct{}); ok {
+ readerVarObj = pv
+ } else {
+ return nil, fmt.Errorf("PassedValues[%s] of Context is not map[*ast.Object]struct{}, but %T", d.ID(), ctx.PassedValues[d.ID()])
+ }
+
+ // io.Copy is a common function.
+ // To reduce false positives, This rule detects code which is used for compressed data only.
+ switch n := node.(type) {
+ case *ast.AssignStmt:
+ for _, expr := range n.Rhs {
+ if callExpr, ok := expr.(*ast.CallExpr); ok && containsReaderCall(callExpr, ctx, d.readerCalls) {
+ if idt, ok := n.Lhs[0].(*ast.Ident); ok && idt.Name != "_" {
+ // Example:
+ // r, _ := zlib.NewReader(buf)
+ // Add r's Obj to readerVarObj map
+ readerVarObj[idt.Obj] = struct{}{}
+ }
+ }
+ }
+ case *ast.CallExpr:
+ if d.copyCalls.ContainsPkgCallExpr(n, ctx, false) != nil {
+ if idt, ok := n.Args[1].(*ast.Ident); ok {
+ if _, ok := readerVarObj[idt.Obj]; ok {
+ // Detect io.Copy(x, r)
+ return gosec.NewIssue(ctx, n, d.ID(), d.What, d.Severity, d.Confidence), nil
+ }
+ }
+ }
+ }
+
+ return nil, nil
+}
+
+// NewDecompressionBombCheck detects if there is potential DoS vulnerability via decompression bomb
+func NewDecompressionBombCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
+ readerCalls := gosec.NewCallList()
+ readerCalls.Add("compress/gzip", "NewReader")
+ readerCalls.AddAll("compress/zlib", "NewReader", "NewReaderDict")
+ readerCalls.Add("compress/bzip2", "NewReader")
+ readerCalls.AddAll("compress/flate", "NewReader", "NewReaderDict")
+ readerCalls.Add("compress/lzw", "NewReader")
+ readerCalls.Add("archive/tar", "NewReader")
+ readerCalls.Add("archive/zip", "NewReader")
+ readerCalls.Add("*archive/zip.File", "Open")
+
+ copyCalls := gosec.NewCallList()
+ copyCalls.Add("io", "Copy")
+
+ return &decompressionBombCheck{
+ MetaData: gosec.MetaData{
+ ID: id,
+ Severity: gosec.Medium,
+ Confidence: gosec.Medium,
+ What: "Potential DoS vulnerability via decompression bomb",
+ },
+ readerCalls: readerCalls,
+ copyCalls: copyCalls,
+ }, []ast.Node{(*ast.FuncDecl)(nil), (*ast.AssignStmt)(nil), (*ast.CallExpr)(nil)}
+}
diff --git a/vendor/github.com/securego/gosec/v2/rules/errors.go b/vendor/github.com/securego/gosec/v2/rules/errors.go
new file mode 100644
index 000000000..f16f91d04
--- /dev/null
+++ b/vendor/github.com/securego/gosec/v2/rules/errors.go
@@ -0,0 +1,119 @@
+// (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/securego/gosec/v2"
+)
+
+type noErrorCheck struct {
+ gosec.MetaData
+ whitelist gosec.CallList
+}
+
+func (r *noErrorCheck) ID() string {
+ return r.MetaData.ID
+}
+
+func returnsError(callExpr *ast.CallExpr, ctx *gosec.Context) int {
+ if tv := ctx.Info.TypeOf(callExpr); tv != nil {
+ switch t := tv.(type) {
+ case *types.Tuple:
+ for pos := 0; pos < t.Len(); pos++ {
+ variable := t.At(pos)
+ if variable != nil && variable.Type().String() == "error" {
+ return pos
+ }
+ }
+ case *types.Named:
+ if t.String() == "error" {
+ return 0
+ }
+ }
+ }
+ return -1
+}
+
+func (r *noErrorCheck) Match(n ast.Node, ctx *gosec.Context) (*gosec.Issue, error) {
+ switch stmt := n.(type) {
+ case *ast.AssignStmt:
+ cfg := ctx.Config
+ if enabled, err := cfg.IsGlobalEnabled(gosec.Audit); err == nil && enabled {
+ for _, expr := range stmt.Rhs {
+ if callExpr, ok := expr.(*ast.CallExpr); ok && r.whitelist.ContainsCallExpr(expr, ctx) == nil {
+ pos := returnsError(callExpr, ctx)
+ if pos < 0 || pos >= len(stmt.Lhs) {
+ return nil, nil
+ }
+ if id, ok := stmt.Lhs[pos].(*ast.Ident); ok && id.Name == "_" {
+ return gosec.NewIssue(ctx, n, r.ID(), r.What, r.Severity, r.Confidence), nil
+ }
+ }
+ }
+ }
+ case *ast.ExprStmt:
+ if callExpr, ok := stmt.X.(*ast.CallExpr); ok && r.whitelist.ContainsCallExpr(stmt.X, ctx) == nil {
+ pos := returnsError(callExpr, ctx)
+ if pos >= 0 {
+ return gosec.NewIssue(ctx, n, r.ID(), r.What, r.Severity, r.Confidence), nil
+ }
+ }
+ }
+ return nil, nil
+}
+
+// NewNoErrorCheck detects if the returned error is unchecked
+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 := gosec.NewCallList()
+ whitelist.AddAll("bytes.Buffer", "Write", "WriteByte", "WriteRune", "WriteString")
+ whitelist.AddAll("fmt", "Print", "Printf", "Println", "Fprint", "Fprintf", "Fprintln")
+ whitelist.AddAll("strings.Builder", "Write", "WriteByte", "WriteRune", "WriteString")
+ whitelist.Add("io.PipeWriter", "CloseWithError")
+
+ if configured, ok := conf["G104"]; ok {
+ if whitelisted, ok := configured.(map[string]interface{}); ok {
+ for pkg, funcs := range whitelisted {
+ if funcs, ok := funcs.([]interface{}); ok {
+ whitelist.AddAll(pkg, toStringSlice(funcs)...)
+ }
+ }
+ }
+ }
+
+ return &noErrorCheck{
+ MetaData: gosec.MetaData{
+ ID: id,
+ Severity: gosec.Low,
+ Confidence: gosec.High,
+ What: "Errors unhandled.",
+ },
+ whitelist: whitelist,
+ }, []ast.Node{(*ast.AssignStmt)(nil), (*ast.ExprStmt)(nil)}
+}
+
+func toStringSlice(values []interface{}) []string {
+ result := []string{}
+ for _, value := range values {
+ if value, ok := value.(string); ok {
+ result = append(result, value)
+ }
+ }
+ return result
+}
diff --git a/vendor/github.com/securego/gosec/v2/rules/fileperms.go b/vendor/github.com/securego/gosec/v2/rules/fileperms.go
new file mode 100644
index 000000000..ffe7b97d5
--- /dev/null
+++ b/vendor/github.com/securego/gosec/v2/rules/fileperms.go
@@ -0,0 +1,111 @@
+// (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 (
+ "fmt"
+ "go/ast"
+ "strconv"
+
+ "github.com/securego/gosec/v2"
+)
+
+type filePermissions struct {
+ gosec.MetaData
+ mode int64
+ pkg string
+ calls []string
+}
+
+func (r *filePermissions) ID() string {
+ return r.MetaData.ID
+}
+
+func getConfiguredMode(conf map[string]interface{}, configKey string, defaultMode int64) int64 {
+ var mode = defaultMode
+ if value, ok := conf[configKey]; ok {
+ switch value := value.(type) {
+ case int64:
+ mode = value
+ case string:
+ if m, e := strconv.ParseInt(value, 0, 64); e != nil {
+ mode = defaultMode
+ } else {
+ mode = m
+ }
+ }
+ }
+ return mode
+}
+
+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 := 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
+}
+
+// NewWritePerms creates a rule to detect file Writes with bad permissions.
+func NewWritePerms(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
+ mode := getConfiguredMode(conf, "G306", 0600)
+ return &filePermissions{
+ mode: mode,
+ pkg: "io/ioutil",
+ calls: []string{"WriteFile"},
+ MetaData: gosec.MetaData{
+ ID: id,
+ Severity: gosec.Medium,
+ Confidence: gosec.High,
+ What: fmt.Sprintf("Expect WriteFile permissions to be %#o or less", mode),
+ },
+ }, []ast.Node{(*ast.CallExpr)(nil)}
+}
+
+// NewFilePerms creates a rule to detect file creation with a more permissive than configured
+// permission mask.
+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: gosec.MetaData{
+ ID: id,
+ Severity: gosec.Medium,
+ Confidence: gosec.High,
+ What: fmt.Sprintf("Expect file permissions to be %#o or less", mode),
+ },
+ }, []ast.Node{(*ast.CallExpr)(nil)}
+}
+
+// NewMkdirPerms creates a rule to detect directory creation with more permissive than
+// configured permission mask.
+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: gosec.MetaData{
+ ID: id,
+ 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/securego/gosec/v2/rules/hardcoded_credentials.go b/vendor/github.com/securego/gosec/v2/rules/hardcoded_credentials.go
new file mode 100644
index 000000000..6b360c5b9
--- /dev/null
+++ b/vendor/github.com/securego/gosec/v2/rules/hardcoded_credentials.go
@@ -0,0 +1,173 @@
+// (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/token"
+ "regexp"
+ "strconv"
+
+ zxcvbn "github.com/nbutton23/zxcvbn-go"
+ "github.com/securego/gosec/v2"
+)
+
+type credentials struct {
+ gosec.MetaData
+ pattern *regexp.Regexp
+ entropyThreshold float64
+ perCharThreshold float64
+ truncate int
+ ignoreEntropy bool
+}
+
+func (r *credentials) ID() string {
+ return r.MetaData.ID
+}
+
+func truncate(s string, n int) string {
+ if n > len(s) {
+ return s
+ }
+ return s[:n]
+}
+
+func (r *credentials) isHighEntropyString(str string) bool {
+ s := truncate(str, r.truncate)
+ info := zxcvbn.PasswordStrength(s, []string{})
+ entropyPerChar := info.Entropy / float64(len(s))
+ return (info.Entropy >= r.entropyThreshold ||
+ (info.Entropy >= (r.entropyThreshold/2) &&
+ entropyPerChar >= r.perCharThreshold))
+}
+
+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)
+ case *ast.ValueSpec:
+ return r.matchValueSpec(node, ctx)
+ case *ast.BinaryExpr:
+ return r.matchEqualityCheck(node, ctx)
+ }
+ return nil, nil
+}
+
+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 := gosec.GetString(e); err == nil {
+ if r.ignoreEntropy || (!r.ignoreEntropy && r.isHighEntropyString(val)) {
+ return gosec.NewIssue(ctx, assign, r.ID(), r.What, r.Severity, r.Confidence), nil
+ }
+ }
+ }
+ }
+ }
+ }
+ return nil, nil
+}
+
+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 := gosec.GetString(valueSpec.Values[index]); err == nil {
+ if r.ignoreEntropy || (!r.ignoreEntropy && r.isHighEntropyString(val)) {
+ return gosec.NewIssue(ctx, valueSpec, r.ID(), r.What, r.Severity, r.Confidence), nil
+ }
+ }
+ }
+ }
+ return nil, nil
+}
+
+func (r *credentials) matchEqualityCheck(binaryExpr *ast.BinaryExpr, ctx *gosec.Context) (*gosec.Issue, error) {
+ if binaryExpr.Op == token.EQL || binaryExpr.Op == token.NEQ {
+ if ident, ok := binaryExpr.X.(*ast.Ident); ok {
+ if r.pattern.MatchString(ident.Name) {
+ if val, err := gosec.GetString(binaryExpr.Y); err == nil {
+ if r.ignoreEntropy || (!r.ignoreEntropy && r.isHighEntropyString(val)) {
+ return gosec.NewIssue(ctx, binaryExpr, r.ID(), r.What, r.Severity, r.Confidence), nil
+ }
+ }
+ }
+ }
+ }
+ return nil, nil
+}
+
+// NewHardcodedCredentials attempts to find high entropy string constants being
+// assigned to variables that appear to be related to credentials.
+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
+ ignoreEntropy := false
+ var truncateString = 16
+ if val, ok := conf["G101"]; ok {
+ conf := val.(map[string]interface{})
+ if configPattern, ok := conf["pattern"]; ok {
+ if cfgPattern, ok := configPattern.(string); ok {
+ pattern = cfgPattern
+ }
+ }
+ if configIgnoreEntropy, ok := conf["ignore_entropy"]; ok {
+ if cfgIgnoreEntropy, ok := configIgnoreEntropy.(bool); ok {
+ ignoreEntropy = cfgIgnoreEntropy
+ }
+ }
+ if configEntropyThreshold, ok := conf["entropy_threshold"]; ok {
+ if cfgEntropyThreshold, ok := configEntropyThreshold.(string); ok {
+ if parsedNum, err := strconv.ParseFloat(cfgEntropyThreshold, 64); err == nil {
+ entropyThreshold = parsedNum
+ }
+ }
+ }
+ if configCharThreshold, ok := conf["per_char_threshold"]; ok {
+ if cfgCharThreshold, ok := configCharThreshold.(string); ok {
+ if parsedNum, err := strconv.ParseFloat(cfgCharThreshold, 64); err == nil {
+ perCharThreshold = parsedNum
+ }
+ }
+ }
+ if configTruncate, ok := conf["truncate"]; ok {
+ if cfgTruncate, ok := configTruncate.(string); ok {
+ if parsedInt, err := strconv.Atoi(cfgTruncate); err == nil {
+ truncateString = parsedInt
+ }
+ }
+ }
+ }
+
+ return &credentials{
+ pattern: regexp.MustCompile(pattern),
+ entropyThreshold: entropyThreshold,
+ perCharThreshold: perCharThreshold,
+ ignoreEntropy: ignoreEntropy,
+ truncate: truncateString,
+ MetaData: gosec.MetaData{
+ ID: id,
+ What: "Potential hardcoded credentials",
+ Confidence: gosec.Low,
+ Severity: gosec.High,
+ },
+ }, []ast.Node{(*ast.AssignStmt)(nil), (*ast.ValueSpec)(nil), (*ast.BinaryExpr)(nil)}
+}
diff --git a/vendor/github.com/securego/gosec/v2/rules/implicit_aliasing.go b/vendor/github.com/securego/gosec/v2/rules/implicit_aliasing.go
new file mode 100644
index 000000000..65c7ae36d
--- /dev/null
+++ b/vendor/github.com/securego/gosec/v2/rules/implicit_aliasing.go
@@ -0,0 +1,116 @@
+package rules
+
+import (
+ "fmt"
+ "github.com/securego/gosec/v2"
+ "go/ast"
+ "go/token"
+)
+
+type implicitAliasing struct {
+ gosec.MetaData
+ aliases map[*ast.Object]struct{}
+ rightBrace token.Pos
+ acceptableAlias []*ast.UnaryExpr
+}
+
+func (r *implicitAliasing) ID() string {
+ return r.MetaData.ID
+}
+
+func containsUnary(exprs []*ast.UnaryExpr, expr *ast.UnaryExpr) bool {
+ for _, e := range exprs {
+ if e == expr {
+ return true
+ }
+ }
+ return false
+}
+
+func (r *implicitAliasing) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
+ switch node := n.(type) {
+ case *ast.RangeStmt:
+ // When presented with a range statement, get the underlying Object bound to
+ // by assignment and add it to our set (r.aliases) of objects to check for.
+ if key, ok := node.Value.(*ast.Ident); ok {
+ if assignment, ok := key.Obj.Decl.(*ast.AssignStmt); ok {
+ if len(assignment.Lhs) < 2 {
+ return nil, nil
+ }
+
+ if object, ok := assignment.Lhs[1].(*ast.Ident); ok {
+ r.aliases[object.Obj] = struct{}{}
+
+ if r.rightBrace < node.Body.Rbrace {
+ r.rightBrace = node.Body.Rbrace
+ }
+ }
+ }
+ }
+ case *ast.UnaryExpr:
+ // If this unary expression is outside of the last range statement we were looking at
+ // then clear the list of objects we're concerned about because they're no longer in
+ // scope
+ if node.Pos() > r.rightBrace {
+ r.aliases = make(map[*ast.Object]struct{})
+ r.acceptableAlias = make([]*ast.UnaryExpr, 0)
+ }
+
+ // Short circuit logic to skip checking aliases if we have nothing to check against.
+ if len(r.aliases) == 0 {
+ return nil, nil
+ }
+
+ // If this unary is at the top level of a return statement then it is okay--
+ // see *ast.ReturnStmt comment below.
+ if containsUnary(r.acceptableAlias, node) {
+ return nil, nil
+ }
+
+ // If we find a unary op of & (reference) of an object within r.aliases, complain.
+ if ident, ok := node.X.(*ast.Ident); ok && node.Op.String() == "&" {
+ if _, contains := r.aliases[ident.Obj]; contains {
+ return gosec.NewIssue(c, n, r.ID(), r.What, r.Severity, r.Confidence), nil
+ }
+ }
+ case *ast.ReturnStmt:
+ // Returning a rangeStmt yielded value is acceptable since only one value will be returned
+ for _, item := range node.Results {
+ if unary, ok := item.(*ast.UnaryExpr); ok && unary.Op.String() == "&" {
+ r.acceptableAlias = append(r.acceptableAlias, unary)
+ }
+ }
+ }
+
+ return nil, nil
+}
+
+// NewImplicitAliasing detects implicit memory aliasing of type: for blah := SomeCall() {... SomeOtherCall(&blah) ...}
+func NewImplicitAliasing(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
+ return &implicitAliasing{
+ aliases: make(map[*ast.Object]struct{}),
+ rightBrace: token.NoPos,
+ acceptableAlias: make([]*ast.UnaryExpr, 0),
+ MetaData: gosec.MetaData{
+ ID: id,
+ Severity: gosec.Medium,
+ Confidence: gosec.Medium,
+ What: fmt.Sprintf("Implicit memory aliasing in for loop."),
+ },
+ }, []ast.Node{(*ast.RangeStmt)(nil), (*ast.UnaryExpr)(nil), (*ast.ReturnStmt)(nil)}
+}
+
+/*
+This rule is prone to flag false positives.
+
+Within GoSec, the rule is just an AST match-- there are a handful of other
+implementation strategies which might lend more nuance to the rule at the
+cost of allowing false negatives.
+
+From a tooling side, I'd rather have this rule flag false positives than
+potentially have some false negatives-- especially if the sentiment of this
+rule (as I understand it, and Go) is that referencing a rangeStmt-yielded
+value is kinda strange and does not have a strongly justified use case.
+
+Which is to say-- a false positive _should_ just be changed.
+*/
diff --git a/vendor/github.com/securego/gosec/v2/rules/integer_overflow.go b/vendor/github.com/securego/gosec/v2/rules/integer_overflow.go
new file mode 100644
index 000000000..dfcda94a8
--- /dev/null
+++ b/vendor/github.com/securego/gosec/v2/rules/integer_overflow.go
@@ -0,0 +1,89 @@
+// (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 (
+ "fmt"
+ "go/ast"
+
+ "github.com/securego/gosec/v2"
+)
+
+type integerOverflowCheck struct {
+ gosec.MetaData
+ calls gosec.CallList
+}
+
+func (i *integerOverflowCheck) ID() string {
+ return i.MetaData.ID
+}
+
+func (i *integerOverflowCheck) Match(node ast.Node, ctx *gosec.Context) (*gosec.Issue, error) {
+ var atoiVarObj map[*ast.Object]ast.Node
+
+ // To check multiple lines, ctx.PassedValues is used to store temporary data.
+ if _, ok := ctx.PassedValues[i.ID()]; !ok {
+ atoiVarObj = make(map[*ast.Object]ast.Node)
+ ctx.PassedValues[i.ID()] = atoiVarObj
+ } else if pv, ok := ctx.PassedValues[i.ID()].(map[*ast.Object]ast.Node); ok {
+ atoiVarObj = pv
+ } else {
+ return nil, fmt.Errorf("PassedValues[%s] of Context is not map[*ast.Object]ast.Node, but %T", i.ID(), ctx.PassedValues[i.ID()])
+ }
+
+ // strconv.Atoi is a common function.
+ // To reduce false positives, This rule detects code which is converted to int32/int16 only.
+ switch n := node.(type) {
+ case *ast.AssignStmt:
+ for _, expr := range n.Rhs {
+ if callExpr, ok := expr.(*ast.CallExpr); ok && i.calls.ContainsPkgCallExpr(callExpr, ctx, false) != nil {
+ if idt, ok := n.Lhs[0].(*ast.Ident); ok && idt.Name != "_" {
+ // Example:
+ // v, _ := strconv.Atoi("1111")
+ // Add v's Obj to atoiVarObj map
+ atoiVarObj[idt.Obj] = n
+ }
+ }
+ }
+ case *ast.CallExpr:
+ if fun, ok := n.Fun.(*ast.Ident); ok {
+ if fun.Name == "int32" || fun.Name == "int16" {
+ if idt, ok := n.Args[0].(*ast.Ident); ok {
+ if n, ok := atoiVarObj[idt.Obj]; ok {
+ // Detect int32(v) and int16(v)
+ return gosec.NewIssue(ctx, n, i.ID(), i.What, i.Severity, i.Confidence), nil
+ }
+ }
+ }
+ }
+ }
+
+ return nil, nil
+}
+
+// NewIntegerOverflowCheck detects if there is potential Integer OverFlow
+func NewIntegerOverflowCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
+ calls := gosec.NewCallList()
+ calls.Add("strconv", "Atoi")
+ return &integerOverflowCheck{
+ MetaData: gosec.MetaData{
+ ID: id,
+ Severity: gosec.High,
+ Confidence: gosec.Medium,
+ What: "Potential Integer overflow made by strconv.Atoi result conversion to int16/32",
+ },
+ calls: calls,
+ }, []ast.Node{(*ast.FuncDecl)(nil), (*ast.AssignStmt)(nil), (*ast.CallExpr)(nil)}
+}
diff --git a/vendor/github.com/securego/gosec/v2/rules/pprof.go b/vendor/github.com/securego/gosec/v2/rules/pprof.go
new file mode 100644
index 000000000..4c99af752
--- /dev/null
+++ b/vendor/github.com/securego/gosec/v2/rules/pprof.go
@@ -0,0 +1,42 @@
+package rules
+
+import (
+ "go/ast"
+
+ "github.com/securego/gosec/v2"
+)
+
+type pprofCheck struct {
+ gosec.MetaData
+ importPath string
+ importName string
+}
+
+// ID returns the ID of the check
+func (p *pprofCheck) ID() string {
+ return p.MetaData.ID
+}
+
+// Match checks for pprof imports
+func (p *pprofCheck) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
+ if node, ok := n.(*ast.ImportSpec); ok {
+ if p.importPath == unquote(node.Path.Value) && node.Name != nil && p.importName == node.Name.Name {
+ return gosec.NewIssue(c, node, p.ID(), p.What, p.Severity, p.Confidence), nil
+ }
+ }
+ return nil, nil
+}
+
+// NewPprofCheck detects when the profiling endpoint is automatically exposed
+func NewPprofCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
+ return &pprofCheck{
+ MetaData: gosec.MetaData{
+ ID: id,
+ Severity: gosec.High,
+ Confidence: gosec.High,
+ What: "Profiling endpoint is automatically exposed on /debug/pprof",
+ },
+ importPath: "net/http/pprof",
+ importName: "_",
+ }, []ast.Node{(*ast.ImportSpec)(nil)}
+}
diff --git a/vendor/github.com/securego/gosec/v2/rules/rand.go b/vendor/github.com/securego/gosec/v2/rules/rand.go
new file mode 100644
index 000000000..08c28fcad
--- /dev/null
+++ b/vendor/github.com/securego/gosec/v2/rules/rand.go
@@ -0,0 +1,55 @@
+// (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"
+
+ "github.com/securego/gosec/v2"
+)
+
+type weakRand struct {
+ gosec.MetaData
+ funcNames []string
+ packagePath string
+}
+
+func (w *weakRand) ID() string {
+ return w.MetaData.ID
+}
+
+func (w *weakRand) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
+ for _, funcName := range w.funcNames {
+ if _, matched := gosec.MatchCallByPackage(n, c, w.packagePath, funcName); matched {
+ return gosec.NewIssue(c, n, w.ID(), w.What, w.Severity, w.Confidence), nil
+ }
+ }
+
+ return nil, nil
+}
+
+// NewWeakRandCheck detects the use of random number generator that isn't cryptographically secure
+func NewWeakRandCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
+ return &weakRand{
+ funcNames: []string{"Read", "Int"},
+ packagePath: "math/rand",
+ MetaData: gosec.MetaData{
+ ID: id,
+ 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/securego/gosec/v2/rules/readfile.go b/vendor/github.com/securego/gosec/v2/rules/readfile.go
new file mode 100644
index 000000000..a52f7425f
--- /dev/null
+++ b/vendor/github.com/securego/gosec/v2/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/securego/gosec/v2"
+)
+
+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.ContainsPkgCallExpr(n, c, false); 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 identities 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.ContainsPkgCallExpr(n, c, false); 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 identities 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/securego/gosec/v2/rules/rsa.go b/vendor/github.com/securego/gosec/v2/rules/rsa.go
new file mode 100644
index 000000000..f2ed5db53
--- /dev/null
+++ b/vendor/github.com/securego/gosec/v2/rules/rsa.go
@@ -0,0 +1,58 @@
+// (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 (
+ "fmt"
+ "go/ast"
+
+ "github.com/securego/gosec/v2"
+)
+
+type weakKeyStrength struct {
+ gosec.MetaData
+ calls gosec.CallList
+ bits int
+}
+
+func (w *weakKeyStrength) ID() string {
+ return w.MetaData.ID
+}
+
+func (w *weakKeyStrength) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
+ if callExpr := w.calls.ContainsPkgCallExpr(n, c, false); callExpr != 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 gosec.Config) (gosec.Rule, []ast.Node) {
+ calls := gosec.NewCallList()
+ calls.Add("crypto/rsa", "GenerateKey")
+ bits := 2048
+ return &weakKeyStrength{
+ calls: calls,
+ bits: bits,
+ MetaData: gosec.MetaData{
+ ID: id,
+ 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/securego/gosec/v2/rules/rulelist.go b/vendor/github.com/securego/gosec/v2/rules/rulelist.go
new file mode 100644
index 000000000..06e1dfb97
--- /dev/null
+++ b/vendor/github.com/securego/gosec/v2/rules/rulelist.go
@@ -0,0 +1,116 @@
+// (c) Copyright 2016 Hewlett Packard Enterprise Development LP
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package rules
+
+import "github.com/securego/gosec/v2"
+
+// RuleDefinition contains the description of a rule and a mechanism to
+// create it.
+type RuleDefinition struct {
+ ID string
+ Description string
+ 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]gosec.RuleBuilder {
+ builders := make(map[string]gosec.RuleBuilder)
+ for _, def := range rl {
+ builders[def.ID] = def.Create
+ }
+ return builders
+}
+
+// RuleFilter can be used to include or exclude a rule depending on the return
+// value of the function
+type RuleFilter func(string) bool
+
+// NewRuleFilter is a closure that will include/exclude the rule ID's based on
+// the supplied boolean value.
+func NewRuleFilter(action bool, ruleIDs ...string) RuleFilter {
+ rulelist := make(map[string]bool)
+ for _, rule := range ruleIDs {
+ rulelist[rule] = true
+ }
+ return func(rule string) bool {
+ if _, found := rulelist[rule]; found {
+ return action
+ }
+ return !action
+ }
+}
+
+// Generate the list of rules to use
+func Generate(filters ...RuleFilter) RuleList {
+ rules := []RuleDefinition{
+ // misc
+ {"G101", "Look for hardcoded credentials", NewHardcodedCredentials},
+ {"G102", "Bind to all interfaces", NewBindsToAllNetworkInterfaces},
+ {"G103", "Audit the use of unsafe block", NewUsingUnsafe},
+ {"G104", "Audit errors not checked", NewNoErrorCheck},
+ {"G106", "Audit the use of ssh.InsecureIgnoreHostKey function", NewSSHHostKey},
+ {"G107", "Url provided to HTTP request as taint input", NewSSRFCheck},
+ {"G108", "Profiling endpoint is automatically exposed", NewPprofCheck},
+ {"G109", "Converting strconv.Atoi result to int32/int16", NewIntegerOverflowCheck},
+ {"G110", "Detect io.Copy instead of io.CopyN when decompression", NewDecompressionBombCheck},
+
+ // injection
+ {"G201", "SQL query construction using format string", NewSQLStrFormat},
+ {"G202", "SQL query construction using string concatenation", NewSQLStrConcat},
+ {"G203", "Use of unescaped data in HTML templates", NewTemplateCheck},
+ {"G204", "Audit use of command execution", NewSubproc},
+
+ // filesystem
+ {"G301", "Poor file permissions used when creating a directory", NewMkdirPerms},
+ {"G302", "Poor file permissions 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},
+ {"G306", "Poor file permissions used when writing to a file", NewWritePerms},
+ {"G307", "Unsafe defer call of a method returning an error", NewDeferredClosing},
+
+ // crypto
+ {"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},
+
+ // blacklist
+ {"G501", "Import blacklist: crypto/md5", NewBlacklistedImportMD5},
+ {"G502", "Import blacklist: crypto/des", NewBlacklistedImportDES},
+ {"G503", "Import blacklist: crypto/rc4", NewBlacklistedImportRC4},
+ {"G504", "Import blacklist: net/http/cgi", NewBlacklistedImportCGI},
+ {"G505", "Import blacklist: crypto/sha1", NewBlacklistedImportSHA1},
+
+ // memory safety
+ {"G601", "Implicit memory aliasing in RangeStmt", NewImplicitAliasing},
+ }
+
+ ruleMap := make(map[string]RuleDefinition)
+
+RULES:
+ for _, rule := range rules {
+ for _, filter := range filters {
+ if filter(rule.ID) {
+ continue RULES
+ }
+ }
+ ruleMap[rule.ID] = rule
+ }
+ return ruleMap
+}
diff --git a/vendor/github.com/securego/gosec/v2/rules/sql.go b/vendor/github.com/securego/gosec/v2/rules/sql.go
new file mode 100644
index 000000000..3279a3400
--- /dev/null
+++ b/vendor/github.com/securego/gosec/v2/rules/sql.go
@@ -0,0 +1,219 @@
+// (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"
+ "regexp"
+
+ "github.com/securego/gosec/v2"
+)
+
+type sqlStatement struct {
+ gosec.MetaData
+
+ // Contains a list of patterns which must all match for the rule to match.
+ patterns []*regexp.Regexp
+}
+
+func (s *sqlStatement) ID() string {
+ return s.MetaData.ID
+}
+
+// See if the string matches the patterns for the statement.
+func (s *sqlStatement) MatchPatterns(str string) bool {
+ for _, pattern := range s.patterns {
+ if !pattern.MatchString(str) {
+ return false
+ }
+ }
+ return true
+}
+
+type sqlStrConcat struct {
+ sqlStatement
+}
+
+func (s *sqlStrConcat) ID() string {
+ return s.MetaData.ID
+}
+
+// see if we can figure out what it is
+func (s *sqlStrConcat) checkObject(n *ast.Ident, c *gosec.Context) bool {
+ if n.Obj != nil {
+ return n.Obj.Kind != ast.Var && n.Obj.Kind != ast.Fun
+ }
+
+ // Try to resolve unresolved identifiers using other files in same package
+ for _, file := range c.PkgFiles {
+ if node, ok := file.Scope.Objects[n.String()]; ok {
+ return node.Kind != ast.Var && node.Kind != ast.Fun
+ }
+ }
+ return false
+}
+
+// Look for "SELECT * FROM table WHERE " + " ' OR 1=1"
+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 := gosec.GetString(start); e == nil {
+ if !s.MatchPatterns(str) {
+ return nil, nil
+ }
+ if _, ok := node.Y.(*ast.BasicLit); ok {
+ return nil, nil // string cat OK
+ }
+ if second, ok := node.Y.(*ast.Ident); ok && s.checkObject(second, c) {
+ return nil, nil
+ }
+ return gosec.NewIssue(c, n, s.ID(), s.What, s.Severity, s.Confidence), nil
+ }
+ }
+ }
+ return nil, nil
+}
+
+// NewSQLStrConcat looks for cases where we are building SQL strings via concatenation
+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: gosec.MetaData{
+ ID: id,
+ Severity: gosec.Medium,
+ Confidence: gosec.High,
+ What: "SQL string concatenation",
+ },
+ },
+ }, []ast.Node{(*ast.BinaryExpr)(nil)}
+}
+
+type sqlStrFormat struct {
+ sqlStatement
+ calls gosec.CallList
+ noIssue gosec.CallList
+ noIssueQuoted gosec.CallList
+}
+
+// see if we can figure out what it is
+func (s *sqlStrFormat) constObject(e ast.Expr, c *gosec.Context) bool {
+ n, ok := e.(*ast.Ident)
+ if !ok {
+ return false
+ }
+
+ if n.Obj != nil {
+ return n.Obj.Kind == ast.Con
+ }
+
+ // Try to resolve unresolved identifiers using other files in same package
+ for _, file := range c.PkgFiles {
+ if node, ok := file.Scope.Objects[n.String()]; ok {
+ return node.Kind == ast.Con
+ }
+ }
+ return false
+}
+
+// Looks for "fmt.Sprintf("SELECT * FROM foo where '%s', userInput)"
+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.ContainsPkgCallExpr(n, c, false); node != 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
+ }
+ }
+
+ // no formatter
+ if len(node.Args) == 0 {
+ return nil, nil
+ }
+
+ var formatter string
+
+ // 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 {
+ formatter = fullStr
+ }
+ } else if arg, e := gosec.GetString(node.Args[argIndex]); e == nil {
+ formatter = arg
+ }
+ if len(formatter) <= 0 {
+ return nil, nil
+ }
+
+ // If all formatter args are quoted or constant, then the SQL construction is safe
+ if argIndex+1 < len(node.Args) {
+ allSafe := true
+ for _, arg := range node.Args[argIndex+1:] {
+ if n := s.noIssueQuoted.ContainsPkgCallExpr(arg, c, true); n == nil && !s.constObject(arg, c) {
+ allSafe = false
+ break
+ }
+ }
+ if allSafe {
+ return nil, nil
+ }
+ }
+ if s.MatchPatterns(formatter) {
+ 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 gosec.Config) (gosec.Rule, []ast.Node) {
+ rule := &sqlStrFormat{
+ calls: gosec.NewCallList(),
+ noIssue: gosec.NewCallList(),
+ noIssueQuoted: gosec.NewCallList(),
+ sqlStatement: sqlStatement{
+ patterns: []*regexp.Regexp{
+ regexp.MustCompile("(?)(SELECT|DELETE|INSERT|UPDATE|INTO|FROM|WHERE) "),
+ regexp.MustCompile("%[^bdoxXfFp]"),
+ },
+ MetaData: gosec.MetaData{
+ ID: id,
+ Severity: gosec.Medium,
+ Confidence: gosec.High,
+ What: "SQL string formatting",
+ },
+ },
+ }
+ rule.calls.AddAll("fmt", "Sprint", "Sprintf", "Sprintln", "Fprintf")
+ rule.noIssue.AddAll("os", "Stdout", "Stderr")
+ rule.noIssueQuoted.Add("github.com/lib/pq", "QuoteIdentifier")
+ return rule, []ast.Node{(*ast.CallExpr)(nil)}
+}
diff --git a/vendor/github.com/securego/gosec/v2/rules/ssh.go b/vendor/github.com/securego/gosec/v2/rules/ssh.go
new file mode 100644
index 000000000..01f37da51
--- /dev/null
+++ b/vendor/github.com/securego/gosec/v2/rules/ssh.go
@@ -0,0 +1,38 @@
+package rules
+
+import (
+ "go/ast"
+
+ "github.com/securego/gosec/v2"
+)
+
+type sshHostKey struct {
+ gosec.MetaData
+ pkg string
+ calls []string
+}
+
+func (r *sshHostKey) ID() string {
+ return r.MetaData.ID
+}
+
+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 gosec.Config) (gosec.Rule, []ast.Node) {
+ return &sshHostKey{
+ pkg: "golang.org/x/crypto/ssh",
+ calls: []string{"InsecureIgnoreHostKey"},
+ MetaData: gosec.MetaData{
+ ID: id,
+ What: "Use of ssh InsecureIgnoreHostKey should be audited",
+ Severity: gosec.Medium,
+ Confidence: gosec.High,
+ },
+ }, []ast.Node{(*ast.CallExpr)(nil)}
+}
diff --git a/vendor/github.com/securego/gosec/v2/rules/ssrf.go b/vendor/github.com/securego/gosec/v2/rules/ssrf.go
new file mode 100644
index 000000000..86bb8278d
--- /dev/null
+++ b/vendor/github.com/securego/gosec/v2/rules/ssrf.go
@@ -0,0 +1,66 @@
+package rules
+
+import (
+ "go/ast"
+ "go/types"
+
+ "github.com/securego/gosec/v2"
+)
+
+type ssrf struct {
+ gosec.MetaData
+ gosec.CallList
+}
+
+// ID returns the identifier for this rule
+func (r *ssrf) ID() string {
+ return r.MetaData.ID
+}
+
+// ResolveVar tries to resolve the first argument of a call expression
+// The first argument is the url
+func (r *ssrf) ResolveVar(n *ast.CallExpr, c *gosec.Context) bool {
+ if len(n.Args) > 0 {
+ arg := n.Args[0]
+ if ident, ok := arg.(*ast.Ident); ok {
+ obj := c.Info.ObjectOf(ident)
+ if _, ok := obj.(*types.Var); ok {
+ scope := c.Pkg.Scope()
+ if scope != nil && scope.Lookup(ident.Name) != nil {
+ // a URL defined in a variable at package scope can be changed at any time
+ return true
+ }
+ if !gosec.TryResolve(ident, c) {
+ return true
+ }
+ }
+ }
+ }
+ return false
+}
+
+// Match inspects AST nodes to determine if certain net/http methods are called with variable input
+func (r *ssrf) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
+ // Call expression is using http package directly
+ if node := r.ContainsPkgCallExpr(n, c, false); node != nil {
+ if r.ResolveVar(node, c) {
+ return gosec.NewIssue(c, n, r.ID(), r.What, r.Severity, r.Confidence), nil
+ }
+ }
+ return nil, nil
+}
+
+// NewSSRFCheck detects cases where HTTP requests are sent
+func NewSSRFCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
+ rule := &ssrf{
+ CallList: gosec.NewCallList(),
+ MetaData: gosec.MetaData{
+ ID: id,
+ What: "Potential HTTP request made with variable url",
+ Severity: gosec.Medium,
+ Confidence: gosec.Medium,
+ },
+ }
+ rule.AddAll("net/http", "Do", "Get", "Head", "Post", "PostForm", "RoundTrip")
+ return rule, []ast.Node{(*ast.CallExpr)(nil)}
+}
diff --git a/vendor/github.com/securego/gosec/v2/rules/subproc.go b/vendor/github.com/securego/gosec/v2/rules/subproc.go
new file mode 100644
index 000000000..30c32cc03
--- /dev/null
+++ b/vendor/github.com/securego/gosec/v2/rules/subproc.go
@@ -0,0 +1,85 @@
+// (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/securego/gosec/v2"
+)
+
+type subprocess struct {
+ gosec.MetaData
+ gosec.CallList
+}
+
+func (r *subprocess) ID() string {
+ return r.MetaData.ID
+}
+
+// TODO(gm) The only real potential for command injection with a Go project
+// is something like this:
+//
+// syscall.Exec("/bin/sh", []string{"-c", tainted})
+//
+// E.g. Input is correctly escaped but the execution context being used
+// is unsafe. For example:
+//
+// syscall.Exec("echo", "foobar" + tainted)
+func (r *subprocess) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
+ if node := r.ContainsPkgCallExpr(n, c, false); node != nil {
+ args := node.Args
+ if r.isContext(n, c) {
+ args = args[1:]
+ }
+ for _, arg := range args {
+ 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(), "Subprocess launched with variable", gosec.Medium, gosec.High), nil
+ }
+ } else if !gosec.TryResolve(arg, c) {
+ // the arg is not a constant or a variable but instead a function call or os.Args[i]
+ return gosec.NewIssue(c, n, r.ID(), "Subprocess launched with function call as argument or cmd arguments", gosec.Medium, gosec.High), nil
+ }
+ }
+ }
+ return nil, nil
+}
+
+// isContext checks whether or not the node is a CommandContext call or not
+// Thi is requried in order to skip the first argument from the check.
+func (r *subprocess) isContext(n ast.Node, ctx *gosec.Context) bool {
+ selector, indent, err := gosec.GetCallInfo(n, ctx)
+ if err != nil {
+ return false
+ }
+ if selector == "exec" && indent == "CommandContext" {
+ return true
+ }
+ return false
+}
+
+// NewSubproc detects cases where we are forking out to an external process
+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")
+ rule.Add("syscall", "ForkExec")
+ rule.Add("syscall", "StartProcess")
+ return rule, []ast.Node{(*ast.CallExpr)(nil)}
+}
diff --git a/vendor/github.com/securego/gosec/v2/rules/tempfiles.go b/vendor/github.com/securego/gosec/v2/rules/tempfiles.go
new file mode 100644
index 000000000..36f0f979b
--- /dev/null
+++ b/vendor/github.com/securego/gosec/v2/rules/tempfiles.go
@@ -0,0 +1,58 @@
+// (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"
+ "regexp"
+
+ "github.com/securego/gosec/v2"
+)
+
+type badTempFile struct {
+ gosec.MetaData
+ calls gosec.CallList
+ args *regexp.Regexp
+}
+
+func (t *badTempFile) ID() string {
+ return t.MetaData.ID
+}
+
+func (t *badTempFile) Match(n ast.Node, c *gosec.Context) (gi *gosec.Issue, err error) {
+ if node := t.calls.ContainsPkgCallExpr(n, c, false); node != 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 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: gosec.MetaData{
+ ID: id,
+ 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/securego/gosec/v2/rules/templates.go b/vendor/github.com/securego/gosec/v2/rules/templates.go
new file mode 100644
index 000000000..819240905
--- /dev/null
+++ b/vendor/github.com/securego/gosec/v2/rules/templates.go
@@ -0,0 +1,61 @@
+// (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"
+
+ "github.com/securego/gosec/v2"
+)
+
+type templateCheck struct {
+ gosec.MetaData
+ calls gosec.CallList
+}
+
+func (t *templateCheck) ID() string {
+ return t.MetaData.ID
+}
+
+func (t *templateCheck) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
+ if node := t.calls.ContainsPkgCallExpr(n, c, false); node != nil {
+ for _, arg := range node.Args {
+ if _, ok := arg.(*ast.BasicLit); !ok { // basic lits are safe
+ return gosec.NewIssue(c, n, t.ID(), t.What, t.Severity, t.Confidence), nil
+ }
+ }
+ }
+ return nil, nil
+}
+
+// NewTemplateCheck constructs the template check rule. This rule is used to
+// find use of templates where HTML/JS escaping is not being used
+func NewTemplateCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
+
+ 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: gosec.MetaData{
+ ID: id,
+ 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/securego/gosec/v2/rules/tls.go b/vendor/github.com/securego/gosec/v2/rules/tls.go
new file mode 100644
index 000000000..fab9ee164
--- /dev/null
+++ b/vendor/github.com/securego/gosec/v2/rules/tls.go
@@ -0,0 +1,130 @@
+// (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.
+
+//go:generate tlsconfig
+
+package rules
+
+import (
+ "fmt"
+ "go/ast"
+
+ "github.com/securego/gosec/v2"
+)
+
+type insecureConfigTLS struct {
+ gosec.MetaData
+ MinVersion int16
+ MaxVersion int16
+ requiredType string
+ goodCiphers []string
+}
+
+func (t *insecureConfigTLS) ID() string {
+ return t.MetaData.ID
+}
+
+func stringInSlice(a string, list []string) bool {
+ for _, b := range list {
+ if b == a {
+ return true
+ }
+ }
+ return false
+}
+
+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 gosec.NewIssue(c, ident, t.ID(), err, gosec.High, gosec.High)
+ }
+ }
+ }
+ }
+ return nil
+}
+
+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 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 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 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 gosec.NewIssue(c, n, t.ID(), "TLS PreferServerCipherSuites may be false.", gosec.Medium, gosec.Low)
+ }
+
+ case "MinVersion":
+ if ival, ierr := gosec.GetInt(n.Value); ierr == nil {
+ if (int16)(ival) < t.MinVersion {
+ 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 gosec.NewIssue(c, n, t.ID(), "TLS MinVersion may be too low.", gosec.High, gosec.Low)
+ }
+
+ case "MaxVersion":
+ if ival, ierr := gosec.GetInt(n.Value); ierr == nil {
+ if (int16)(ival) < t.MaxVersion {
+ 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 gosec.NewIssue(c, n, t.ID(), "TLS MaxVersion may be too low.", gosec.High, gosec.Low)
+ }
+
+ case "CipherSuites":
+ if ret := t.processTLSCipherSuites(n.Value, c); ret != nil {
+ return ret
+ }
+
+ }
+
+ }
+ return nil
+}
+
+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 {
+ for _, elt := range complit.Elts {
+ if kve, ok := elt.(*ast.KeyValueExpr); ok {
+ issue := t.processTLSConfVal(kve, c)
+ if issue != nil {
+ return issue, nil
+ }
+ }
+ }
+ }
+ }
+ return nil, nil
+}
diff --git a/vendor/github.com/securego/gosec/v2/rules/tls_config.go b/vendor/github.com/securego/gosec/v2/rules/tls_config.go
new file mode 100644
index 000000000..ff4f3fe2e
--- /dev/null
+++ b/vendor/github.com/securego/gosec/v2/rules/tls_config.go
@@ -0,0 +1,88 @@
+package rules
+
+import (
+ "go/ast"
+
+ "github.com/securego/gosec/v2"
+)
+
+// NewModernTLSCheck creates a check for Modern TLS ciphers
+// DO NOT EDIT - generated by tlsconfig tool
+func NewModernTLSCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
+ return &insecureConfigTLS{
+ MetaData: gosec.MetaData{ID: id},
+ requiredType: "crypto/tls.Config",
+ MinVersion: 0x0304,
+ MaxVersion: 0x0304,
+ goodCiphers: []string{
+ "TLS_AES_128_GCM_SHA256",
+ "TLS_AES_256_GCM_SHA384",
+ "TLS_CHACHA20_POLY1305_SHA256",
+ },
+ }, []ast.Node{(*ast.CompositeLit)(nil)}
+}
+
+// NewIntermediateTLSCheck creates a check for Intermediate TLS ciphers
+// DO NOT EDIT - generated by tlsconfig tool
+func NewIntermediateTLSCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
+ return &insecureConfigTLS{
+ MetaData: gosec.MetaData{ID: id},
+ requiredType: "crypto/tls.Config",
+ MinVersion: 0x0303,
+ MaxVersion: 0x0304,
+ goodCiphers: []string{
+ "TLS_AES_128_GCM_SHA256",
+ "TLS_AES_256_GCM_SHA384",
+ "TLS_CHACHA20_POLY1305_SHA256",
+ "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
+ "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
+ "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
+ "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
+ "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305",
+ "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305",
+ "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256",
+ "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384",
+ },
+ }, []ast.Node{(*ast.CompositeLit)(nil)}
+}
+
+// NewOldTLSCheck creates a check for Old TLS ciphers
+// DO NOT EDIT - generated by tlsconfig tool
+func NewOldTLSCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
+ return &insecureConfigTLS{
+ MetaData: gosec.MetaData{ID: id},
+ requiredType: "crypto/tls.Config",
+ MinVersion: 0x0301,
+ MaxVersion: 0x0304,
+ goodCiphers: []string{
+ "TLS_AES_128_GCM_SHA256",
+ "TLS_AES_256_GCM_SHA384",
+ "TLS_CHACHA20_POLY1305_SHA256",
+ "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
+ "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
+ "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
+ "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
+ "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305",
+ "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305",
+ "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256",
+ "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384",
+ "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
+ "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
+ "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
+ "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
+ "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384",
+ "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384",
+ "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
+ "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
+ "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256",
+ "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256",
+ "TLS_RSA_WITH_AES_128_GCM_SHA256",
+ "TLS_RSA_WITH_AES_256_GCM_SHA384",
+ "TLS_RSA_WITH_AES_128_CBC_SHA256",
+ "TLS_RSA_WITH_AES_256_CBC_SHA256",
+ "TLS_RSA_WITH_AES_128_CBC_SHA",
+ "TLS_RSA_WITH_AES_256_CBC_SHA",
+ "TLS_RSA_WITH_3DES_EDE_CBC_SHA",
+ },
+ }, []ast.Node{(*ast.CompositeLit)(nil)}
+}
diff --git a/vendor/github.com/securego/gosec/v2/rules/unsafe.go b/vendor/github.com/securego/gosec/v2/rules/unsafe.go
new file mode 100644
index 000000000..88a298fb5
--- /dev/null
+++ b/vendor/github.com/securego/gosec/v2/rules/unsafe.go
@@ -0,0 +1,53 @@
+// (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"
+
+ "github.com/securego/gosec/v2"
+)
+
+type usingUnsafe struct {
+ gosec.MetaData
+ pkg string
+ calls []string
+}
+
+func (r *usingUnsafe) ID() string {
+ return r.MetaData.ID
+}
+
+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 gosec.Config) (gosec.Rule, []ast.Node) {
+ return &usingUnsafe{
+ pkg: "unsafe",
+ calls: []string{"Alignof", "Offsetof", "Sizeof", "Pointer"},
+ MetaData: gosec.MetaData{
+ ID: id,
+ What: "Use of unsafe calls should be audited",
+ Severity: gosec.Low,
+ Confidence: gosec.High,
+ },
+ }, []ast.Node{(*ast.CallExpr)(nil)}
+}
diff --git a/vendor/github.com/securego/gosec/v2/rules/weakcrypto.go b/vendor/github.com/securego/gosec/v2/rules/weakcrypto.go
new file mode 100644
index 000000000..0e45393db
--- /dev/null
+++ b/vendor/github.com/securego/gosec/v2/rules/weakcrypto.go
@@ -0,0 +1,58 @@
+// (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"
+
+ "github.com/securego/gosec/v2"
+)
+
+type usesWeakCryptography struct {
+ gosec.MetaData
+ blacklist map[string][]string
+}
+
+func (r *usesWeakCryptography) ID() string {
+ return r.MetaData.ID
+}
+
+func (r *usesWeakCryptography) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
+ for pkg, funcs := range r.blacklist {
+ 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 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: gosec.MetaData{
+ ID: id,
+ Severity: gosec.Medium,
+ Confidence: gosec.High,
+ What: "Use of weak cryptographic primitive",
+ },
+ }
+ return rule, []ast.Node{(*ast.CallExpr)(nil)}
+}