mirror of
https://github.com/securego/gosec.git
synced 2026-01-15 01:33:41 +08:00
Compare commits
51 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e57efa8482 | ||
|
|
ff17c30a97 | ||
|
|
3eba7b8a3e | ||
|
|
55c6ceaaa6 | ||
|
|
40fa36d1de | ||
|
|
873ac243ea | ||
|
|
f1f0056a90 | ||
|
|
0680c75f99 | ||
|
|
79c8b79263 | ||
|
|
69213955da | ||
|
|
5a3a27afae | ||
|
|
17105ab93e | ||
|
|
1297bedbc7 | ||
|
|
7fd4aef9dc | ||
|
|
991dd94f3a | ||
|
|
1933cba5b5 | ||
|
|
e73248cc12 | ||
|
|
c59cd6bb95 | ||
|
|
bfb0f422fe | ||
|
|
cb89567f99 | ||
|
|
1b2eecc8c4 | ||
|
|
efbefc6930 | ||
|
|
1978a52ff4 | ||
|
|
fd5472caaf | ||
|
|
d3309fb4f5 | ||
|
|
b695b66e4d | ||
|
|
aee782bfe8 | ||
|
|
f285d612b5 | ||
|
|
ba23b5e49a | ||
|
|
5a131be2ec | ||
|
|
9f30bb6602 | ||
|
|
83355dc837 | ||
|
|
2d4133d7a1 | ||
|
|
91447a45f5 | ||
|
|
c0c122cdc7 | ||
|
|
62db81342e | ||
|
|
521e69ef66 | ||
|
|
d4dc2d2df5 | ||
|
|
8b90c95c07 | ||
|
|
5b3d23117c | ||
|
|
9535c9e3e1 | ||
|
|
b869720342 | ||
|
|
0ee8ad3d5b | ||
|
|
2a4064d45d | ||
|
|
a484c77736 | ||
|
|
514f65f3c3 | ||
|
|
e936c84a90 | ||
|
|
8c43b96d54 | ||
|
|
5032f998a0 | ||
|
|
03e876754d | ||
|
|
01b12b43d4 |
7
.github/workflows/ci.yml
vendored
7
.github/workflows/ci.yml
vendored
@@ -21,9 +21,8 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
go_version:
|
||||
- '1.14'
|
||||
- '1.15'
|
||||
- '1.16'
|
||||
- '1.17'
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
GO111MODULE: on
|
||||
@@ -51,7 +50,7 @@ jobs:
|
||||
- name: Setup go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: '1.16'
|
||||
go-version: '1.17'
|
||||
- name: Checkout Source
|
||||
uses: actions/checkout@v2
|
||||
- uses: actions/cache@v2
|
||||
@@ -63,7 +62,7 @@ jobs:
|
||||
- name: Create Test Coverage
|
||||
run: make test-coverage
|
||||
- name: Upload Test Coverage
|
||||
uses: codecov/codecov-action@v1
|
||||
uses: codecov/codecov-action@v2
|
||||
with:
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
fail_ci_if_error: true
|
||||
|
||||
9
.github/workflows/release.yml
vendored
9
.github/workflows/release.yml
vendored
@@ -17,10 +17,15 @@ jobs:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.16.x
|
||||
go-version: 1.17
|
||||
- name : Get release version
|
||||
id: get_version
|
||||
run: echo ::set-env name=RELEASE_VERSION::$(echo ${GITHUB_REF:10})
|
||||
- name: Generate SBOM
|
||||
uses: CycloneDX/gh-gomod-generate-sbom@v1
|
||||
with:
|
||||
version: v1
|
||||
args: mod -licenses -json -output bom.json
|
||||
- name: Release Binaries
|
||||
uses: goreleaser/goreleaser-action@v2
|
||||
with:
|
||||
@@ -34,6 +39,6 @@ jobs:
|
||||
name: securego/gosec
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
buildargs: GO_VERSION=1.16
|
||||
buildargs: GO_VERSION=1.17
|
||||
tags: "latest,${{ env.RELEASE_VERSION }}"
|
||||
tag_names: true
|
||||
|
||||
26
.github/workflows/scan.yml
vendored
Normal file
26
.github/workflows/scan.yml
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
name: "Security Scan"
|
||||
|
||||
# Run workflow each time code is pushed to your repository and on a schedule.
|
||||
# The scheduled workflow runs every at 00:00 on Sunday UTC time.
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
schedule:
|
||||
- cron: '0 0 * * 0'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v2
|
||||
- name: Security Scan
|
||||
uses: securego/gosec@master
|
||||
with:
|
||||
# we let the report trigger content trigger a failure using the GitHub Security features.
|
||||
args: '-no-fail -fmt sarif -out results.sarif ./...'
|
||||
- name: Upload SARIF file
|
||||
uses: github/codeql-action/upload-sarif@v1
|
||||
with:
|
||||
# Path to SARIF file relative to the root of the repository
|
||||
sarif_file: results.sarif
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -33,3 +33,7 @@ _testmain.go
|
||||
.DS_Store
|
||||
|
||||
.vscode
|
||||
.idea
|
||||
|
||||
# SBOMs generated during CI
|
||||
/bom.json
|
||||
|
||||
@@ -2,22 +2,32 @@ linters:
|
||||
enable:
|
||||
- asciicheck
|
||||
- bodyclose
|
||||
- deadcode
|
||||
- depguard
|
||||
- dogsled
|
||||
- durationcheck
|
||||
- errcheck
|
||||
- errorlint
|
||||
- exportloopref
|
||||
- gci
|
||||
- gofmt
|
||||
- gofumpt
|
||||
- goimports
|
||||
- gosec
|
||||
- gosimple
|
||||
- govet
|
||||
- importas
|
||||
- ineffassign
|
||||
- megacheck
|
||||
- misspell
|
||||
- nakedret
|
||||
- nolintlint
|
||||
- revive
|
||||
- staticcheck
|
||||
- structcheck
|
||||
- typecheck
|
||||
- unconvert
|
||||
- unparam
|
||||
- wastedassign
|
||||
- unused
|
||||
- varcheck
|
||||
- wastedassign
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
project_name: gosec
|
||||
|
||||
release:
|
||||
extra_files:
|
||||
- glob: ./bom.json
|
||||
github:
|
||||
owner: securego
|
||||
name: gosec
|
||||
|
||||
@@ -8,7 +8,7 @@ RUN go mod download
|
||||
RUN make build-linux
|
||||
|
||||
FROM golang:${GO_VERSION}-alpine
|
||||
RUN apk add --update --no-cache ca-certificates bash git gcc libc-dev
|
||||
RUN apk add --update --no-cache ca-certificates bash git gcc libc-dev openssh
|
||||
ENV GO111MODULE on
|
||||
COPY --from=builder /build/gosec /bin/gosec
|
||||
COPY entrypoint.sh /bin/entrypoint.sh
|
||||
|
||||
5
Makefile
5
Makefile
@@ -2,7 +2,8 @@ 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'
|
||||
BUILD_DATE ?= $(shell date +%Y-%m-%d)
|
||||
BUILDFLAGS := "-w -s -X 'main.Version=$(GIT_TAG)' -X 'main.GitTag=$(GIT_TAG)' -X 'main.BuildDate=$(BUILD_DATE)'"
|
||||
CGO_ENABLED = 0
|
||||
GO := GO111MODULE=on go
|
||||
GO_NOMOD :=GO111MODULE=off go
|
||||
@@ -55,7 +56,7 @@ release:
|
||||
goreleaser release
|
||||
|
||||
build-linux:
|
||||
CGO_ENABLED=$(CGO_ENABLED) GOOS=linux GOARCH=amd64 go build -ldflags $(BUILDFLAGS) -o $(BIN) ./cmd/gosec/
|
||||
CGO_ENABLED=$(CGO_ENABLED) GOOS=linux GOARCH=amd64 go build -ldflags=$(BUILDFLAGS) -o $(BIN) ./cmd/gosec/
|
||||
|
||||
image:
|
||||
@echo "Building the Docker image..."
|
||||
|
||||
28
README.md
28
README.md
@@ -113,6 +113,14 @@ jobs:
|
||||
|
||||
### Local Installation
|
||||
|
||||
#### Go 1.16+
|
||||
|
||||
```bash
|
||||
go install github.com/securego/gosec/v2/cmd/gosec@latest
|
||||
```
|
||||
|
||||
#### Go version < 1.16
|
||||
|
||||
```bash
|
||||
go get -u github.com/securego/gosec/v2/cmd/gosec
|
||||
```
|
||||
@@ -205,7 +213,7 @@ of functions which will be skipped when auditing the not checked errors:
|
||||
```JSON
|
||||
{
|
||||
"G104": {
|
||||
"io/ioutil": ["WriteFile"]
|
||||
"ioutil": ["WriteFile"]
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -236,7 +244,6 @@ gosec will ignore test files across all packages and any dependencies in your ve
|
||||
The scanning of test files can be enabled with the following flag:
|
||||
|
||||
```bash
|
||||
|
||||
gosec -tests ./...
|
||||
```
|
||||
|
||||
@@ -246,6 +253,19 @@ Also additional folders can be excluded as follows:
|
||||
gosec -exclude-dir=rules -exclude-dir=cmd ./...
|
||||
```
|
||||
|
||||
### Excluding generated files
|
||||
|
||||
gosec can ignore generated go files with default generated code comment.
|
||||
|
||||
```
|
||||
// Code generated by some generator DO NOT EDIT.
|
||||
```
|
||||
|
||||
```bash
|
||||
gosec -exclude-generated ./...
|
||||
```
|
||||
|
||||
|
||||
### 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,
|
||||
@@ -288,7 +308,7 @@ gosec is able to pass your [Go build tags](https://golang.org/pkg/go/build/) to
|
||||
They can be provided as a comma separated list as follows:
|
||||
|
||||
```bash
|
||||
gosec -tag debug,ignore ./...
|
||||
gosec -tags debug,ignore ./...
|
||||
```
|
||||
|
||||
### Output formats
|
||||
@@ -338,7 +358,7 @@ Then generate the types with :
|
||||
schema-generate -i sarif-schema-2.1.0.json -o mypath/types.go
|
||||
```
|
||||
|
||||
Most of the MarshallJSON/UnmarshalJSON are removed except the one for PropertyBag which is handy to inline the additionnal properties. The rest can be removed.
|
||||
Most of the MarshallJSON/UnmarshalJSON are removed except the one for PropertyBag which is handy to inline the additional properties. The rest can be removed.
|
||||
The URI,ID, UUID, GUID were renamed so it fits the Golang convention defined [here](https://github.com/golang/lint/blob/master/lint.go#L700)
|
||||
|
||||
### Tests
|
||||
|
||||
1
USERS.md
1
USERS.md
@@ -14,6 +14,7 @@ This is a list of gosec's users. Please send a pull request with your organisati
|
||||
8. [1Password](https://github.com/1Password/srp)
|
||||
9. [PingCAP/tidb](https://github.com/pingcap/tidb)
|
||||
10. [Checkmarx](https://www.checkmarx.com/)
|
||||
11. [SeatGeek](https://www.seatgeek.com/)
|
||||
|
||||
## Projects
|
||||
|
||||
|
||||
96
analyzer.go
96
analyzer.go
@@ -43,6 +43,8 @@ const LoadMode = packages.NeedName |
|
||||
packages.NeedTypesInfo |
|
||||
packages.NeedSyntax
|
||||
|
||||
var generatedCodePattern = regexp.MustCompile(`^// Code generated .* DO NOT EDIT\.$`)
|
||||
|
||||
// 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.
|
||||
@@ -70,40 +72,48 @@ type Metrics struct {
|
||||
// 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
|
||||
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
|
||||
excludeGenerated bool
|
||||
showIgnored bool
|
||||
}
|
||||
|
||||
// NewAnalyzer builds a new analyzer.
|
||||
func NewAnalyzer(conf Config, tests bool, logger *log.Logger) *Analyzer {
|
||||
func NewAnalyzer(conf Config, tests bool, excludeGenerated bool, logger *log.Logger) *Analyzer {
|
||||
ignoreNoSec := false
|
||||
if enabled, err := conf.IsGlobalEnabled(Nosec); err == nil {
|
||||
ignoreNoSec = enabled
|
||||
}
|
||||
showIgnored := false
|
||||
if enabled, err := conf.IsGlobalEnabled(ShowIgnored); err == nil {
|
||||
showIgnored = 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,
|
||||
ignoreNosec: ignoreNoSec,
|
||||
showIgnored: showIgnored,
|
||||
ruleset: make(RuleSet),
|
||||
context: &Context{},
|
||||
config: conf,
|
||||
logger: logger,
|
||||
issues: make([]*Issue, 0, 16),
|
||||
stats: &Metrics{},
|
||||
errors: make(map[string][]Error),
|
||||
tests: tests,
|
||||
excludeGenerated: excludeGenerated,
|
||||
}
|
||||
}
|
||||
|
||||
// SetConfig upates the analyzer configuration
|
||||
// SetConfig updates the analyzer configuration
|
||||
func (gosec *Analyzer) SetConfig(conf Config) {
|
||||
gosec.config = conf
|
||||
}
|
||||
@@ -139,7 +149,7 @@ func (gosec *Analyzer) Process(buildTags []string, packagePaths ...string) error
|
||||
if pkg.Name != "" {
|
||||
err := gosec.ParseErrors(pkg)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parsing errors in pkg %q: %v", pkg.Name, err)
|
||||
return fmt.Errorf("parsing errors in pkg %q: %w", pkg.Name, err)
|
||||
}
|
||||
gosec.Check(pkg)
|
||||
}
|
||||
@@ -163,7 +173,7 @@ func (gosec *Analyzer) load(pkgPath string, conf *packages.Config) ([]*packages.
|
||||
buildD.BuildTags = conf.BuildFlags
|
||||
basePackage, err := buildD.ImportDir(pkgPath, build.ImportComment)
|
||||
if err != nil {
|
||||
return []*packages.Package{}, fmt.Errorf("importing dir %q: %v", pkgPath, err)
|
||||
return []*packages.Package{}, fmt.Errorf("importing dir %q: %w", pkgPath, err)
|
||||
}
|
||||
|
||||
var packageFiles []string
|
||||
@@ -175,7 +185,7 @@ func (gosec *Analyzer) load(pkgPath string, conf *packages.Config) ([]*packages.
|
||||
}
|
||||
|
||||
if gosec.tests {
|
||||
testsFiles := []string{}
|
||||
testsFiles := make([]string, 0)
|
||||
testsFiles = append(testsFiles, basePackage.TestGoFiles...)
|
||||
testsFiles = append(testsFiles, basePackage.XTestGoFiles...)
|
||||
for _, filename := range testsFiles {
|
||||
@@ -187,7 +197,7 @@ func (gosec *Analyzer) load(pkgPath string, conf *packages.Config) ([]*packages.
|
||||
conf.BuildFlags = nil
|
||||
pkgs, err := packages.Load(conf, packageFiles...)
|
||||
if err != nil {
|
||||
return []*packages.Package{}, fmt.Errorf("loading files from package %q: %v", pkgPath, err)
|
||||
return []*packages.Package{}, fmt.Errorf("loading files from package %q: %w", pkgPath, err)
|
||||
}
|
||||
return pkgs, nil
|
||||
}
|
||||
@@ -202,6 +212,11 @@ func (gosec *Analyzer) Check(pkg *packages.Package) {
|
||||
if filepath.Ext(checkedFile) != ".go" {
|
||||
continue
|
||||
}
|
||||
if gosec.excludeGenerated && isGeneratedFile(file) {
|
||||
gosec.logger.Println("Ignoring generated file:", checkedFile)
|
||||
continue
|
||||
}
|
||||
|
||||
gosec.logger.Println("Checking file:", checkedFile)
|
||||
gosec.context.FileSet = pkg.Fset
|
||||
gosec.context.Config = gosec.config
|
||||
@@ -219,6 +234,17 @@ func (gosec *Analyzer) Check(pkg *packages.Package) {
|
||||
}
|
||||
}
|
||||
|
||||
func isGeneratedFile(file *ast.File) bool {
|
||||
for _, comment := range file.Comments {
|
||||
for _, row := range comment.List {
|
||||
if generatedCodePattern.MatchString(row.Text) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// ParseErrors parses the errors from given package
|
||||
func (gosec *Analyzer) ParseErrors(pkg *packages.Package) error {
|
||||
if len(pkg.Errors) == 0 {
|
||||
@@ -231,13 +257,13 @@ func (gosec *Analyzer) ParseErrors(pkg *packages.Package) error {
|
||||
var line int
|
||||
if len(parts) > 1 {
|
||||
if line, err = strconv.Atoi(parts[1]); err != nil {
|
||||
return fmt.Errorf("parsing line: %v", err)
|
||||
return fmt.Errorf("parsing line: %w", err)
|
||||
}
|
||||
}
|
||||
var column int
|
||||
if len(parts) > 2 {
|
||||
if column, err = strconv.Atoi(parts[2]); err != nil {
|
||||
return fmt.Errorf("parsing column: %v", err)
|
||||
return fmt.Errorf("parsing column: %w", err)
|
||||
}
|
||||
}
|
||||
msg := strings.TrimSpace(pkgErr.Msg)
|
||||
@@ -259,7 +285,7 @@ func (gosec *Analyzer) AppendError(file string, err error) {
|
||||
if r.MatchString(err.Error()) {
|
||||
return
|
||||
}
|
||||
errors := []Error{}
|
||||
errors := make([]Error, 0)
|
||||
if ferrs, ok := gosec.errors[file]; ok {
|
||||
errors = ferrs
|
||||
}
|
||||
@@ -344,9 +370,8 @@ func (gosec *Analyzer) Visit(n ast.Node) ast.Visitor {
|
||||
gosec.context.Imports.TrackImport(n)
|
||||
|
||||
for _, rule := range gosec.ruleset.RegisteredFor(n) {
|
||||
if _, ok := ignores[rule.ID()]; ok {
|
||||
continue
|
||||
}
|
||||
_, ignored := ignores[rule.ID()]
|
||||
|
||||
issue, err := rule.Match(n, gosec.context)
|
||||
if err != nil {
|
||||
file, line := GetLocation(n, gosec.context)
|
||||
@@ -354,8 +379,15 @@ func (gosec *Analyzer) Visit(n ast.Node) ast.Visitor {
|
||||
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++
|
||||
if gosec.showIgnored {
|
||||
issue.NoSec = ignored
|
||||
}
|
||||
if !ignored || !gosec.showIgnored {
|
||||
gosec.stats.NumFound++
|
||||
}
|
||||
if !ignored || gosec.showIgnored || gosec.ignoreNosec {
|
||||
gosec.issues = append(gosec.issues, issue)
|
||||
}
|
||||
}
|
||||
}
|
||||
return gosec
|
||||
|
||||
@@ -7,13 +7,12 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/securego/gosec/v2"
|
||||
"github.com/securego/gosec/v2/rules"
|
||||
"golang.org/x/tools/go/packages"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/securego/gosec/v2"
|
||||
"github.com/securego/gosec/v2/rules"
|
||||
"github.com/securego/gosec/v2/testutils"
|
||||
"golang.org/x/tools/go/packages"
|
||||
)
|
||||
|
||||
var _ = Describe("Analyzer", func() {
|
||||
@@ -25,7 +24,7 @@ var _ = Describe("Analyzer", func() {
|
||||
)
|
||||
BeforeEach(func() {
|
||||
logger, _ = testutils.NewLogger()
|
||||
analyzer = gosec.NewAnalyzer(nil, tests, logger)
|
||||
analyzer = gosec.NewAnalyzer(nil, tests, false, logger)
|
||||
})
|
||||
|
||||
Context("when processing a package", func() {
|
||||
@@ -246,7 +245,7 @@ var _ = Describe("Analyzer", func() {
|
||||
// overwrite nosec option
|
||||
nosecIgnoreConfig := gosec.NewConfig()
|
||||
nosecIgnoreConfig.SetGlobal(gosec.Nosec, "true")
|
||||
customAnalyzer := gosec.NewAnalyzer(nosecIgnoreConfig, tests, logger)
|
||||
customAnalyzer := gosec.NewAnalyzer(nosecIgnoreConfig, tests, false, logger)
|
||||
customAnalyzer.LoadRules(rules.Generate(rules.NewRuleFilter(false, "G401")).Builders())
|
||||
|
||||
nosecPackage := testutils.NewTestPackage()
|
||||
@@ -261,6 +260,32 @@ var _ = Describe("Analyzer", func() {
|
||||
Expect(nosecIssues).Should(HaveLen(sample.Errors))
|
||||
})
|
||||
|
||||
XIt("should be possible to overwrite nosec comments, and report issues but the should not be counted", func() {
|
||||
// Rule for MD5 weak crypto usage
|
||||
sample := testutils.SampleCodeG401[0]
|
||||
source := sample.Code[0]
|
||||
|
||||
// overwrite nosec option
|
||||
nosecIgnoreConfig := gosec.NewConfig()
|
||||
nosecIgnoreConfig.SetGlobal(gosec.Nosec, "true")
|
||||
nosecIgnoreConfig.SetGlobal(gosec.ShowIgnored, "true")
|
||||
customAnalyzer := gosec.NewAnalyzer(nosecIgnoreConfig, tests, false, logger)
|
||||
customAnalyzer.LoadRules(rules.Generate(rules.NewRuleFilter(false, "G401")).Builders())
|
||||
|
||||
nosecPackage := testutils.NewTestPackage()
|
||||
defer nosecPackage.Close()
|
||||
nosecSource := strings.Replace(source, "h := md5.New()", "h := md5.New() // #nosec", 1)
|
||||
nosecPackage.AddFile("md5.go", nosecSource)
|
||||
err := nosecPackage.Build()
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
err = customAnalyzer.Process(buildTags, nosecPackage.Path)
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
nosecIssues, metrics, _ := customAnalyzer.Report()
|
||||
Expect(nosecIssues).Should(HaveLen(sample.Errors))
|
||||
Expect(metrics.NumFound).Should(Equal(0))
|
||||
Expect(metrics.NumNosec).Should(Equal(1))
|
||||
})
|
||||
|
||||
It("should be possible to use an alternative nosec tag", func() {
|
||||
// Rule for MD5 weak crypto usage
|
||||
sample := testutils.SampleCodeG401[0]
|
||||
@@ -269,7 +294,7 @@ var _ = Describe("Analyzer", func() {
|
||||
// overwrite nosec option
|
||||
nosecIgnoreConfig := gosec.NewConfig()
|
||||
nosecIgnoreConfig.SetGlobal(gosec.NoSecAlternative, "#falsePositive")
|
||||
customAnalyzer := gosec.NewAnalyzer(nosecIgnoreConfig, tests, logger)
|
||||
customAnalyzer := gosec.NewAnalyzer(nosecIgnoreConfig, tests, false, logger)
|
||||
customAnalyzer.LoadRules(rules.Generate(rules.NewRuleFilter(false, "G401")).Builders())
|
||||
|
||||
nosecPackage := testutils.NewTestPackage()
|
||||
@@ -292,7 +317,7 @@ var _ = Describe("Analyzer", func() {
|
||||
// overwrite nosec option
|
||||
nosecIgnoreConfig := gosec.NewConfig()
|
||||
nosecIgnoreConfig.SetGlobal(gosec.NoSecAlternative, "#falsePositive")
|
||||
customAnalyzer := gosec.NewAnalyzer(nosecIgnoreConfig, tests, logger)
|
||||
customAnalyzer := gosec.NewAnalyzer(nosecIgnoreConfig, tests, false, logger)
|
||||
customAnalyzer.LoadRules(rules.Generate(rules.NewRuleFilter(false, "G401")).Builders())
|
||||
|
||||
nosecPackage := testutils.NewTestPackage()
|
||||
@@ -308,7 +333,7 @@ var _ = Describe("Analyzer", func() {
|
||||
})
|
||||
|
||||
It("should be able to analyze Go test package", func() {
|
||||
customAnalyzer := gosec.NewAnalyzer(nil, true, logger)
|
||||
customAnalyzer := gosec.NewAnalyzer(nil, true, false, logger)
|
||||
customAnalyzer.LoadRules(rules.Generate().Builders())
|
||||
pkg := testutils.NewTestPackage()
|
||||
defer pkg.Close()
|
||||
@@ -332,6 +357,48 @@ var _ = Describe("Analyzer", func() {
|
||||
issues, _, _ := customAnalyzer.Report()
|
||||
Expect(issues).Should(HaveLen(1))
|
||||
})
|
||||
It("should be able to scan generated files if NOT excluded", func() {
|
||||
customAnalyzer := gosec.NewAnalyzer(nil, true, false, logger)
|
||||
customAnalyzer.LoadRules(rules.Generate().Builders())
|
||||
pkg := testutils.NewTestPackage()
|
||||
defer pkg.Close()
|
||||
pkg.AddFile("foo.go", `
|
||||
package foo
|
||||
// Code generated some-generator DO NOT EDIT.
|
||||
func test() error {
|
||||
return nil
|
||||
}
|
||||
func TestFoo(t *testing.T){
|
||||
test()
|
||||
}`)
|
||||
err := pkg.Build()
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
err = customAnalyzer.Process(buildTags, pkg.Path)
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
issues, _, _ := customAnalyzer.Report()
|
||||
Expect(issues).Should(HaveLen(1))
|
||||
})
|
||||
It("should be able to skip generated files if excluded", func() {
|
||||
customAnalyzer := gosec.NewAnalyzer(nil, true, true, logger)
|
||||
customAnalyzer.LoadRules(rules.Generate().Builders())
|
||||
pkg := testutils.NewTestPackage()
|
||||
defer pkg.Close()
|
||||
pkg.AddFile("foo.go", `
|
||||
package foo
|
||||
// Code generated some-generator DO NOT EDIT.
|
||||
func test() error {
|
||||
return nil
|
||||
}
|
||||
func TestFoo(t *testing.T){
|
||||
test()
|
||||
}`)
|
||||
err := pkg.Build()
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
err = customAnalyzer.Process(buildTags, pkg.Path)
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
issues, _, _ := customAnalyzer.Report()
|
||||
Expect(issues).Should(HaveLen(0))
|
||||
})
|
||||
})
|
||||
It("should be able to analyze Cgo files", func() {
|
||||
analyzer.LoadRules(rules.Generate().Builders())
|
||||
|
||||
@@ -24,6 +24,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/securego/gosec/v2"
|
||||
"github.com/securego/gosec/v2/cmd/vflag"
|
||||
"github.com/securego/gosec/v2/report"
|
||||
"github.com/securego/gosec/v2/rules"
|
||||
)
|
||||
@@ -72,6 +73,9 @@ var (
|
||||
// #nosec flag
|
||||
flagIgnoreNoSec = flag.Bool("nosec", false, "Ignores #nosec comments when set")
|
||||
|
||||
// show ignored
|
||||
flagShowIgnored = flag.Bool("show-ignored", false, "If enabled, ignored issues are printed")
|
||||
|
||||
// format output
|
||||
flagFormat = flag.String("fmt", "text", "Set output format. Valid options are: json, yaml, csv, junit-xml, html, sonarqube, golint, sarif or text")
|
||||
|
||||
@@ -91,11 +95,13 @@ var (
|
||||
flagRulesInclude = flag.String("include", "", "Comma separated list of rules IDs to include. (see rule list)")
|
||||
|
||||
// rules to explicitly exclude
|
||||
flagRulesExclude = flag.String("exclude", "", "Comma separated list of rules IDs to exclude. (see rule list)")
|
||||
flagRulesExclude = vflag.ValidatedFlag{}
|
||||
|
||||
// rules to explicitly exclude
|
||||
flagExcludeGenerated = flag.Bool("exclude-generated", false, "Exclude generated files")
|
||||
|
||||
// log to file or stderr
|
||||
flagLogfile = flag.String("log", "", "Log messages to file rather than stderr")
|
||||
|
||||
// sort the issues by severity
|
||||
flagSortIssues = flag.Bool("sort", true, "Sort issues by severity")
|
||||
|
||||
@@ -170,6 +176,9 @@ func loadConfig(configFile string) (gosec.Config, error) {
|
||||
if *flagIgnoreNoSec {
|
||||
config.SetGlobal(gosec.Nosec, "true")
|
||||
}
|
||||
if *flagShowIgnored {
|
||||
config.SetGlobal(gosec.ShowIgnored, "true")
|
||||
}
|
||||
if *flagAlternativeNoSec != "" {
|
||||
config.SetGlobal(gosec.NoSecAlternative, *flagAlternativeNoSec)
|
||||
}
|
||||
@@ -197,11 +206,11 @@ func loadRules(include, exclude string) rules.RuleList {
|
||||
}
|
||||
|
||||
func getRootPaths(paths []string) []string {
|
||||
rootPaths := []string{}
|
||||
rootPaths := make([]string, 0)
|
||||
for _, path := range paths {
|
||||
rootPath, err := gosec.RootPath(path)
|
||||
if err != nil {
|
||||
logger.Fatal(fmt.Errorf("failed to get the root path of the projects: %s", err))
|
||||
logger.Fatal(fmt.Errorf("failed to get the root path of the projects: %w", err))
|
||||
}
|
||||
rootPaths = append(rootPaths, rootPath)
|
||||
}
|
||||
@@ -238,9 +247,9 @@ func saveReport(filename, format string, rootPaths []string, reportInfo *gosec.R
|
||||
return nil
|
||||
}
|
||||
|
||||
func convertToScore(severity string) (gosec.Score, error) {
|
||||
severity = strings.ToLower(severity)
|
||||
switch severity {
|
||||
func convertToScore(value string) (gosec.Score, error) {
|
||||
value = strings.ToLower(value)
|
||||
switch value {
|
||||
case "low":
|
||||
return gosec.Low, nil
|
||||
case "medium":
|
||||
@@ -248,18 +257,22 @@ func convertToScore(severity string) (gosec.Score, error) {
|
||||
case "high":
|
||||
return gosec.High, nil
|
||||
default:
|
||||
return gosec.Low, fmt.Errorf("provided severity '%s' not valid. Valid options: low, medium, high", severity)
|
||||
return gosec.Low, fmt.Errorf("provided value '%s' not valid. Valid options: low, medium, high", value)
|
||||
}
|
||||
}
|
||||
|
||||
func filterIssues(issues []*gosec.Issue, severity gosec.Score, confidence gosec.Score) []*gosec.Issue {
|
||||
result := []*gosec.Issue{}
|
||||
func filterIssues(issues []*gosec.Issue, severity gosec.Score, confidence gosec.Score) ([]*gosec.Issue, int) {
|
||||
result := make([]*gosec.Issue, 0)
|
||||
trueIssues := 0
|
||||
for _, issue := range issues {
|
||||
if issue.Severity >= severity && issue.Confidence >= confidence {
|
||||
result = append(result, issue)
|
||||
if !issue.NoSec || !*flagShowIgnored {
|
||||
trueIssues++
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
return result, trueIssues
|
||||
}
|
||||
|
||||
func main() {
|
||||
@@ -280,6 +293,9 @@ func main() {
|
||||
fmt.Fprintf(os.Stderr, "\nError: failed to exclude the %q directory from scan", ".git")
|
||||
}
|
||||
|
||||
// set for exclude
|
||||
flag.Var(&flagRulesExclude, "exclude", "Comma separated list of rules IDs to exclude. (see rule list)")
|
||||
|
||||
// Parse command line arguments
|
||||
flag.Parse()
|
||||
|
||||
@@ -329,13 +345,13 @@ func main() {
|
||||
}
|
||||
|
||||
// Load enabled rule definitions
|
||||
ruleDefinitions := loadRules(*flagRulesInclude, *flagRulesExclude)
|
||||
ruleDefinitions := loadRules(*flagRulesInclude, flagRulesExclude.String())
|
||||
if len(ruleDefinitions) == 0 {
|
||||
logger.Fatal("No rules are configured")
|
||||
}
|
||||
|
||||
// Create the analyzer
|
||||
analyzer := gosec.NewAnalyzer(config, *flagScanTests, logger)
|
||||
analyzer := gosec.NewAnalyzer(config, *flagScanTests, *flagExcludeGenerated, logger)
|
||||
analyzer.LoadRules(ruleDefinitions.Builders())
|
||||
|
||||
excludedDirs := gosec.ExcludedDirsRegExp(flagDirsExclude)
|
||||
@@ -369,9 +385,10 @@ func main() {
|
||||
}
|
||||
|
||||
// Filter the issues by severity and confidence
|
||||
issues = filterIssues(issues, failSeverity, failConfidence)
|
||||
if metrics.NumFound != len(issues) {
|
||||
metrics.NumFound = len(issues)
|
||||
var trueIssues int
|
||||
issues, trueIssues = filterIssues(issues, failSeverity, failConfidence)
|
||||
if metrics.NumFound != trueIssues {
|
||||
metrics.NumFound = trueIssues
|
||||
}
|
||||
|
||||
// Exit quietly if nothing was found
|
||||
@@ -387,7 +404,7 @@ func main() {
|
||||
if *flagOutput == "" || *flagStdOut {
|
||||
fileFormat := getPrintedFormat(*flagFormat, *flagVerbose)
|
||||
if err := printReport(fileFormat, *flagColor, rootPaths, reportInfo); err != nil {
|
||||
logger.Fatal((err))
|
||||
logger.Fatal(err)
|
||||
}
|
||||
}
|
||||
if *flagOutput != "" {
|
||||
|
||||
@@ -38,7 +38,7 @@ func firstIsGreater(less, greater *gosec.Issue) {
|
||||
}
|
||||
|
||||
var _ = Describe("Sorting by Severity", func() {
|
||||
It("sortes by severity", func() {
|
||||
It("sorts by severity", func() {
|
||||
less := createIssue()
|
||||
less.Severity = gosec.Low
|
||||
greater := createIssue()
|
||||
@@ -46,8 +46,8 @@ var _ = Describe("Sorting by Severity", func() {
|
||||
firstIsGreater(&less, &greater)
|
||||
})
|
||||
|
||||
Context("Serverity is same", func() {
|
||||
It("sortes by What", func() {
|
||||
Context("Severity is same", func() {
|
||||
It("sorts by What", func() {
|
||||
less := createIssue()
|
||||
less.What = "test1"
|
||||
greater := createIssue()
|
||||
@@ -56,8 +56,8 @@ var _ = Describe("Sorting by Severity", func() {
|
||||
})
|
||||
})
|
||||
|
||||
Context("Serverity and What is same", func() {
|
||||
It("sortes by File", func() {
|
||||
Context("Severity and What is same", func() {
|
||||
It("sorts by File", func() {
|
||||
less := createIssue()
|
||||
less.File = "test1"
|
||||
greater := createIssue()
|
||||
@@ -67,8 +67,8 @@ var _ = Describe("Sorting by Severity", func() {
|
||||
})
|
||||
})
|
||||
|
||||
Context("Serverity, What and File is same", func() {
|
||||
It("sortes by line number", func() {
|
||||
Context("Severity, What and File is same", func() {
|
||||
It("sorts by line number", func() {
|
||||
less := createIssue()
|
||||
less.Line = "1"
|
||||
greater := createIssue()
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//go:build go1.14 || !go1.11
|
||||
// +build go1.14 !go1.11
|
||||
|
||||
// main
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//go:build go1.12
|
||||
// +build go1.12
|
||||
|
||||
package main
|
||||
@@ -187,7 +188,7 @@ func main() {
|
||||
}
|
||||
|
||||
outputPath := filepath.Join(dir, *outputFile)
|
||||
if err := ioutil.WriteFile(outputPath, src, 0644); err != nil {
|
||||
if err := ioutil.WriteFile(outputPath, src, 0o644); err != nil {
|
||||
log.Fatalf("Writing output: %s", err)
|
||||
} // #nosec G306
|
||||
}
|
||||
|
||||
25
cmd/vflag/flag.go
Normal file
25
cmd/vflag/flag.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package vflag
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ValidatedFlag cli string type
|
||||
type ValidatedFlag struct {
|
||||
Value string
|
||||
}
|
||||
|
||||
func (f *ValidatedFlag) String() string {
|
||||
return f.Value
|
||||
}
|
||||
|
||||
// Set will be called for flag that is of validateFlag type
|
||||
func (f *ValidatedFlag) Set(value string) error {
|
||||
if strings.Contains(value, "-") {
|
||||
return errors.New("flag value cannot start with -")
|
||||
}
|
||||
|
||||
f.Value = value
|
||||
return nil
|
||||
}
|
||||
@@ -20,6 +20,8 @@ type GlobalOption string
|
||||
const (
|
||||
// Nosec global option for #nosec directive
|
||||
Nosec GlobalOption = "nosec"
|
||||
// ShowIgnored defines whether nosec issues are counted as finding or not
|
||||
ShowIgnored GlobalOption = "show-ignored"
|
||||
// Audit global option which indicates that gosec runs in audit mode
|
||||
Audit GlobalOption = "audit"
|
||||
// NoSecAlternative global option alternative for #nosec directive
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Expand the arguments into an array of strings. This is requires because the GitHub action
|
||||
# Expand the arguments into an array of strings. This is required because the GitHub action
|
||||
# provides all arguments concatenated as a single string.
|
||||
ARGS=("$@")
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ func NewError(line, column int, err string) *Error {
|
||||
}
|
||||
}
|
||||
|
||||
// sortErros sorts the golang erros by line
|
||||
// sortErrors sorts the golang errors by line
|
||||
func sortErrors(allErrors map[string][]Error) {
|
||||
for _, errors := range allErrors {
|
||||
sort.Slice(errors, func(i, j int) bool {
|
||||
|
||||
42
flag_test.go
Normal file
42
flag_test.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package gosec_test
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"os"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/securego/gosec/v2/cmd/vflag"
|
||||
)
|
||||
|
||||
var _ = Describe("Cli", func() {
|
||||
Context("vflag test", func() {
|
||||
It("value must be empty as parameter value contains invalid character", func() {
|
||||
os.Args = []string{"gosec", "-test1=-incorrect"}
|
||||
f := vflag.ValidatedFlag{}
|
||||
flag.Var(&f, "test1", "")
|
||||
flag.CommandLine.Init("test1", flag.ContinueOnError)
|
||||
flag.Parse()
|
||||
Expect(flag.Parsed()).Should(Equal(true))
|
||||
Expect(f.Value).Should(Equal(``))
|
||||
})
|
||||
It("value must be empty as parameter value contains invalid character without equal sign", func() {
|
||||
os.Args = []string{"gosec", "-test2= -incorrect"}
|
||||
f := vflag.ValidatedFlag{}
|
||||
flag.Var(&f, "test2", "")
|
||||
flag.CommandLine.Init("test2", flag.ContinueOnError)
|
||||
flag.Parse()
|
||||
Expect(flag.Parsed()).Should(Equal(true))
|
||||
Expect(f.Value).Should(Equal(``))
|
||||
})
|
||||
It("value must not be empty as parameter value contains valid character", func() {
|
||||
os.Args = []string{"gosec", "-test3=correct"}
|
||||
f := vflag.ValidatedFlag{}
|
||||
flag.Var(&f, "test3", "")
|
||||
flag.CommandLine.Init("test3", flag.ContinueOnError)
|
||||
flag.Parse()
|
||||
Expect(flag.Parsed()).Should(Equal(true))
|
||||
Expect(f.Value).Should(Equal(`correct`))
|
||||
})
|
||||
})
|
||||
})
|
||||
16
go.mod
16
go.mod
@@ -1,17 +1,17 @@
|
||||
module github.com/securego/gosec/v2
|
||||
|
||||
require (
|
||||
github.com/google/uuid v1.2.0
|
||||
github.com/gookit/color v1.4.2
|
||||
github.com/lib/pq v1.10.2
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/gookit/color v1.5.0
|
||||
github.com/lib/pq v1.10.4
|
||||
github.com/mozilla/tls-observatory v0.0.0-20210609171429-7bc42856d2e5
|
||||
github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354
|
||||
github.com/onsi/ginkgo v1.16.4
|
||||
github.com/onsi/gomega v1.13.0
|
||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a
|
||||
github.com/onsi/ginkgo v1.16.5
|
||||
github.com/onsi/gomega v1.17.0
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519
|
||||
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616
|
||||
golang.org/x/text v0.3.6
|
||||
golang.org/x/tools v0.1.3
|
||||
golang.org/x/text v0.3.7
|
||||
golang.org/x/tools v0.1.7
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
)
|
||||
|
||||
|
||||
45
go.sum
45
go.sum
@@ -162,12 +162,12 @@ github.com/google/trillian v1.3.11/go.mod h1:0tPraVHrSDkA3BO6vKX67zgLXs6SsOAbHEi
|
||||
github.com/google/uuid v0.0.0-20161128191214-064e2069ce9c/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs=
|
||||
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/gookit/color v1.4.2 h1:tXy44JFSFkKnELV6WaMo/lLfu/meqITX3iAV52do7lk=
|
||||
github.com/gookit/color v1.4.2/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQHCoQ=
|
||||
github.com/gookit/color v1.5.0 h1:1Opow3+BWDwqor78DcJkJCIwnkviFi+rrOANki9BUFw=
|
||||
github.com/gookit/color v1.5.0/go.mod h1:43aQb+Zerm/BWh2GnrgOQm7ffz7tvQXEKV6BFMl7wAo=
|
||||
github.com/gordonklaus/ineffassign v0.0.0-20200309095847-7953dde2c7bf/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU=
|
||||
github.com/gorhill/cronexpr v0.0.0-20180427100037-88b0669f7d75/go.mod h1:g2644b03hfBX9Ov0ZBDgXXens4rxSxmqFBbhvKv2yVA=
|
||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
@@ -219,8 +219,8 @@ github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+
|
||||
github.com/letsencrypt/pkcs11key/v4 v4.0.0/go.mod h1:EFUvBDay26dErnNb70Nd0/VW3tJiIbETBPTl9ATXQag=
|
||||
github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/lib/pq v1.9.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8=
|
||||
github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/lib/pq v1.10.4 h1:SO9z7FRPzA03QhHKJrH5BXA6HU1rS4V2nIVrrNC1iYk=
|
||||
github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
@@ -264,13 +264,13 @@ github.com/olekukonko/tablewriter v0.0.2/go.mod h1:rSAaSIOAGT9odnlyGlUfAJaoc5w2f
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||
github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E=
|
||||
github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
|
||||
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
|
||||
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
||||
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/onsi/gomega v1.13.0 h1:7lLHu94wT9Ij0o6EWWclhu0aOh32VxhkwEJvzuWPeak=
|
||||
github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY=
|
||||
github.com/onsi/gomega v1.17.0 h1:9Luw4uT5HTjHTN8+aNcSThgH1vdXnmdJ8xIfZ4wyTRE=
|
||||
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
|
||||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
|
||||
@@ -323,8 +323,9 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20200427203606-3cfed13b9966/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
@@ -344,7 +345,7 @@ github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
|
||||
go.etcd.io/etcd v0.0.0-20200513171258-e048e166ab9c/go.mod h1:xCI7ZzBfRuGgBXyXO6yfWfDmlWd35khcWpUa4L0xI/k=
|
||||
@@ -372,8 +373,8 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a h1:kr2P4QFmQr29mSLA43kwrOcgcReGTfbE9N577tCTuBc=
|
||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
@@ -444,9 +445,9 @@ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81R
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 h1:DzZ89McO9/gWPsQXS/FVKAlG02ZjaQ6AlZRBimEYOd0=
|
||||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
||||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI=
|
||||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@@ -510,8 +511,9 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA=
|
||||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
@@ -520,8 +522,9 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
@@ -574,8 +577,8 @@ golang.org/x/tools v0.0.0-20200626171337-aa94e735be7f/go.mod h1:EkVYQZoAsY45+roY
|
||||
golang.org/x/tools v0.0.0-20200630154851-b2d8b0336632/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200706234117-b22de6825cf7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.3 h1:L69ShwSZEyCsLKoAxDKeMvLDZkumEe8gXUZAjab0tX8=
|
||||
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ=
|
||||
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
||||
@@ -402,7 +402,7 @@ func PackagePaths(root string, excludes []*regexp.Regexp) ([]string, error) {
|
||||
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) {
|
||||
if isExcluded(filepath.ToSlash(path), excludes) {
|
||||
return nil
|
||||
}
|
||||
paths[path] = true
|
||||
@@ -437,7 +437,7 @@ func isExcluded(str string, excludes []*regexp.Regexp) bool {
|
||||
func ExcludedDirsRegExp(excludedDirs []string) []*regexp.Regexp {
|
||||
var exps []*regexp.Regexp
|
||||
for _, excludedDir := range excludedDirs {
|
||||
str := fmt.Sprintf(`([\\/])?%s([\\/])?`, excludedDir)
|
||||
str := fmt.Sprintf(`([\\/])?%s([\\/])?`, strings.ReplaceAll(filepath.ToSlash(excludedDir), "/", `\/`))
|
||||
r := regexp.MustCompile(str)
|
||||
exps = append(exps, r)
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ var _ = Describe("Helpers", func() {
|
||||
})
|
||||
It("should exclude folder", func() {
|
||||
nested := dir + "/vendor"
|
||||
err := os.Mkdir(nested, 0755)
|
||||
err := os.Mkdir(nested, 0o755)
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
_, err = os.Create(nested + "/test.go")
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
@@ -49,6 +49,18 @@ var _ = Describe("Helpers", func() {
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
Expect(paths).Should(Equal([]string{dir}))
|
||||
})
|
||||
It("should exclude folder with subpath", func() {
|
||||
nested := dir + "/pkg/generated"
|
||||
err := os.MkdirAll(nested, 0o755)
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
_, err = os.Create(nested + "/test.go")
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
exclude, err := regexp.Compile(`([\\/])?/pkg\/generated([\\/])?`)
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
paths, err := gosec.PackagePaths(dir+"/...", []*regexp.Regexp{exclude})
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
Expect(paths).Should(Equal([]string{dir}))
|
||||
})
|
||||
It("should be empty when folder does not exist", func() {
|
||||
nested := dir + "/test"
|
||||
paths, err := gosec.PackagePaths(nested+"/...", nil)
|
||||
@@ -66,7 +78,7 @@ var _ = Describe("Helpers", func() {
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
Expect(root).Should(Equal(filepath.Join(cwd, base)))
|
||||
})
|
||||
It("should retrun the absolute path from ellipsis path", func() {
|
||||
It("should return the absolute path from ellipsis path", func() {
|
||||
base := "test"
|
||||
cwd, err := os.Getwd()
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
@@ -86,6 +98,17 @@ var _ = Describe("Helpers", func() {
|
||||
Expect(match).Should(BeFalse())
|
||||
})
|
||||
|
||||
It("should create a proper regexp for dir with subdir", func() {
|
||||
r := gosec.ExcludedDirsRegExp([]string{`test/generated`})
|
||||
Expect(len(r)).Should(Equal(1))
|
||||
match := r[0].MatchString("/home/go/src/project/test/generated")
|
||||
Expect(match).Should(BeTrue())
|
||||
match = r[0].MatchString("/home/go/src/project/test/pkg")
|
||||
Expect(match).Should(BeFalse())
|
||||
match = r[0].MatchString("/home/go/src/project/vendor/pkg")
|
||||
Expect(match).Should(BeFalse())
|
||||
})
|
||||
|
||||
It("should create no regexp when dir list is empty", func() {
|
||||
r := gosec.ExcludedDirsRegExp(nil)
|
||||
Expect(len(r)).Should(Equal(0))
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
package gosec_test
|
||||
|
||||
import (
|
||||
"github.com/securego/gosec/v2"
|
||||
"github.com/securego/gosec/v2/testutils"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/securego/gosec/v2"
|
||||
"github.com/securego/gosec/v2/testutils"
|
||||
)
|
||||
|
||||
var _ = Describe("Import Tracker", func() {
|
||||
|
||||
1
issue.go
1
issue.go
@@ -97,6 +97,7 @@ type Issue struct {
|
||||
Code string `json:"code"` // Impacted code line
|
||||
Line string `json:"line"` // Line number in file
|
||||
Col string `json:"column"` // Column number in line
|
||||
NoSec bool `json:"nosec"` // true if the issue is nosec
|
||||
}
|
||||
|
||||
// FileLocation point out the file path and line number in file
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"dependencyDashboard": true,
|
||||
"dependencyDashboardTitle" : "Renovate(bot) : dependency dashboard",
|
||||
"vulnerabilityAlerts": {
|
||||
"enabled": true
|
||||
},
|
||||
|
||||
@@ -1,20 +1,3 @@
|
||||
// (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 html
|
||||
|
||||
const templateContent = `
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
@@ -41,6 +24,15 @@ const templateContent = `
|
||||
.tag {
|
||||
width: 80px;
|
||||
}
|
||||
.summary-first {
|
||||
padding: .75rem .75rem .1rem .75rem;
|
||||
}
|
||||
.summary-last {
|
||||
padding: .1rem .75rem .75rem .75rem;
|
||||
}
|
||||
.summary {
|
||||
padding: .1rem .75rem ;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@@ -62,6 +54,8 @@ const templateContent = `
|
||||
level += " is-warning";
|
||||
} else if (this.props.level === "LOW") {
|
||||
level += " is-info";
|
||||
} else if (this.props.level === "WAIVED") {
|
||||
level += " is-success";
|
||||
}
|
||||
level +=" is-rounded";
|
||||
return (
|
||||
@@ -92,17 +86,18 @@ const templateContent = `
|
||||
<div className="columns">
|
||||
<div className="column is-three-quarters">
|
||||
<strong className="break-word">{ this.props.data.file } (line { this.props.data.line })</strong>
|
||||
<p>{ this.props.data.details }</p>
|
||||
<p>{this.props.data.rule_id} (CWE-{this.props.data.cwe.id}): { this.props.data.details }</p>
|
||||
</div>
|
||||
<div className="column is-one-quarter">
|
||||
<div className="field is-grouped is-grouped-multiline">
|
||||
{this.props.data.nosec && <IssueTag label="NoSec" level="WAIVED"/>}
|
||||
<IssueTag label="Severity" level={ this.props.data.severity }/>
|
||||
<IssueTag label="Confidence" level={ this.props.data.confidence }/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="highlight">
|
||||
<Highlight code={ this.props.data.code }/>
|
||||
<Highlight key={ this.props.data.file + this.props.data.line } code={ this.props.data.code }/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -248,50 +243,89 @@ const templateContent = `
|
||||
);
|
||||
}.bind(this));
|
||||
return (
|
||||
<nav className="panel">
|
||||
<div className="panel-heading">Filters</div>
|
||||
<div className="panel-block">
|
||||
<div className="field is-horizontal">
|
||||
<div className="field-label is-normal">
|
||||
<label className="label is-pulled-left">Severity</label>
|
||||
<div>
|
||||
<nav className="panel">
|
||||
<div className="panel-heading">Filters</div>
|
||||
<div className="panel-block">
|
||||
<div className="field is-horizontal">
|
||||
<div className="field-label is-normal">
|
||||
<label className="label is-pulled-left">Severity</label>
|
||||
</div>
|
||||
<div className="field-body">
|
||||
<LevelSelector selected={ this.props.severity } available={ this.props.allSeverities } onChange={ this.updateSeverity } />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="field-body">
|
||||
<LevelSelector selected={ this.props.severity } available={ this.props.allSeverities } onChange={ this.updateSeverity } />
|
||||
<div className="panel-block">
|
||||
<div className="field is-horizontal">
|
||||
<div className="field-label is-normal">
|
||||
<label className="label is-pulled-left">Confidence</label>
|
||||
</div>
|
||||
<div className="field-body">
|
||||
<LevelSelector selected={ this.props.confidence } available={ this.props.allConfidences } onChange={ this.updateConfidence } />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="panel-block">
|
||||
<div className="field is-horizontal">
|
||||
<div className="field-label is-normal">
|
||||
<label className="label is-pulled-left">Confidence</label>
|
||||
</div>
|
||||
<div className="field-body">
|
||||
<LevelSelector selected={ this.props.confidence } available={ this.props.allConfidences } onChange={ this.updateConfidence } />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="panel-block">
|
||||
<div className="field is-horizontal">
|
||||
<div className="field-label is-normal">
|
||||
<label className="label is-pulled-left">Issue type</label>
|
||||
</div>
|
||||
<div className="field-body">
|
||||
<div className="field">
|
||||
<div className="control">
|
||||
<div className="select is-fullwidth">
|
||||
<select onChange={ this.updateIssueType }>
|
||||
<option value="all" selected={ !this.props.issueType }>
|
||||
(all)
|
||||
</option>
|
||||
{ issueTypes }
|
||||
</select>
|
||||
<div className="panel-block">
|
||||
<div className="field is-horizontal">
|
||||
<div className="field-label is-normal">
|
||||
<label className="label is-pulled-left">Issue type</label>
|
||||
</div>
|
||||
<div className="field-body">
|
||||
<div className="field">
|
||||
<div className="control">
|
||||
<div className="select is-fullwidth">
|
||||
<select onChange={ this.updateIssueType }>
|
||||
<option value="all" selected={ !this.props.issueType }>
|
||||
(all)
|
||||
</option>
|
||||
{ issueTypes }
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</nav>
|
||||
<nav className="panel">
|
||||
<div className="panel-heading">Summary</div>
|
||||
<div className="panel-block">
|
||||
<div className="columns is-multiline">
|
||||
<div className="column is-half summary-first">
|
||||
<label className="label is-pulled-left">Gosec: </label>
|
||||
</div>
|
||||
<div className="column is-half summary-first">
|
||||
{this.props.data.GosecVersion}
|
||||
</div>
|
||||
<div className="column is-half summary">
|
||||
<label className="label is-pulled-left">Files: </label>
|
||||
</div>
|
||||
<div className="column is-half summary">
|
||||
{this.props.data.Stats.files.toLocaleString()}
|
||||
</div>
|
||||
<div className="column is-half summary">
|
||||
<label className="label is-pulled-left">Lines: </label>
|
||||
</div>
|
||||
<div className="column is-half summary">
|
||||
{this.props.data.Stats.lines.toLocaleString()}
|
||||
</div>
|
||||
<div className="column is-half summary">
|
||||
<label className="label is-pulled-left">Nosec: </label>
|
||||
</div>
|
||||
<div className="column is-half summary">
|
||||
{this.props.data.Stats.nosec.toLocaleString()}
|
||||
</div>
|
||||
<div className="column is-half summary-last">
|
||||
<label className="label is-pulled-left">Issues: </label>
|
||||
</div>
|
||||
<div className="column is-half summary-last">
|
||||
{this.props.data.Stats.found.toLocaleString()}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
@@ -372,6 +406,7 @@ const templateContent = `
|
||||
<div className="columns">
|
||||
<div className="column is-one-quarter">
|
||||
<Navigation
|
||||
data={ this.props.data }
|
||||
severity={ this.state.severity }
|
||||
confidence={ this.state.confidence }
|
||||
issueType={ this.state.issueType }
|
||||
@@ -402,4 +437,4 @@ const templateContent = `
|
||||
);
|
||||
</script>
|
||||
</body>
|
||||
</html>`
|
||||
</html>
|
||||
@@ -1,12 +1,18 @@
|
||||
package html
|
||||
|
||||
import (
|
||||
|
||||
// use go embed to import template
|
||||
_ "embed"
|
||||
"html/template"
|
||||
"io"
|
||||
|
||||
"github.com/securego/gosec/v2"
|
||||
)
|
||||
|
||||
//go:embed template.html
|
||||
var templateContent string
|
||||
|
||||
// WriteReport write a report in html format to the output writer
|
||||
func WriteReport(w io.Writer, data *gosec.ReportInfo) error {
|
||||
t, e := template.New("gosec").Parse(templateContent)
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/google/uuid"
|
||||
|
||||
"github.com/securego/gosec/v2"
|
||||
"github.com/securego/gosec/v2/cwe"
|
||||
)
|
||||
|
||||
@@ -269,7 +269,7 @@ type ExternalProperties struct {
|
||||
// An array of graph objects that will be merged with a separate run.
|
||||
Graphs []*Graph `json:"graphs,omitempty"`
|
||||
|
||||
// A stable, unique identifer for this external properties object, in the form of a GUID.
|
||||
// A stable, unique identifier for this external properties object, in the form of a GUID.
|
||||
GUID string `json:"guid,omitempty"`
|
||||
|
||||
// Describes the invocation of the analysis tool that will be merged with a separate run.
|
||||
@@ -287,7 +287,7 @@ type ExternalProperties struct {
|
||||
// An array of result objects that will be merged with a separate run.
|
||||
Results []*Result `json:"results,omitempty"`
|
||||
|
||||
// A stable, unique identifer for the run associated with this external properties object, in the form of a GUID.
|
||||
// A stable, unique identifier for the run associated with this external properties object, in the form of a GUID.
|
||||
RunGUID string `json:"runGuid,omitempty"`
|
||||
|
||||
// The URI of the JSON schema corresponding to the version of the external property file format.
|
||||
@@ -315,7 +315,7 @@ type ExternalProperties struct {
|
||||
// ExternalPropertyFileReference Contains information that enables a SARIF consumer to locate the external property file that contains the value of an externalized property associated with the run.
|
||||
type ExternalPropertyFileReference struct {
|
||||
|
||||
// A stable, unique identifer for the external property file in the form of a GUID.
|
||||
// A stable, unique identifier for the external property file in the form of a GUID.
|
||||
GUID string `json:"guid,omitempty"`
|
||||
|
||||
// A non-negative integer specifying the number of items contained in the external property file.
|
||||
@@ -801,7 +801,7 @@ type ReportingDescriptor struct {
|
||||
// A description of the report. Should, as far as possible, provide details sufficient to enable resolution of any problem indicated by the result.
|
||||
FullDescription *MultiformatMessageString `json:"fullDescription,omitempty"`
|
||||
|
||||
// A unique identifer for the reporting descriptor in the form of a GUID.
|
||||
// A unique identifier for the reporting descriptor in the form of a GUID.
|
||||
GUID string `json:"guid,omitempty"`
|
||||
|
||||
// Provides the primary documentation for the report, useful when there is no online documentation.
|
||||
@@ -894,7 +894,7 @@ type Result struct {
|
||||
// An array of zero or more unique graph objects associated with the result.
|
||||
Graphs []*Graph `json:"graphs,omitempty"`
|
||||
|
||||
// A stable, unique identifer for the result in the form of a GUID.
|
||||
// A stable, unique identifier for the result in the form of a GUID.
|
||||
GUID string `json:"guid,omitempty"`
|
||||
|
||||
// An absolute URI at which the result can be viewed.
|
||||
@@ -1080,7 +1080,7 @@ type RunAutomationDetails struct {
|
||||
// A description of the identity and role played within the engineering system by this object's containing run object.
|
||||
Description *Message `json:"description,omitempty"`
|
||||
|
||||
// A stable, unique identifer for this object's containing run object in the form of a GUID.
|
||||
// A stable, unique identifier for this object's containing run object in the form of a GUID.
|
||||
GUID string `json:"guid,omitempty"`
|
||||
|
||||
// A hierarchical string that uniquely identifies this object's containing run object.
|
||||
@@ -1154,7 +1154,7 @@ type Report struct {
|
||||
// Suppression A suppression that is relevant to a result.
|
||||
type Suppression struct {
|
||||
|
||||
// A stable, unique identifer for the suprression in the form of a GUID.
|
||||
// A stable, unique identifier for the suprression in the form of a GUID.
|
||||
GUID string `json:"guid,omitempty"`
|
||||
|
||||
// A string representing the justification for the suppression.
|
||||
@@ -1278,7 +1278,7 @@ type ToolComponent struct {
|
||||
// A dictionary, each of whose keys is a resource identifier and each of whose values is a multiformatMessageString object, which holds message strings in plain text and (optionally) Markdown format. The strings can include placeholders, which can be used to construct a message in combination with an arbitrary number of additional string arguments.
|
||||
GlobalMessageStrings map[string]*MultiformatMessageString `json:"globalMessageStrings,omitempty"`
|
||||
|
||||
// A unique identifer for the tool component in the form of a GUID.
|
||||
// A unique identifier for the tool component in the form of a GUID.
|
||||
GUID string `json:"guid,omitempty"`
|
||||
|
||||
// The absolute URI at which information about this version of the tool component can be found.
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
package text
|
||||
|
||||
const templateContent = `Results:
|
||||
Results:
|
||||
{{range $filePath,$fileErrors := .Errors}}
|
||||
Golang errors in file: [{{ $filePath }}]:
|
||||
{{range $index, $error := $fileErrors}}
|
||||
@@ -8,7 +6,7 @@ Golang errors in file: [{{ $filePath }}]:
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{ range $index, $issue := .Issues }}
|
||||
[{{ highlight $issue.FileLocation $issue.Severity }}] - {{ $issue.RuleID }} ({{ $issue.Cwe.SprintID }}): {{ $issue.What }} (Confidence: {{ $issue.Confidence}}, Severity: {{ $issue.Severity }})
|
||||
[{{ highlight $issue.FileLocation $issue.Severity $issue.NoSec }}] - {{ $issue.RuleID }}{{ if $issue.NoSec }} ({{- success "NoSec" -}}){{ end }} ({{ $issue.Cwe.SprintID }}): {{ $issue.What }} (Confidence: {{ $issue.Confidence}}, Severity: {{ $issue.Severity }})
|
||||
{{ printCode $issue }}
|
||||
|
||||
{{ end }}
|
||||
@@ -23,4 +21,3 @@ Golang errors in file: [{{ $filePath }}]:
|
||||
{{- danger .Stats.NumFound }}
|
||||
{{- end }}
|
||||
|
||||
`
|
||||
@@ -3,6 +3,9 @@ package text
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
|
||||
// use go embed to import template
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"io"
|
||||
"strconv"
|
||||
@@ -17,6 +20,9 @@ var (
|
||||
errorTheme = color.New(color.FgLightWhite, color.BgRed)
|
||||
warningTheme = color.New(color.FgBlack, color.BgYellow)
|
||||
defaultTheme = color.New(color.FgWhite, color.BgBlack)
|
||||
|
||||
//go:embed template.txt
|
||||
templateContent string
|
||||
)
|
||||
|
||||
// WriteReport write a (colorized) report in text format
|
||||
@@ -45,7 +51,7 @@ func plainTextFuncMap(enableColor bool) template.FuncMap {
|
||||
|
||||
// by default those functions return the given content untouched
|
||||
return template.FuncMap{
|
||||
"highlight": func(t string, s gosec.Score) string {
|
||||
"highlight": func(t string, s gosec.Score, ignored bool) string {
|
||||
return t
|
||||
},
|
||||
"danger": fmt.Sprint,
|
||||
@@ -56,7 +62,10 @@ func plainTextFuncMap(enableColor bool) template.FuncMap {
|
||||
}
|
||||
|
||||
// highlight returns content t colored based on Score
|
||||
func highlight(t string, s gosec.Score) string {
|
||||
func highlight(t string, s gosec.Score, ignored bool) string {
|
||||
if ignored {
|
||||
return defaultTheme.Sprint(t)
|
||||
}
|
||||
switch s {
|
||||
case gosec.High:
|
||||
return errorTheme.Sprint(t)
|
||||
|
||||
@@ -38,10 +38,11 @@ func contains(methods []string, method string) bool {
|
||||
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, method, typ), r.Severity, r.Confidence), nil
|
||||
}
|
||||
if issue := r.checkChild(n, c, deferStmt.Call, deferTyp); issue != nil {
|
||||
return issue, nil
|
||||
}
|
||||
if issue := r.checkFunction(n, c, deferStmt, deferTyp); issue != nil {
|
||||
return issue, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -49,6 +50,42 @@ func (r *badDefer) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (r *badDefer) checkChild(n ast.Node, c *gosec.Context, callExp *ast.CallExpr, deferTyp deferType) *gosec.Issue {
|
||||
if typ, method, err := gosec.GetCallInfo(callExp, c); err == nil {
|
||||
if normalize(typ) == deferTyp.typ && contains(deferTyp.methods, method) {
|
||||
return gosec.NewIssue(c, n, r.ID(), fmt.Sprintf(r.What, method, typ), r.Severity, r.Confidence)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *badDefer) checkFunction(n ast.Node, c *gosec.Context, deferStmt *ast.DeferStmt, deferTyp deferType) *gosec.Issue {
|
||||
if anonFunc, isAnonFunc := deferStmt.Call.Fun.(*ast.FuncLit); isAnonFunc {
|
||||
for _, subElem := range anonFunc.Body.List {
|
||||
if issue := r.checkStmt(n, c, subElem, deferTyp); issue != nil {
|
||||
return issue
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *badDefer) checkStmt(n ast.Node, c *gosec.Context, subElem ast.Stmt, deferTyp deferType) *gosec.Issue {
|
||||
switch stmt := subElem.(type) {
|
||||
case *ast.AssignStmt:
|
||||
for _, rh := range stmt.Rhs {
|
||||
if e, isCallExp := rh.(*ast.CallExpr); isCallExp {
|
||||
return r.checkChild(n, c, e, deferTyp)
|
||||
}
|
||||
}
|
||||
case *ast.IfStmt:
|
||||
if s, is := stmt.Init.(*ast.AssignStmt); is {
|
||||
return r.checkStmt(n, c, s, deferTyp)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewDeferredClosing detects unsafe defer of error returning methods
|
||||
func NewDeferredClosing(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
|
||||
return &badDefer{
|
||||
|
||||
@@ -87,6 +87,7 @@ func NewNoErrorCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
|
||||
whitelist.AddAll("strings.Builder", "Write", "WriteByte", "WriteRune", "WriteString")
|
||||
whitelist.Add("io.PipeWriter", "CloseWithError")
|
||||
whitelist.Add("hash.Hash", "Write")
|
||||
whitelist.Add("os", "Unsetenv")
|
||||
|
||||
if configured, ok := conf["G104"]; ok {
|
||||
if whitelisted, ok := configured.(map[string]interface{}); ok {
|
||||
|
||||
@@ -64,7 +64,7 @@ func (r *filePermissions) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, err
|
||||
|
||||
// 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)
|
||||
mode := getConfiguredMode(conf, "G306", 0o600)
|
||||
return &filePermissions{
|
||||
mode: mode,
|
||||
pkgs: []string{"io/ioutil", "os"},
|
||||
@@ -81,7 +81,7 @@ func NewWritePerms(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
|
||||
// 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)
|
||||
mode := getConfiguredMode(conf, "G302", 0o600)
|
||||
return &filePermissions{
|
||||
mode: mode,
|
||||
pkgs: []string{"os"},
|
||||
@@ -98,7 +98,7 @@ func NewFilePerms(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
|
||||
// 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)
|
||||
mode := getConfiguredMode(conf, "G301", 0o750)
|
||||
return &filePermissions{
|
||||
mode: mode,
|
||||
pkgs: []string{"os"},
|
||||
|
||||
@@ -117,7 +117,7 @@ func (r *credentials) matchEqualityCheck(binaryExpr *ast.BinaryExpr, ctx *gosec.
|
||||
// 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`
|
||||
pattern := `(?i)passwd|pass|password|pwd|secret|token|pw|apiKey|bearer|cred`
|
||||
entropyThreshold := 80.0
|
||||
perCharThreshold := 3.0
|
||||
ignoreEntropy := false
|
||||
|
||||
@@ -122,6 +122,7 @@ func NewReadFile(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
|
||||
rule.clean.Add("path/filepath", "Clean")
|
||||
rule.clean.Add("path/filepath", "Rel")
|
||||
rule.Add("io/ioutil", "ReadFile")
|
||||
rule.Add("os", "ReadFile")
|
||||
rule.Add("os", "Open")
|
||||
rule.Add("os", "OpenFile")
|
||||
return rule, []ast.Node{(*ast.CallExpr)(nil)}
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
"github.com/securego/gosec/v2"
|
||||
"github.com/securego/gosec/v2/rules"
|
||||
"github.com/securego/gosec/v2/testutils"
|
||||
@@ -25,7 +24,7 @@ var _ = Describe("gosec rules", func() {
|
||||
BeforeEach(func() {
|
||||
logger, _ = testutils.NewLogger()
|
||||
config = gosec.NewConfig()
|
||||
analyzer = gosec.NewAnalyzer(config, tests, logger)
|
||||
analyzer = gosec.NewAnalyzer(config, tests, false, logger)
|
||||
runner = func(rule string, samples []testutils.CodeSample) {
|
||||
for n, sample := range samples {
|
||||
analyzer.Reset()
|
||||
|
||||
@@ -48,12 +48,40 @@ func (r *subprocess) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
|
||||
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
|
||||
|
||||
// need to cast and check whether it is for a variable ?
|
||||
_, variable := obj.(*types.Var)
|
||||
|
||||
// .. indeed it is a variable then processing is different than a normal
|
||||
// field assignment
|
||||
if variable {
|
||||
// skip the check when the declaration is not available
|
||||
if ident.Obj == nil {
|
||||
continue
|
||||
}
|
||||
switch ident.Obj.Decl.(type) {
|
||||
case *ast.AssignStmt:
|
||||
_, assignment := ident.Obj.Decl.(*ast.AssignStmt)
|
||||
if variable && assignment {
|
||||
if !gosec.TryResolve(ident, c) {
|
||||
return gosec.NewIssue(c, n, r.ID(), "Subprocess launched with variable", gosec.Medium, gosec.High), nil
|
||||
}
|
||||
}
|
||||
case *ast.Field:
|
||||
_, field := ident.Obj.Decl.(*ast.Field)
|
||||
if variable && field {
|
||||
// check if the variable exist in the scope
|
||||
vv, vvok := obj.(*types.Var)
|
||||
|
||||
if vvok && vv.Parent().Lookup(ident.Name) == nil {
|
||||
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 gosec.NewIssue(c, n, r.ID(), "Subprocess launched with a potential tainted input or cmd arguments", gosec.Medium, gosec.High), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -81,5 +109,7 @@ func NewSubproc(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
|
||||
rule.Add("syscall", "Exec")
|
||||
rule.Add("syscall", "ForkExec")
|
||||
rule.Add("syscall", "StartProcess")
|
||||
rule.Add("golang.org/x/sys/execabs", "Command")
|
||||
rule.Add("golang.org/x/sys/execabs", "CommandContext")
|
||||
return rule, []ast.Node{(*ast.CallExpr)(nil)}
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ func (t *badTempFile) Match(n ast.Node, c *gosec.Context) (gi *gosec.Issue, err
|
||||
func NewBadTempFile(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
|
||||
calls := gosec.NewCallList()
|
||||
calls.Add("io/ioutil", "WriteFile")
|
||||
calls.Add("os", "Create")
|
||||
calls.AddAll("os", "Create", "WriteFile")
|
||||
return &badTempFile{
|
||||
calls: calls,
|
||||
args: regexp.MustCompile(`^/tmp/.*$|^/var/tmp/.*$`),
|
||||
|
||||
26
rules/tls.go
26
rules/tls.go
@@ -20,6 +20,8 @@ import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/types"
|
||||
"strconv"
|
||||
|
||||
"github.com/securego/gosec/v2"
|
||||
)
|
||||
@@ -85,7 +87,29 @@ func (t *insecureConfigTLS) processTLSConfVal(n *ast.KeyValueExpr, c *gosec.Cont
|
||||
}
|
||||
|
||||
case "MinVersion":
|
||||
if ival, ierr := gosec.GetInt(n.Value); ierr == nil {
|
||||
if d, ok := n.Value.(*ast.Ident); ok {
|
||||
if vs, ok := d.Obj.Decl.(*ast.ValueSpec); ok && len(vs.Values) > 0 {
|
||||
if s, ok := vs.Values[0].(*ast.SelectorExpr); ok {
|
||||
x := s.X.(*ast.Ident).Name
|
||||
sel := s.Sel.Name
|
||||
|
||||
for _, imp := range c.Pkg.Imports() {
|
||||
if imp.Name() == x {
|
||||
tObj := imp.Scope().Lookup(sel)
|
||||
if cst, ok := tObj.(*types.Const); ok {
|
||||
// ..got the value check if this can be translated
|
||||
if minVersion, err := strconv.ParseInt(cst.Val().String(), 10, 64); err == nil {
|
||||
t.actualMinVersion = minVersion
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ival, ierr := gosec.GetInt(vs.Values[0]); ierr == nil {
|
||||
t.actualMinVersion = ival
|
||||
}
|
||||
}
|
||||
} else if ival, ierr := gosec.GetInt(n.Value); ierr == nil {
|
||||
t.actualMinVersion = ival
|
||||
} else {
|
||||
if se, ok := n.Value.(*ast.SelectorExpr); ok {
|
||||
|
||||
@@ -53,7 +53,7 @@ func (p *TestPackage) write() error {
|
||||
return nil
|
||||
}
|
||||
for filename, content := range p.Files {
|
||||
if e := ioutil.WriteFile(filename, []byte(content), 0644); e != nil {
|
||||
if e := ioutil.WriteFile(filename, []byte(content), 0o644); e != nil {
|
||||
return e
|
||||
} // #nosec G306
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user