mirror of
https://github.com/redhat-developer/odo.git
synced 2025-10-19 03:06:19 +03:00
Go: Bump github.com/securego/gosec/v2 from 2.17.0 to 2.18.2 (#7167)
Bumps [github.com/securego/gosec/v2](https://github.com/securego/gosec) from 2.17.0 to 2.18.2. - [Release notes](https://github.com/securego/gosec/releases) - [Changelog](https://github.com/securego/gosec/blob/master/.goreleaser.yml) - [Commits](https://github.com/securego/gosec/compare/v2.17.0...v2.18.2) --- updated-dependencies: - dependency-name: github.com/securego/gosec/v2 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
This commit is contained in:
9
vendor/github.com/google/uuid/.travis.yml
generated
vendored
9
vendor/github.com/google/uuid/.travis.yml
generated
vendored
@@ -1,9 +0,0 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.4.3
|
||||
- 1.5.3
|
||||
- tip
|
||||
|
||||
script:
|
||||
- go test -v ./...
|
||||
10
vendor/github.com/google/uuid/CHANGELOG.md
generated
vendored
Normal file
10
vendor/github.com/google/uuid/CHANGELOG.md
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
# Changelog
|
||||
|
||||
## [1.3.1](https://github.com/google/uuid/compare/v1.3.0...v1.3.1) (2023-08-18)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Use .EqualFold() to parse urn prefixed UUIDs ([#118](https://github.com/google/uuid/issues/118)) ([574e687](https://github.com/google/uuid/commit/574e6874943741fb99d41764c705173ada5293f0))
|
||||
|
||||
## Changelog
|
||||
16
vendor/github.com/google/uuid/CONTRIBUTING.md
generated
vendored
16
vendor/github.com/google/uuid/CONTRIBUTING.md
generated
vendored
@@ -2,6 +2,22 @@
|
||||
|
||||
We definitely welcome patches and contribution to this project!
|
||||
|
||||
### Tips
|
||||
|
||||
Commits must be formatted according to the [Conventional Commits Specification](https://www.conventionalcommits.org).
|
||||
|
||||
Always try to include a test case! If it is not possible or not necessary,
|
||||
please explain why in the pull request description.
|
||||
|
||||
### Releasing
|
||||
|
||||
Commits that would precipitate a SemVer change, as desrcibed in the Conventional
|
||||
Commits Specification, will trigger [`release-please`](https://github.com/google-github-actions/release-please-action)
|
||||
to create a release candidate pull request. Once submitted, `release-please`
|
||||
will create a release.
|
||||
|
||||
For tips on how to work with `release-please`, see its documentation.
|
||||
|
||||
### Legal requirements
|
||||
|
||||
In order to protect both you and ourselves, you will need to sign the
|
||||
|
||||
10
vendor/github.com/google/uuid/README.md
generated
vendored
10
vendor/github.com/google/uuid/README.md
generated
vendored
@@ -1,6 +1,6 @@
|
||||
# uuid 
|
||||
# uuid
|
||||
The uuid package generates and inspects UUIDs based on
|
||||
[RFC 4122](http://tools.ietf.org/html/rfc4122)
|
||||
[RFC 4122](https://datatracker.ietf.org/doc/html/rfc4122)
|
||||
and DCE 1.1: Authentication and Security Services.
|
||||
|
||||
This package is based on the github.com/pborman/uuid package (previously named
|
||||
@@ -9,10 +9,12 @@ a UUID is a 16 byte array rather than a byte slice. One loss due to this
|
||||
change is the ability to represent an invalid UUID (vs a NIL UUID).
|
||||
|
||||
###### Install
|
||||
`go get github.com/google/uuid`
|
||||
```sh
|
||||
go get github.com/google/uuid
|
||||
```
|
||||
|
||||
###### Documentation
|
||||
[](http://godoc.org/github.com/google/uuid)
|
||||
[](https://pkg.go.dev/github.com/google/uuid)
|
||||
|
||||
Full `go doc` style documentation for the package can be viewed online without
|
||||
installing this package by using the GoDoc site here:
|
||||
|
||||
2
vendor/github.com/google/uuid/node_js.go
generated
vendored
2
vendor/github.com/google/uuid/node_js.go
generated
vendored
@@ -7,6 +7,6 @@
|
||||
package uuid
|
||||
|
||||
// getHardwareInterface returns nil values for the JS version of the code.
|
||||
// This remvoves the "net" dependency, because it is not used in the browser.
|
||||
// This removes the "net" dependency, because it is not used in the browser.
|
||||
// Using the "net" library inflates the size of the transpiled JS code by 673k bytes.
|
||||
func getHardwareInterface(name string) (string, []byte) { return "", nil }
|
||||
|
||||
10
vendor/github.com/google/uuid/uuid.go
generated
vendored
10
vendor/github.com/google/uuid/uuid.go
generated
vendored
@@ -69,7 +69,7 @@ func Parse(s string) (UUID, error) {
|
||||
|
||||
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||
case 36 + 9:
|
||||
if strings.ToLower(s[:9]) != "urn:uuid:" {
|
||||
if !strings.EqualFold(s[:9], "urn:uuid:") {
|
||||
return uuid, fmt.Errorf("invalid urn prefix: %q", s[:9])
|
||||
}
|
||||
s = s[9:]
|
||||
@@ -101,7 +101,8 @@ func Parse(s string) (UUID, error) {
|
||||
9, 11,
|
||||
14, 16,
|
||||
19, 21,
|
||||
24, 26, 28, 30, 32, 34} {
|
||||
24, 26, 28, 30, 32, 34,
|
||||
} {
|
||||
v, ok := xtob(s[x], s[x+1])
|
||||
if !ok {
|
||||
return uuid, errors.New("invalid UUID format")
|
||||
@@ -117,7 +118,7 @@ func ParseBytes(b []byte) (UUID, error) {
|
||||
switch len(b) {
|
||||
case 36: // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||
case 36 + 9: // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||
if !bytes.Equal(bytes.ToLower(b[:9]), []byte("urn:uuid:")) {
|
||||
if !bytes.EqualFold(b[:9], []byte("urn:uuid:")) {
|
||||
return uuid, fmt.Errorf("invalid urn prefix: %q", b[:9])
|
||||
}
|
||||
b = b[9:]
|
||||
@@ -145,7 +146,8 @@ func ParseBytes(b []byte) (UUID, error) {
|
||||
9, 11,
|
||||
14, 16,
|
||||
19, 21,
|
||||
24, 26, 28, 30, 32, 34} {
|
||||
24, 26, 28, 30, 32, 34,
|
||||
} {
|
||||
v, ok := xtob(b[x], b[x+1])
|
||||
if !ok {
|
||||
return uuid, errors.New("invalid UUID format")
|
||||
|
||||
6
vendor/github.com/onsi/ginkgo/v2/CHANGELOG.md
generated
vendored
6
vendor/github.com/onsi/ginkgo/v2/CHANGELOG.md
generated
vendored
@@ -1,3 +1,9 @@
|
||||
## 2.13.0
|
||||
|
||||
### Features
|
||||
|
||||
Add PreviewSpect() to enable programmatic preview access to the suite report (fixes #1225)
|
||||
|
||||
## 2.12.1
|
||||
|
||||
### Fixes
|
||||
|
||||
94
vendor/github.com/onsi/ginkgo/v2/core_dsl.go
generated
vendored
94
vendor/github.com/onsi/ginkgo/v2/core_dsl.go
generated
vendored
@@ -248,31 +248,13 @@ func RunSpecs(t GinkgoTestingT, description string, args ...interface{}) bool {
|
||||
exitIfErr(types.GinkgoErrors.RerunningSuite())
|
||||
}
|
||||
suiteDidRun = true
|
||||
|
||||
suiteLabels := Labels{}
|
||||
configErrors := []error{}
|
||||
for _, arg := range args {
|
||||
switch arg := arg.(type) {
|
||||
case types.SuiteConfig:
|
||||
suiteConfig = arg
|
||||
case types.ReporterConfig:
|
||||
reporterConfig = arg
|
||||
case Labels:
|
||||
suiteLabels = append(suiteLabels, arg...)
|
||||
default:
|
||||
configErrors = append(configErrors, types.GinkgoErrors.UnknownTypePassedToRunSpecs(arg))
|
||||
}
|
||||
err := global.PushClone()
|
||||
if err != nil {
|
||||
exitIfErr(err)
|
||||
}
|
||||
exitIfErrors(configErrors)
|
||||
defer global.PopClone()
|
||||
|
||||
configErrors = types.VetConfig(flagSet, suiteConfig, reporterConfig)
|
||||
if len(configErrors) > 0 {
|
||||
fmt.Fprintf(formatter.ColorableStdErr, formatter.F("{{red}}Ginkgo detected configuration issues:{{/}}\n"))
|
||||
for _, err := range configErrors {
|
||||
fmt.Fprintf(formatter.ColorableStdErr, err.Error())
|
||||
}
|
||||
os.Exit(1)
|
||||
}
|
||||
suiteLabels := extractSuiteConfiguration(args)
|
||||
|
||||
var reporter reporters.Reporter
|
||||
if suiteConfig.ParallelTotal == 1 {
|
||||
@@ -308,9 +290,8 @@ func RunSpecs(t GinkgoTestingT, description string, args ...interface{}) bool {
|
||||
registerReportAfterSuiteNodeForAutogeneratedReports(reporterConfig)
|
||||
}
|
||||
|
||||
err := global.Suite.BuildTree()
|
||||
err = global.Suite.BuildTree()
|
||||
exitIfErr(err)
|
||||
|
||||
suitePath, err := os.Getwd()
|
||||
exitIfErr(err)
|
||||
suitePath, err = filepath.Abs(suitePath)
|
||||
@@ -335,6 +316,69 @@ func RunSpecs(t GinkgoTestingT, description string, args ...interface{}) bool {
|
||||
return passed
|
||||
}
|
||||
|
||||
func extractSuiteConfiguration(args []interface{}) Labels {
|
||||
suiteLabels := Labels{}
|
||||
configErrors := []error{}
|
||||
for _, arg := range args {
|
||||
switch arg := arg.(type) {
|
||||
case types.SuiteConfig:
|
||||
suiteConfig = arg
|
||||
case types.ReporterConfig:
|
||||
reporterConfig = arg
|
||||
case Labels:
|
||||
suiteLabels = append(suiteLabels, arg...)
|
||||
default:
|
||||
configErrors = append(configErrors, types.GinkgoErrors.UnknownTypePassedToRunSpecs(arg))
|
||||
}
|
||||
}
|
||||
exitIfErrors(configErrors)
|
||||
|
||||
configErrors = types.VetConfig(flagSet, suiteConfig, reporterConfig)
|
||||
if len(configErrors) > 0 {
|
||||
fmt.Fprintf(formatter.ColorableStdErr, formatter.F("{{red}}Ginkgo detected configuration issues:{{/}}\n"))
|
||||
for _, err := range configErrors {
|
||||
fmt.Fprintf(formatter.ColorableStdErr, err.Error())
|
||||
}
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
return suiteLabels
|
||||
}
|
||||
|
||||
/*
|
||||
PreviewSpecs walks the testing tree and produces a report without actually invoking the specs.
|
||||
See http://onsi.github.io/ginkgo/#previewing-specs for more information.
|
||||
*/
|
||||
func PreviewSpecs(description string, args ...any) Report {
|
||||
err := global.PushClone()
|
||||
if err != nil {
|
||||
exitIfErr(err)
|
||||
}
|
||||
defer global.PopClone()
|
||||
|
||||
suiteLabels := extractSuiteConfiguration(args)
|
||||
priorDryRun, priorParallelTotal, priorParallelProcess := suiteConfig.DryRun, suiteConfig.ParallelTotal, suiteConfig.ParallelProcess
|
||||
suiteConfig.DryRun, suiteConfig.ParallelTotal, suiteConfig.ParallelProcess = true, 1, 1
|
||||
defer func() {
|
||||
suiteConfig.DryRun, suiteConfig.ParallelTotal, suiteConfig.ParallelProcess = priorDryRun, priorParallelTotal, priorParallelProcess
|
||||
}()
|
||||
reporter := reporters.NoopReporter{}
|
||||
outputInterceptor = internal.NoopOutputInterceptor{}
|
||||
client = nil
|
||||
writer := GinkgoWriter.(*internal.Writer)
|
||||
|
||||
err = global.Suite.BuildTree()
|
||||
exitIfErr(err)
|
||||
suitePath, err := os.Getwd()
|
||||
exitIfErr(err)
|
||||
suitePath, err = filepath.Abs(suitePath)
|
||||
exitIfErr(err)
|
||||
|
||||
global.Suite.Run(description, suiteLabels, suitePath, global.Failer, reporter, writer, outputInterceptor, interrupt_handler.NewInterruptHandler(client), client, internal.RegisterForProgressSignal, suiteConfig)
|
||||
|
||||
return global.Suite.GetPreviewReport()
|
||||
}
|
||||
|
||||
/*
|
||||
Skip instructs Ginkgo to skip the current spec
|
||||
|
||||
|
||||
11
vendor/github.com/onsi/ginkgo/v2/internal/global/init.go
generated
vendored
11
vendor/github.com/onsi/ginkgo/v2/internal/global/init.go
generated
vendored
@@ -6,6 +6,7 @@ import (
|
||||
|
||||
var Suite *internal.Suite
|
||||
var Failer *internal.Failer
|
||||
var backupSuite *internal.Suite
|
||||
|
||||
func init() {
|
||||
InitializeGlobals()
|
||||
@@ -15,3 +16,13 @@ func InitializeGlobals() {
|
||||
Failer = internal.NewFailer()
|
||||
Suite = internal.NewSuite()
|
||||
}
|
||||
|
||||
func PushClone() error {
|
||||
var err error
|
||||
backupSuite, err = Suite.Clone()
|
||||
return err
|
||||
}
|
||||
|
||||
func PopClone() {
|
||||
Suite = backupSuite
|
||||
}
|
||||
|
||||
6
vendor/github.com/onsi/ginkgo/v2/internal/node.go
generated
vendored
6
vendor/github.com/onsi/ginkgo/v2/internal/node.go
generated
vendored
@@ -597,6 +597,12 @@ func (n Node) IsZero() bool {
|
||||
/* Nodes */
|
||||
type Nodes []Node
|
||||
|
||||
func (n Nodes) Clone() Nodes {
|
||||
nodes := make(Nodes, len(n))
|
||||
copy(nodes, n)
|
||||
return nodes
|
||||
}
|
||||
|
||||
func (n Nodes) CopyAppend(nodes ...Node) Nodes {
|
||||
numN := len(n)
|
||||
out := make(Nodes, numN+len(nodes))
|
||||
|
||||
24
vendor/github.com/onsi/ginkgo/v2/internal/suite.go
generated
vendored
24
vendor/github.com/onsi/ginkgo/v2/internal/suite.go
generated
vendored
@@ -77,6 +77,20 @@ func NewSuite() *Suite {
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *Suite) Clone() (*Suite, error) {
|
||||
if suite.phase != PhaseBuildTopLevel {
|
||||
return nil, fmt.Errorf("cnanot clone suite after tree has been built")
|
||||
}
|
||||
return &Suite{
|
||||
tree: &TreeNode{},
|
||||
phase: PhaseBuildTopLevel,
|
||||
ProgressReporterManager: NewProgressReporterManager(),
|
||||
topLevelContainers: suite.topLevelContainers.Clone(),
|
||||
suiteNodes: suite.suiteNodes.Clone(),
|
||||
selectiveLock: &sync.Mutex{},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (suite *Suite) BuildTree() error {
|
||||
// During PhaseBuildTopLevel, the top level containers are stored in suite.topLevelCotainers and entered
|
||||
// We now enter PhaseBuildTree where these top level containers are entered and added to the spec tree
|
||||
@@ -328,6 +342,16 @@ func (suite *Suite) CurrentSpecReport() types.SpecReport {
|
||||
return report
|
||||
}
|
||||
|
||||
// Only valid in the preview context. In general suite.report only includes
|
||||
// the specs run by _this_ node - it is only at the end of the suite that
|
||||
// the parallel reports are aggregated. However in the preview context we run
|
||||
// in series and
|
||||
func (suite *Suite) GetPreviewReport() types.Report {
|
||||
suite.selectiveLock.Lock()
|
||||
defer suite.selectiveLock.Unlock()
|
||||
return suite.report
|
||||
}
|
||||
|
||||
func (suite *Suite) AddReportEntry(entry ReportEntry) error {
|
||||
if suite.phase != PhaseRun {
|
||||
return types.GinkgoErrors.AddReportEntryNotDuringRunPhase(entry.Location)
|
||||
|
||||
2
vendor/github.com/onsi/ginkgo/v2/types/version.go
generated
vendored
2
vendor/github.com/onsi/ginkgo/v2/types/version.go
generated
vendored
@@ -1,3 +1,3 @@
|
||||
package types
|
||||
|
||||
const VERSION = "2.12.1"
|
||||
const VERSION = "2.13.0"
|
||||
|
||||
24
vendor/github.com/onsi/gomega/CHANGELOG.md
generated
vendored
24
vendor/github.com/onsi/gomega/CHANGELOG.md
generated
vendored
@@ -1,3 +1,27 @@
|
||||
## 1.28.1
|
||||
|
||||
### Maintenance
|
||||
- Bump github.com/onsi/ginkgo/v2 from 2.12.0 to 2.13.0 [635d196]
|
||||
- Bump github.com/google/go-cmp from 0.5.9 to 0.6.0 [14f8859]
|
||||
- Bump golang.org/x/net from 0.14.0 to 0.17.0 [d8a6508]
|
||||
- #703 doc(matchers): HaveEach() doc comment updated [2705bdb]
|
||||
- Minor typos (#699) [375648c]
|
||||
|
||||
## 1.28.0
|
||||
|
||||
### Features
|
||||
- Add VerifyHost handler to ghttp (#698) [0b03b36]
|
||||
|
||||
### Fixes
|
||||
- Read Body for Newer Responses in HaveHTTPBodyMatcher (#686) [18d6673]
|
||||
|
||||
### Maintenance
|
||||
- Bump github.com/onsi/ginkgo/v2 from 2.11.0 to 2.12.0 (#693) [55a33f3]
|
||||
- Typo in matchers.go (#691) [de68e8f]
|
||||
- Bump commonmarker from 0.23.9 to 0.23.10 in /docs (#690) [ab17f5e]
|
||||
- chore: update test matrix for Go 1.21 (#689) [5069017]
|
||||
- Bump golang.org/x/net from 0.12.0 to 0.14.0 (#688) [babe25f]
|
||||
|
||||
## 1.27.10
|
||||
|
||||
### Fixes
|
||||
|
||||
10
vendor/github.com/onsi/gomega/gomega_dsl.go
generated
vendored
10
vendor/github.com/onsi/gomega/gomega_dsl.go
generated
vendored
@@ -22,7 +22,7 @@ import (
|
||||
"github.com/onsi/gomega/types"
|
||||
)
|
||||
|
||||
const GOMEGA_VERSION = "1.27.10"
|
||||
const GOMEGA_VERSION = "1.28.1"
|
||||
|
||||
const nilGomegaPanic = `You are trying to make an assertion, but haven't registered Gomega's fail handler.
|
||||
If you're using Ginkgo then you probably forgot to put your assertion in an It().
|
||||
@@ -242,7 +242,7 @@ func ExpectWithOffset(offset int, actual interface{}, extra ...interface{}) Asse
|
||||
Eventually enables making assertions on asynchronous behavior.
|
||||
|
||||
Eventually checks that an assertion *eventually* passes. Eventually blocks when called and attempts an assertion periodically until it passes or a timeout occurs. Both the timeout and polling interval are configurable as optional arguments.
|
||||
The first optional argument is the timeout (which defaults to 1s), the second is the polling interval (which defaults to 10ms). Both intervals can be specified as time.Duration, parsable duration strings or floats/integers (in which case they are interpreted as seconds). In addition an optional context.Context can be passed in - Eventually will keep trying until either the timeout epxires or the context is cancelled, whichever comes first.
|
||||
The first optional argument is the timeout (which defaults to 1s), the second is the polling interval (which defaults to 10ms). Both intervals can be specified as time.Duration, parsable duration strings or floats/integers (in which case they are interpreted as seconds). In addition an optional context.Context can be passed in - Eventually will keep trying until either the timeout expires or the context is cancelled, whichever comes first.
|
||||
|
||||
Eventually works with any Gomega compatible matcher and supports making assertions against three categories of actual value:
|
||||
|
||||
@@ -313,13 +313,13 @@ It is important to note that the function passed into Eventually is invoked *syn
|
||||
}).Should(BeNumerically(">=", 17))
|
||||
}, SpecTimeout(time.Second))
|
||||
|
||||
you an also use Eventually().WithContext(ctx) to pass in the context. Passed-in contexts play nicely with paseed-in arguments as long as the context appears first. You can rewrite the above example as:
|
||||
you an also use Eventually().WithContext(ctx) to pass in the context. Passed-in contexts play nicely with passed-in arguments as long as the context appears first. You can rewrite the above example as:
|
||||
|
||||
It("fetches the correct count", func(ctx SpecContext) {
|
||||
Eventually(client.FetchCount).WithContext(ctx).WithArguments("/users").Should(BeNumerically(">=", 17))
|
||||
}, SpecTimeout(time.Second))
|
||||
|
||||
Either way the context passd to Eventually is also passed to the underlying funciton. Now, when Ginkgo cancels the context both the FetchCount client and Gomega will be informed and can exit.
|
||||
Either way the context passd to Eventually is also passed to the underlying function. Now, when Ginkgo cancels the context both the FetchCount client and Gomega will be informed and can exit.
|
||||
|
||||
**Category 3: Making assertions _in_ the function passed into Eventually**
|
||||
|
||||
@@ -349,7 +349,7 @@ For example:
|
||||
|
||||
will rerun the function until all assertions pass.
|
||||
|
||||
You can also pass additional arugments to functions that take a Gomega. The only rule is that the Gomega argument must be first. If you also want to pass the context attached to Eventually you must ensure that is the second argument. For example:
|
||||
You can also pass additional arguments to functions that take a Gomega. The only rule is that the Gomega argument must be first. If you also want to pass the context attached to Eventually you must ensure that is the second argument. For example:
|
||||
|
||||
Eventually(func(g Gomega, ctx context.Context, path string, expected ...string){
|
||||
tok, err := client.GetToken(ctx)
|
||||
|
||||
4
vendor/github.com/onsi/gomega/matchers.go
generated
vendored
4
vendor/github.com/onsi/gomega/matchers.go
generated
vendored
@@ -94,7 +94,7 @@ func Succeed() types.GomegaMatcher {
|
||||
//
|
||||
// Expect(err).Should(MatchError("an error")) //asserts that err.Error() == "an error"
|
||||
// Expect(err).Should(MatchError(SomeError)) //asserts that err == SomeError (via reflect.DeepEqual)
|
||||
// Expect(err).Should(MatchError(ContainSubstring("sprocket not found"))) // asserts that edrr.Error() contains substring "sprocket not found"
|
||||
// Expect(err).Should(MatchError(ContainSubstring("sprocket not found"))) // asserts that err.Error() contains substring "sprocket not found"
|
||||
//
|
||||
// It is an error for err to be nil or an object that does not implement the
|
||||
// Error interface
|
||||
@@ -381,7 +381,7 @@ func ContainElements(elements ...interface{}) types.GomegaMatcher {
|
||||
}
|
||||
|
||||
// HaveEach succeeds if actual solely contains elements that match the passed in element.
|
||||
// Please note that if actual is empty, HaveEach always will succeed.
|
||||
// Please note that if actual is empty, HaveEach always will fail.
|
||||
// By default HaveEach() uses Equal() to perform the match, however a
|
||||
// matcher can be passed in instead:
|
||||
//
|
||||
|
||||
9
vendor/github.com/onsi/gomega/matchers/have_http_body_matcher.go
generated
vendored
9
vendor/github.com/onsi/gomega/matchers/have_http_body_matcher.go
generated
vendored
@@ -11,8 +11,9 @@ import (
|
||||
)
|
||||
|
||||
type HaveHTTPBodyMatcher struct {
|
||||
Expected interface{}
|
||||
cachedBody []byte
|
||||
Expected interface{}
|
||||
cachedResponse interface{}
|
||||
cachedBody []byte
|
||||
}
|
||||
|
||||
func (matcher *HaveHTTPBodyMatcher) Match(actual interface{}) (bool, error) {
|
||||
@@ -73,7 +74,7 @@ func (matcher *HaveHTTPBodyMatcher) NegatedFailureMessage(actual interface{}) (m
|
||||
// the Reader is closed and it is not readable again in FailureMessage()
|
||||
// or NegatedFailureMessage()
|
||||
func (matcher *HaveHTTPBodyMatcher) body(actual interface{}) ([]byte, error) {
|
||||
if matcher.cachedBody != nil {
|
||||
if matcher.cachedResponse == actual && matcher.cachedBody != nil {
|
||||
return matcher.cachedBody, nil
|
||||
}
|
||||
|
||||
@@ -91,8 +92,10 @@ func (matcher *HaveHTTPBodyMatcher) body(actual interface{}) ([]byte, error) {
|
||||
|
||||
switch a := actual.(type) {
|
||||
case *http.Response:
|
||||
matcher.cachedResponse = a
|
||||
return body(a)
|
||||
case *httptest.ResponseRecorder:
|
||||
matcher.cachedResponse = a
|
||||
return body(a.Result())
|
||||
default:
|
||||
return nil, fmt.Errorf("HaveHTTPBody matcher expects *http.Response or *httptest.ResponseRecorder. Got:\n%s", format.Object(actual, 1))
|
||||
|
||||
5
vendor/github.com/securego/gosec/v2/.golangci.yml
generated
vendored
5
vendor/github.com/securego/gosec/v2/.golangci.yml
generated
vendored
@@ -9,6 +9,7 @@ linters:
|
||||
- exportloopref
|
||||
- gci
|
||||
- ginkgolinter
|
||||
- gochecknoinits
|
||||
- gofmt
|
||||
- gofumpt
|
||||
- goimports
|
||||
@@ -35,6 +36,10 @@ linters-settings:
|
||||
- standard
|
||||
- default
|
||||
- prefix(github.com/securego)
|
||||
revive:
|
||||
rules:
|
||||
- name: dot-imports
|
||||
disabled: true
|
||||
|
||||
run:
|
||||
timeout: 5m
|
||||
|
||||
12
vendor/github.com/securego/gosec/v2/Makefile
generated
vendored
12
vendor/github.com/securego/gosec/v2/Makefile
generated
vendored
@@ -11,7 +11,6 @@ endif
|
||||
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
|
||||
GOPATH ?= $(shell $(GO) env GOPATH)
|
||||
GOBIN ?= $(GOPATH)/bin
|
||||
GOSEC ?= $(GOBIN)/gosec
|
||||
@@ -25,15 +24,15 @@ default:
|
||||
|
||||
install-test-deps:
|
||||
go install github.com/onsi/ginkgo/v2/ginkgo@latest
|
||||
$(GO_NOMOD) get -u golang.org/x/crypto/ssh
|
||||
$(GO_NOMOD) get -u github.com/lib/pq
|
||||
go install golang.org/x/crypto/...@latest
|
||||
go install github.com/lib/pq/...@latest
|
||||
|
||||
install-govulncheck:
|
||||
@if [ $(GO_MINOR_VERSION) -gt $(GOVULN_MIN_VERSION) ]; then \
|
||||
go install golang.org/x/vuln/cmd/govulncheck@latest; \
|
||||
fi
|
||||
|
||||
test: install-test-deps build fmt vet sec govulncheck
|
||||
test: install-test-deps build-race fmt vet sec govulncheck
|
||||
$(GINKGO) -v --fail-fast
|
||||
|
||||
fmt:
|
||||
@@ -65,6 +64,9 @@ test-coverage: install-test-deps
|
||||
build:
|
||||
go build -o $(BIN) ./cmd/gosec/
|
||||
|
||||
build-race:
|
||||
go build -race -o $(BIN) ./cmd/gosec/
|
||||
|
||||
clean:
|
||||
rm -rf build vendor dist coverage.txt
|
||||
rm -f release image $(BIN)
|
||||
@@ -89,5 +91,5 @@ image-push: image
|
||||
|
||||
tlsconfig:
|
||||
go generate ./...
|
||||
|
||||
|
||||
.PHONY: test build clean release image image-push tlsconfig
|
||||
|
||||
37
vendor/github.com/securego/gosec/v2/README.md
generated
vendored
37
vendor/github.com/securego/gosec/v2/README.md
generated
vendored
@@ -1,7 +1,7 @@
|
||||
|
||||
# gosec - Golang Security Checker
|
||||
|
||||
Inspects source code for security problems by scanning the Go AST.
|
||||
Inspects source code for security problems by scanning the Go AST and SSA code representation.
|
||||
|
||||
<img src="https://securego.io/img/gosec.png" width="320">
|
||||
|
||||
@@ -157,6 +157,7 @@ directory you can supply `./...` as the input argument.
|
||||
- G304: File path provided as taint input
|
||||
- G305: File traversal when extracting zip/tar archive
|
||||
- G306: Poor file permissions used when writing to a new file
|
||||
- G307: Poor file permissions used when creating a file with os.Create
|
||||
- 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
|
||||
@@ -273,31 +274,33 @@ 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,
|
||||
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 comment that starts with `#nosec`.
|
||||
|
||||
The `#nosec` comment should have the format `#nosec [RuleList] [-- Justification]`.
|
||||
|
||||
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.
|
||||
The `#nosec` comment needs to be placed on the line where the warning is reported.
|
||||
|
||||
```go
|
||||
func main() {
|
||||
tr := &http.Transport{
|
||||
TLSClientConfig: &tls.Config{
|
||||
InsecureSkipVerify: true, // #nosec G402
|
||||
},
|
||||
}
|
||||
|
||||
import "md5" //#nosec
|
||||
|
||||
|
||||
func main(){
|
||||
|
||||
/* #nosec */
|
||||
if x > y {
|
||||
h := md5.New() // this will also be ignored
|
||||
}
|
||||
|
||||
client := &http.Client{Transport: tr}
|
||||
_, err := client.Get("https://golang.org/")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
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
|
||||
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`
|
||||
|
||||
You could put the description or justification text for the annotation. The
|
||||
|
||||
1
vendor/github.com/securego/gosec/v2/USERS.md
generated
vendored
1
vendor/github.com/securego/gosec/v2/USERS.md
generated
vendored
@@ -15,6 +15,7 @@ This is a list of gosec's users. Please send a pull request with your organisati
|
||||
9. [PingCAP/tidb](https://github.com/pingcap/tidb)
|
||||
10. [Checkmarx](https://www.checkmarx.com/)
|
||||
11. [SeatGeek](https://www.seatgeek.com/)
|
||||
12. [reMarkable](https://remarkable.com)
|
||||
|
||||
## Projects
|
||||
|
||||
|
||||
2
vendor/github.com/securego/gosec/v2/action.yml
generated
vendored
2
vendor/github.com/securego/gosec/v2/action.yml
generated
vendored
@@ -10,7 +10,7 @@ inputs:
|
||||
|
||||
runs:
|
||||
using: 'docker'
|
||||
image: 'docker://securego/gosec:2.16.0'
|
||||
image: 'docker://securego/gosec:2.18.1'
|
||||
args:
|
||||
- ${{ inputs.args }}
|
||||
|
||||
|
||||
224
vendor/github.com/securego/gosec/v2/analyzer.go
generated
vendored
224
vendor/github.com/securego/gosec/v2/analyzer.go
generated
vendored
@@ -57,6 +57,80 @@ const aliasOfAllRules = "*"
|
||||
|
||||
var generatedCodePattern = regexp.MustCompile(`^// Code generated .* DO NOT EDIT\.$`)
|
||||
|
||||
type ignore struct {
|
||||
start int
|
||||
end int
|
||||
suppressions map[string][]issue.SuppressionInfo
|
||||
}
|
||||
|
||||
type ignores map[string][]ignore
|
||||
|
||||
func newIgnores() ignores {
|
||||
return make(map[string][]ignore)
|
||||
}
|
||||
|
||||
func (i ignores) parseLine(line string) (int, int) {
|
||||
parts := strings.Split(line, "-")
|
||||
start, err := strconv.Atoi(parts[0])
|
||||
if err != nil {
|
||||
start = 0
|
||||
}
|
||||
end := start
|
||||
if len(parts) > 1 {
|
||||
if e, err := strconv.Atoi(parts[1]); err == nil {
|
||||
end = e
|
||||
}
|
||||
}
|
||||
return start, end
|
||||
}
|
||||
|
||||
func (i ignores) add(file string, line string, suppressions map[string]issue.SuppressionInfo) {
|
||||
is := []ignore{}
|
||||
if _, ok := i[file]; ok {
|
||||
is = i[file]
|
||||
}
|
||||
found := false
|
||||
start, end := i.parseLine(line)
|
||||
for _, ig := range is {
|
||||
if ig.start <= start && ig.end >= end {
|
||||
found = true
|
||||
for r, s := range suppressions {
|
||||
ss, ok := ig.suppressions[r]
|
||||
if !ok {
|
||||
ss = []issue.SuppressionInfo{}
|
||||
}
|
||||
ss = append(ss, s)
|
||||
ig.suppressions[r] = ss
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
ig := ignore{
|
||||
start: start,
|
||||
end: end,
|
||||
suppressions: map[string][]issue.SuppressionInfo{},
|
||||
}
|
||||
for r, s := range suppressions {
|
||||
ig.suppressions[r] = []issue.SuppressionInfo{s}
|
||||
}
|
||||
is = append(is, ig)
|
||||
}
|
||||
i[file] = is
|
||||
}
|
||||
|
||||
func (i ignores) get(file string, line string) map[string][]issue.SuppressionInfo {
|
||||
start, end := i.parseLine(line)
|
||||
if is, ok := i[file]; ok {
|
||||
for _, i := range is {
|
||||
if i.start <= start && i.end >= end {
|
||||
return i.suppressions
|
||||
}
|
||||
}
|
||||
}
|
||||
return map[string][]issue.SuppressionInfo{}
|
||||
}
|
||||
|
||||
// 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 with the encountered AST node.
|
||||
@@ -69,7 +143,7 @@ type Context struct {
|
||||
Root *ast.File
|
||||
Imports *ImportTracker
|
||||
Config Config
|
||||
Ignores []map[string][]issue.SuppressionInfo
|
||||
Ignores ignores
|
||||
PassedValues map[string]interface{}
|
||||
}
|
||||
|
||||
@@ -110,6 +184,7 @@ type Analyzer struct {
|
||||
trackSuppressions bool
|
||||
concurrency int
|
||||
analyzerList []*analysis.Analyzer
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
// NewAnalyzer builds a new analyzer.
|
||||
@@ -231,9 +306,7 @@ func (gosec *Analyzer) Process(buildTags []string, packagePaths ...string) error
|
||||
return fmt.Errorf("parsing errors in pkg %q: %w", pkg.Name, err)
|
||||
}
|
||||
gosec.CheckRules(pkg)
|
||||
if on, err := gosec.config.IsGlobalEnabled(SSA); err == nil && on {
|
||||
gosec.CheckAnalyzers(pkg)
|
||||
}
|
||||
gosec.CheckAnalyzers(pkg)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -252,7 +325,9 @@ func (gosec *Analyzer) load(pkgPath string, conf *packages.Config) ([]*packages.
|
||||
// step 1/3 create build context.
|
||||
buildD := build.Default
|
||||
// step 2/3: add build tags to get env dependent files into basePackage.
|
||||
gosec.mu.Lock()
|
||||
buildD.BuildTags = conf.BuildFlags
|
||||
gosec.mu.Unlock()
|
||||
basePackage, err := buildD.ImportDir(pkgPath, build.ImportComment)
|
||||
if err != nil {
|
||||
return []*packages.Package{}, fmt.Errorf("importing dir %q: %w", pkgPath, err)
|
||||
@@ -276,7 +351,9 @@ func (gosec *Analyzer) load(pkgPath string, conf *packages.Config) ([]*packages.
|
||||
}
|
||||
|
||||
// step 3/3 remove build tags from conf to proceed build correctly.
|
||||
gosec.mu.Lock()
|
||||
conf.BuildFlags = nil
|
||||
defer gosec.mu.Unlock()
|
||||
pkgs, err := packages.Load(conf, packageFiles...)
|
||||
if err != nil {
|
||||
return []*packages.Package{}, fmt.Errorf("loading files from package %q: %w", pkgPath, err)
|
||||
@@ -284,7 +361,7 @@ func (gosec *Analyzer) load(pkgPath string, conf *packages.Config) ([]*packages.
|
||||
return pkgs, nil
|
||||
}
|
||||
|
||||
// CheckRules runs analysis on the given package
|
||||
// CheckRules runs analysis on the given package.
|
||||
func (gosec *Analyzer) CheckRules(pkg *packages.Package) {
|
||||
gosec.logger.Println("Checking package:", pkg.Name)
|
||||
for _, file := range pkg.Syntax {
|
||||
@@ -314,37 +391,22 @@ func (gosec *Analyzer) CheckRules(pkg *packages.Package) {
|
||||
gosec.context.PkgFiles = pkg.Syntax
|
||||
gosec.context.Imports = NewImportTracker()
|
||||
gosec.context.PassedValues = make(map[string]interface{})
|
||||
gosec.context.Ignores = newIgnores()
|
||||
gosec.updateIgnores()
|
||||
ast.Walk(gosec, file)
|
||||
gosec.stats.NumFiles++
|
||||
gosec.stats.NumLines += pkg.Fset.File(file.Pos()).LineCount()
|
||||
}
|
||||
}
|
||||
|
||||
// CheckAnalyzers runs analyzers on a given package
|
||||
// CheckAnalyzers runs analyzers on a given package.
|
||||
func (gosec *Analyzer) CheckAnalyzers(pkg *packages.Package) {
|
||||
ssaPass := &analysis.Pass{
|
||||
Analyzer: buildssa.Analyzer,
|
||||
Fset: pkg.Fset,
|
||||
Files: pkg.Syntax,
|
||||
OtherFiles: pkg.OtherFiles,
|
||||
IgnoredFiles: pkg.IgnoredFiles,
|
||||
Pkg: pkg.Types,
|
||||
TypesInfo: pkg.TypesInfo,
|
||||
TypesSizes: pkg.TypesSizes,
|
||||
ResultOf: nil,
|
||||
Report: nil,
|
||||
ImportObjectFact: nil,
|
||||
ExportObjectFact: nil,
|
||||
ImportPackageFact: nil,
|
||||
ExportPackageFact: nil,
|
||||
AllObjectFacts: nil,
|
||||
AllPackageFacts: nil,
|
||||
}
|
||||
ssaResult, err := ssaPass.Analyzer.Run(ssaPass)
|
||||
if err != nil {
|
||||
gosec.logger.Printf("Error running SSA analyser on package %q: %s", pkg.Name, err)
|
||||
ssaResult, err := gosec.buildSSA(pkg)
|
||||
if err != nil || ssaResult == nil {
|
||||
gosec.logger.Printf("Error building the SSA representation of the package %q: %s", pkg.Name, err)
|
||||
return
|
||||
}
|
||||
|
||||
resultMap := map[*analysis.Analyzer]interface{}{
|
||||
buildssa.Analyzer: &analyzers.SSAAnalyzerResult{
|
||||
Config: gosec.Config(),
|
||||
@@ -377,13 +439,44 @@ func (gosec *Analyzer) CheckAnalyzers(pkg *packages.Package) {
|
||||
continue
|
||||
}
|
||||
if result != nil {
|
||||
if aissue, ok := result.(*issue.Issue); ok {
|
||||
gosec.updateIssues(aissue, false, []issue.SuppressionInfo{})
|
||||
if passIssues, ok := result.([]*issue.Issue); ok {
|
||||
for _, iss := range passIssues {
|
||||
gosec.updateIssues(iss)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// buildSSA runs the SSA pass which builds the SSA representation of the package. It handles gracefully any panic.
|
||||
func (gosec *Analyzer) buildSSA(pkg *packages.Package) (interface{}, error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
gosec.logger.Printf("Panic when running SSA analyser on package: %s", pkg.Name)
|
||||
}
|
||||
}()
|
||||
ssaPass := &analysis.Pass{
|
||||
Analyzer: buildssa.Analyzer,
|
||||
Fset: pkg.Fset,
|
||||
Files: pkg.Syntax,
|
||||
OtherFiles: pkg.OtherFiles,
|
||||
IgnoredFiles: pkg.IgnoredFiles,
|
||||
Pkg: pkg.Types,
|
||||
TypesInfo: pkg.TypesInfo,
|
||||
TypesSizes: pkg.TypesSizes,
|
||||
ResultOf: nil,
|
||||
Report: nil,
|
||||
ImportObjectFact: nil,
|
||||
ExportObjectFact: nil,
|
||||
ImportPackageFact: nil,
|
||||
ExportPackageFact: nil,
|
||||
AllObjectFacts: nil,
|
||||
AllPackageFacts: nil,
|
||||
}
|
||||
|
||||
return ssaPass.Analyzer.Run(ssaPass)
|
||||
}
|
||||
|
||||
func isGeneratedFile(file *ast.File) bool {
|
||||
for _, comment := range file.Comments {
|
||||
for _, row := range comment.List {
|
||||
@@ -449,7 +542,12 @@ func (gosec *Analyzer) ignore(n ast.Node) map[string]issue.SuppressionInfo {
|
||||
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 := NoSecTag(string(Nosec))
|
||||
noSecDefaultTag, err := gosec.config.GetGlobal(Nosec)
|
||||
if err != nil {
|
||||
noSecDefaultTag = NoSecTag(string(Nosec))
|
||||
} else {
|
||||
noSecDefaultTag = NoSecTag(noSecDefaultTag)
|
||||
}
|
||||
noSecAlternativeTag, err := gosec.config.GetGlobal(NoSecAlternative)
|
||||
if err != nil {
|
||||
noSecAlternativeTag = noSecDefaultTag
|
||||
@@ -509,11 +607,6 @@ func (gosec *Analyzer) ignore(n ast.Node) map[string]issue.SuppressionInfo {
|
||||
// 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 {
|
||||
ignores, ok := gosec.updateIgnoredRules(n)
|
||||
if !ok {
|
||||
return gosec
|
||||
}
|
||||
|
||||
// Using ast.File instead of ast.ImportSpec, so that we can track all imports at once.
|
||||
switch i := n.(type) {
|
||||
case *ast.File:
|
||||
@@ -521,56 +614,48 @@ func (gosec *Analyzer) Visit(n ast.Node) ast.Visitor {
|
||||
}
|
||||
|
||||
for _, rule := range gosec.ruleset.RegisteredFor(n) {
|
||||
suppressions, ignored := gosec.updateSuppressions(rule.ID(), ignores)
|
||||
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)
|
||||
}
|
||||
gosec.updateIssues(issue, ignored, suppressions)
|
||||
gosec.updateIssues(issue)
|
||||
}
|
||||
return gosec
|
||||
}
|
||||
|
||||
func (gosec *Analyzer) updateIgnoredRules(n ast.Node) (map[string][]issue.SuppressionInfo, bool) {
|
||||
if n == nil {
|
||||
if len(gosec.context.Ignores) > 0 {
|
||||
gosec.context.Ignores = gosec.context.Ignores[1:]
|
||||
}
|
||||
return nil, false
|
||||
func (gosec *Analyzer) updateIgnores() {
|
||||
for n := range gosec.context.Comments {
|
||||
gosec.updateIgnoredRulesForNode(n)
|
||||
}
|
||||
// Get any new rule exclusions.
|
||||
ignoredRules := gosec.ignore(n)
|
||||
|
||||
// Now create the union of exclusions.
|
||||
ignores := map[string][]issue.SuppressionInfo{}
|
||||
if len(gosec.context.Ignores) > 0 {
|
||||
for k, v := range gosec.context.Ignores[0] {
|
||||
ignores[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
for ruleID, suppression := range ignoredRules {
|
||||
ignores[ruleID] = append(ignores[ruleID], suppression)
|
||||
}
|
||||
|
||||
// Push the new set onto the stack.
|
||||
gosec.context.Ignores = append([]map[string][]issue.SuppressionInfo{ignores}, gosec.context.Ignores...)
|
||||
|
||||
return ignores, true
|
||||
}
|
||||
|
||||
func (gosec *Analyzer) updateSuppressions(id string, ignores map[string][]issue.SuppressionInfo) ([]issue.SuppressionInfo, bool) {
|
||||
// Check if all rules are ignored.
|
||||
generalSuppressions, generalIgnored := ignores[aliasOfAllRules]
|
||||
// Check if the specific rule is ignored
|
||||
ruleSuppressions, ruleIgnored := ignores[id]
|
||||
func (gosec *Analyzer) updateIgnoredRulesForNode(n ast.Node) {
|
||||
ignoredRules := gosec.ignore(n)
|
||||
if len(ignoredRules) > 0 {
|
||||
if gosec.context.Ignores == nil {
|
||||
gosec.context.Ignores = newIgnores()
|
||||
}
|
||||
line := issue.GetLine(gosec.context.FileSet.File(n.Pos()), n)
|
||||
gosec.context.Ignores.add(
|
||||
gosec.context.FileSet.File(n.Pos()).Name(),
|
||||
line,
|
||||
ignoredRules,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func (gosec *Analyzer) getSuppressionsAtLineInFile(file string, line string, id string) ([]issue.SuppressionInfo, bool) {
|
||||
ignoredRules := gosec.context.Ignores.get(file, line)
|
||||
|
||||
// Check if the rule was specifically suppressed at this location.
|
||||
generalSuppressions, generalIgnored := ignoredRules[aliasOfAllRules]
|
||||
ruleSuppressions, ruleIgnored := ignoredRules[id]
|
||||
ignored := generalIgnored || ruleIgnored
|
||||
suppressions := append(generalSuppressions, ruleSuppressions...)
|
||||
|
||||
// Track external suppressions.
|
||||
// Track external suppressions of this rule.
|
||||
if gosec.ruleset.IsRuleSuppressed(id) {
|
||||
ignored = true
|
||||
suppressions = append(suppressions, issue.SuppressionInfo{
|
||||
@@ -581,8 +666,9 @@ func (gosec *Analyzer) updateSuppressions(id string, ignores map[string][]issue.
|
||||
return suppressions, ignored
|
||||
}
|
||||
|
||||
func (gosec *Analyzer) updateIssues(issue *issue.Issue, ignored bool, suppressions []issue.SuppressionInfo) {
|
||||
func (gosec *Analyzer) updateIssues(issue *issue.Issue) {
|
||||
if issue != nil {
|
||||
suppressions, ignored := gosec.getSuppressionsAtLineInFile(issue.File, issue.Line, issue.RuleID)
|
||||
if gosec.showIgnored {
|
||||
issue.NoSec = ignored
|
||||
}
|
||||
|
||||
386
vendor/github.com/securego/gosec/v2/analyzers/slice_bounds.go
generated
vendored
Normal file
386
vendor/github.com/securego/gosec/v2/analyzers/slice_bounds.go
generated
vendored
Normal file
@@ -0,0 +1,386 @@
|
||||
// (c) Copyright gosec's authors
|
||||
//
|
||||
// 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 analyzers
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"go/token"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/tools/go/analysis"
|
||||
"golang.org/x/tools/go/analysis/passes/buildssa"
|
||||
"golang.org/x/tools/go/ssa"
|
||||
|
||||
"github.com/securego/gosec/v2/issue"
|
||||
)
|
||||
|
||||
type bound int
|
||||
|
||||
const (
|
||||
lowerUnbounded bound = iota
|
||||
upperUnbounded
|
||||
unbounded
|
||||
upperBounded
|
||||
)
|
||||
|
||||
const maxDepth = 20
|
||||
|
||||
func newSliceBoundsAnalyzer(id string, description string) *analysis.Analyzer {
|
||||
return &analysis.Analyzer{
|
||||
Name: id,
|
||||
Doc: description,
|
||||
Run: runSliceBounds,
|
||||
Requires: []*analysis.Analyzer{buildssa.Analyzer},
|
||||
}
|
||||
}
|
||||
|
||||
func runSliceBounds(pass *analysis.Pass) (interface{}, error) {
|
||||
ssaResult, err := getSSAResult(pass)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
issues := map[ssa.Instruction]*issue.Issue{}
|
||||
ifs := map[ssa.If]*ssa.BinOp{}
|
||||
for _, mcall := range ssaResult.SSA.SrcFuncs {
|
||||
for _, block := range mcall.DomPreorder() {
|
||||
for _, instr := range block.Instrs {
|
||||
switch instr := instr.(type) {
|
||||
case *ssa.Alloc:
|
||||
sliceCap, err := extractSliceCapFromAlloc(instr.String())
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
allocRefs := instr.Referrers()
|
||||
if allocRefs == nil {
|
||||
break
|
||||
}
|
||||
for _, instr := range *allocRefs {
|
||||
if slice, ok := instr.(*ssa.Slice); ok {
|
||||
if _, ok := slice.X.(*ssa.Alloc); ok {
|
||||
if slice.Parent() != nil {
|
||||
l, h := extractSliceBounds(slice)
|
||||
newCap := computeSliceNewCap(l, h, sliceCap)
|
||||
violations := []ssa.Instruction{}
|
||||
trackSliceBounds(0, newCap, slice, &violations, ifs)
|
||||
for _, s := range violations {
|
||||
switch s := s.(type) {
|
||||
case *ssa.Slice:
|
||||
issue := newIssue(
|
||||
pass.Analyzer.Name,
|
||||
"slice bounds out of range",
|
||||
pass.Fset,
|
||||
s.Pos(),
|
||||
issue.Low,
|
||||
issue.High)
|
||||
issues[s] = issue
|
||||
case *ssa.IndexAddr:
|
||||
issue := newIssue(
|
||||
pass.Analyzer.Name,
|
||||
"slice index out of range",
|
||||
pass.Fset,
|
||||
s.Pos(),
|
||||
issue.Low,
|
||||
issue.High)
|
||||
issues[s] = issue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for ifref, binop := range ifs {
|
||||
bound, value, err := extractBinOpBound(binop)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
for i, block := range ifref.Block().Succs {
|
||||
if i == 1 {
|
||||
bound = invBound(bound)
|
||||
}
|
||||
for _, instr := range block.Instrs {
|
||||
if _, ok := issues[instr]; ok {
|
||||
switch bound {
|
||||
case lowerUnbounded:
|
||||
break
|
||||
case upperUnbounded, unbounded:
|
||||
delete(issues, instr)
|
||||
case upperBounded:
|
||||
switch tinstr := instr.(type) {
|
||||
case *ssa.Slice:
|
||||
lower, upper := extractSliceBounds(tinstr)
|
||||
if isSliceInsideBounds(0, value, lower, upper) {
|
||||
delete(issues, instr)
|
||||
}
|
||||
case *ssa.IndexAddr:
|
||||
indexValue, err := extractIntValue(tinstr.Index.String())
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
if isSliceIndexInsideBounds(0, value, indexValue) {
|
||||
delete(issues, instr)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foundIssues := []*issue.Issue{}
|
||||
for _, issue := range issues {
|
||||
foundIssues = append(foundIssues, issue)
|
||||
}
|
||||
if len(foundIssues) > 0 {
|
||||
return foundIssues, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func trackSliceBounds(depth int, sliceCap int, slice ssa.Node, violations *[]ssa.Instruction, ifs map[ssa.If]*ssa.BinOp) {
|
||||
if depth == maxDepth {
|
||||
return
|
||||
}
|
||||
depth++
|
||||
if violations == nil {
|
||||
violations = &[]ssa.Instruction{}
|
||||
}
|
||||
referrers := slice.Referrers()
|
||||
if referrers != nil {
|
||||
for _, refinstr := range *referrers {
|
||||
switch refinstr := refinstr.(type) {
|
||||
case *ssa.Slice:
|
||||
checkAllSlicesBounds(depth, sliceCap, refinstr, violations, ifs)
|
||||
switch refinstr.X.(type) {
|
||||
case *ssa.Alloc, *ssa.Parameter:
|
||||
l, h := extractSliceBounds(refinstr)
|
||||
newCap := computeSliceNewCap(l, h, sliceCap)
|
||||
trackSliceBounds(depth, newCap, refinstr, violations, ifs)
|
||||
}
|
||||
case *ssa.IndexAddr:
|
||||
indexValue, err := extractIntValue(refinstr.Index.String())
|
||||
if err == nil && !isSliceIndexInsideBounds(0, sliceCap, indexValue) {
|
||||
*violations = append(*violations, refinstr)
|
||||
}
|
||||
case *ssa.Call:
|
||||
if ifref, cond := extractSliceIfLenCondition(refinstr); ifref != nil && cond != nil {
|
||||
ifs[*ifref] = cond
|
||||
} else {
|
||||
parPos := -1
|
||||
for pos, arg := range refinstr.Call.Args {
|
||||
if a, ok := arg.(*ssa.Slice); ok && a == slice {
|
||||
parPos = pos
|
||||
}
|
||||
}
|
||||
if fn, ok := refinstr.Call.Value.(*ssa.Function); ok {
|
||||
if len(fn.Params) > parPos && parPos > -1 {
|
||||
param := fn.Params[parPos]
|
||||
trackSliceBounds(depth, sliceCap, param, violations, ifs)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func checkAllSlicesBounds(depth int, sliceCap int, slice *ssa.Slice, violations *[]ssa.Instruction, ifs map[ssa.If]*ssa.BinOp) {
|
||||
if depth == maxDepth {
|
||||
return
|
||||
}
|
||||
depth++
|
||||
if violations == nil {
|
||||
violations = &[]ssa.Instruction{}
|
||||
}
|
||||
sliceLow, sliceHigh := extractSliceBounds(slice)
|
||||
if !isSliceInsideBounds(0, sliceCap, sliceLow, sliceHigh) {
|
||||
*violations = append(*violations, slice)
|
||||
}
|
||||
switch slice.X.(type) {
|
||||
case *ssa.Alloc, *ssa.Parameter, *ssa.Slice:
|
||||
l, h := extractSliceBounds(slice)
|
||||
newCap := computeSliceNewCap(l, h, sliceCap)
|
||||
trackSliceBounds(depth, newCap, slice, violations, ifs)
|
||||
}
|
||||
|
||||
references := slice.Referrers()
|
||||
if references == nil {
|
||||
return
|
||||
}
|
||||
for _, ref := range *references {
|
||||
switch s := ref.(type) {
|
||||
case *ssa.Slice:
|
||||
checkAllSlicesBounds(depth, sliceCap, s, violations, ifs)
|
||||
switch s.X.(type) {
|
||||
case *ssa.Alloc, *ssa.Parameter:
|
||||
l, h := extractSliceBounds(s)
|
||||
newCap := computeSliceNewCap(l, h, sliceCap)
|
||||
trackSliceBounds(depth, newCap, s, violations, ifs)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func extractSliceIfLenCondition(call *ssa.Call) (*ssa.If, *ssa.BinOp) {
|
||||
if builtInLen, ok := call.Call.Value.(*ssa.Builtin); ok {
|
||||
if builtInLen.Name() == "len" {
|
||||
refs := call.Referrers()
|
||||
if refs != nil {
|
||||
for _, ref := range *refs {
|
||||
if binop, ok := ref.(*ssa.BinOp); ok {
|
||||
binoprefs := binop.Referrers()
|
||||
for _, ref := range *binoprefs {
|
||||
if ifref, ok := ref.(*ssa.If); ok {
|
||||
return ifref, binop
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func computeSliceNewCap(l, h, oldCap int) int {
|
||||
if l == 0 && h == 0 {
|
||||
return oldCap
|
||||
}
|
||||
if l > 0 && h == 0 {
|
||||
return oldCap - l
|
||||
}
|
||||
if l == 0 && h > 0 {
|
||||
return h
|
||||
}
|
||||
return h - l
|
||||
}
|
||||
|
||||
func invBound(bound bound) bound {
|
||||
switch bound {
|
||||
case lowerUnbounded:
|
||||
return upperUnbounded
|
||||
case upperUnbounded:
|
||||
return lowerUnbounded
|
||||
case upperBounded:
|
||||
return unbounded
|
||||
case unbounded:
|
||||
return upperBounded
|
||||
default:
|
||||
return unbounded
|
||||
}
|
||||
}
|
||||
|
||||
func extractBinOpBound(binop *ssa.BinOp) (bound, int, error) {
|
||||
if binop.X != nil {
|
||||
if x, ok := binop.X.(*ssa.Const); ok {
|
||||
value, err := strconv.Atoi(x.Value.String())
|
||||
if err != nil {
|
||||
return lowerUnbounded, value, err
|
||||
}
|
||||
switch binop.Op {
|
||||
case token.LSS, token.LEQ:
|
||||
return upperUnbounded, value, nil
|
||||
case token.GTR, token.GEQ:
|
||||
return lowerUnbounded, value, nil
|
||||
case token.EQL:
|
||||
return upperBounded, value, nil
|
||||
case token.NEQ:
|
||||
return unbounded, value, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
if binop.Y != nil {
|
||||
if y, ok := binop.Y.(*ssa.Const); ok {
|
||||
value, err := strconv.Atoi(y.Value.String())
|
||||
if err != nil {
|
||||
return lowerUnbounded, value, err
|
||||
}
|
||||
switch binop.Op {
|
||||
case token.LSS, token.LEQ:
|
||||
return lowerUnbounded, value, nil
|
||||
case token.GTR, token.GEQ:
|
||||
return upperUnbounded, value, nil
|
||||
case token.EQL:
|
||||
return upperBounded, value, nil
|
||||
case token.NEQ:
|
||||
return unbounded, value, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return lowerUnbounded, 0, fmt.Errorf("unable to extract constant from binop")
|
||||
}
|
||||
|
||||
func isSliceIndexInsideBounds(l, h int, index int) bool {
|
||||
return (l <= index && index < h)
|
||||
}
|
||||
|
||||
func isSliceInsideBounds(l, h int, cl, ch int) bool {
|
||||
return (l <= cl && h >= ch) && (l <= ch && h >= cl)
|
||||
}
|
||||
|
||||
func extractSliceBounds(slice *ssa.Slice) (int, int) {
|
||||
var low int
|
||||
if slice.Low != nil {
|
||||
l, err := extractIntValue(slice.Low.String())
|
||||
if err == nil {
|
||||
low = l
|
||||
}
|
||||
}
|
||||
var high int
|
||||
if slice.High != nil {
|
||||
h, err := extractIntValue(slice.High.String())
|
||||
if err == nil {
|
||||
high = h
|
||||
}
|
||||
}
|
||||
return low, high
|
||||
}
|
||||
|
||||
func extractIntValue(value string) (int, error) {
|
||||
parts := strings.Split(value, ":")
|
||||
if len(parts) != 2 {
|
||||
return 0, fmt.Errorf("invalid value: %s", value)
|
||||
}
|
||||
if parts[1] != "int" {
|
||||
return 0, fmt.Errorf("invalid value: %s", value)
|
||||
}
|
||||
return strconv.Atoi(parts[0])
|
||||
}
|
||||
|
||||
func extractSliceCapFromAlloc(instr string) (int, error) {
|
||||
re := regexp.MustCompile(`new \[(\d+)\]*`)
|
||||
var sliceCap int
|
||||
matches := re.FindAllStringSubmatch(instr, -1)
|
||||
if matches == nil {
|
||||
return sliceCap, errors.New("no slice cap found")
|
||||
}
|
||||
|
||||
if len(matches) > 0 {
|
||||
m := matches[0]
|
||||
if len(m) > 1 {
|
||||
return strconv.Atoi(m[1])
|
||||
}
|
||||
}
|
||||
|
||||
return 0, errors.New("no slice cap found")
|
||||
}
|
||||
57
vendor/github.com/securego/gosec/v2/analyzers/ssrf.go
generated
vendored
57
vendor/github.com/securego/gosec/v2/analyzers/ssrf.go
generated
vendored
@@ -1,57 +0,0 @@
|
||||
// (c) Copyright gosec's authors
|
||||
//
|
||||
// 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 analyzers
|
||||
|
||||
import (
|
||||
"golang.org/x/tools/go/analysis"
|
||||
"golang.org/x/tools/go/analysis/passes/buildssa"
|
||||
"golang.org/x/tools/go/ssa"
|
||||
|
||||
"github.com/securego/gosec/v2/issue"
|
||||
)
|
||||
|
||||
func newSSRFAnalyzer(id string, description string) *analysis.Analyzer {
|
||||
return &analysis.Analyzer{
|
||||
Name: id,
|
||||
Doc: description,
|
||||
Run: runSSRF,
|
||||
Requires: []*analysis.Analyzer{buildssa.Analyzer},
|
||||
}
|
||||
}
|
||||
|
||||
func runSSRF(pass *analysis.Pass) (interface{}, error) {
|
||||
ssaResult, err := getSSAResult(pass)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// TODO: implement the analysis
|
||||
for _, fn := range ssaResult.SSA.SrcFuncs {
|
||||
for _, block := range fn.DomPreorder() {
|
||||
for _, instr := range block.Instrs {
|
||||
switch instr := instr.(type) {
|
||||
case *ssa.Call:
|
||||
callee := instr.Call.StaticCallee()
|
||||
if callee != nil {
|
||||
ssaResult.Logger.Printf("callee: %s\n", callee)
|
||||
return newIssue(pass.Analyzer.Name,
|
||||
"not implemented",
|
||||
pass.Fset, instr.Call.Pos(), issue.Low, issue.High), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
2
vendor/github.com/securego/gosec/v2/analyzers/util.go
generated
vendored
2
vendor/github.com/securego/gosec/v2/analyzers/util.go
generated
vendored
@@ -38,7 +38,7 @@ type SSAAnalyzerResult struct {
|
||||
// BuildDefaultAnalyzers returns the default list of analyzers
|
||||
func BuildDefaultAnalyzers() []*analysis.Analyzer {
|
||||
return []*analysis.Analyzer{
|
||||
newSSRFAnalyzer("G107", "URL provided to HTTP request as taint input"),
|
||||
newSliceBoundsAnalyzer("G602", "Possible slice bounds out of range"),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
241
vendor/github.com/securego/gosec/v2/cwe/data.go
generated
vendored
241
vendor/github.com/securego/gosec/v2/cwe/data.go
generated
vendored
@@ -1,7 +1,5 @@
|
||||
package cwe
|
||||
|
||||
import "fmt"
|
||||
|
||||
const (
|
||||
// Acronym is the acronym of CWE
|
||||
Acronym = "CWE"
|
||||
@@ -13,139 +11,128 @@ const (
|
||||
Organization = "MITRE"
|
||||
// Description the description of CWE
|
||||
Description = "The MITRE Common Weakness Enumeration"
|
||||
)
|
||||
|
||||
var (
|
||||
// InformationURI link to the published CWE PDF
|
||||
InformationURI = fmt.Sprintf("https://cwe.mitre.org/data/published/cwe_v%s.pdf/", Version)
|
||||
InformationURI = "https://cwe.mitre.org/data/published/cwe_v" + Version + ".pdf/"
|
||||
// DownloadURI link to the zipped XML of the CWE list
|
||||
DownloadURI = fmt.Sprintf("https://cwe.mitre.org/data/xml/cwec_v%s.xml.zip", Version)
|
||||
|
||||
data = map[string]*Weakness{}
|
||||
|
||||
weaknesses = []*Weakness{
|
||||
{
|
||||
ID: "118",
|
||||
Description: "The software does not restrict or incorrectly restricts operations within the boundaries of a resource that is accessed using an index or pointer, such as memory or files.",
|
||||
Name: "Incorrect Access of Indexable Resource ('Range Error')",
|
||||
},
|
||||
{
|
||||
ID: "190",
|
||||
Description: "The software performs a calculation that can produce an integer overflow or wraparound, when the logic assumes that the resulting value will always be larger than the original value. This can introduce other weaknesses when the calculation is used for resource management or execution control.",
|
||||
Name: "Integer Overflow or Wraparound",
|
||||
},
|
||||
{
|
||||
ID: "200",
|
||||
Description: "The product exposes sensitive information to an actor that is not explicitly authorized to have access to that information.",
|
||||
Name: "Exposure of Sensitive Information to an Unauthorized Actor",
|
||||
},
|
||||
{
|
||||
ID: "22",
|
||||
Description: "The software uses external input to construct a pathname that is intended to identify a file or directory that is located underneath a restricted parent directory, but the software does not properly neutralize special elements within the pathname that can cause the pathname to resolve to a location that is outside of the restricted directory.",
|
||||
Name: "Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')",
|
||||
},
|
||||
{
|
||||
ID: "242",
|
||||
Description: "The program calls a function that can never be guaranteed to work safely.",
|
||||
Name: "Use of Inherently Dangerous Function",
|
||||
},
|
||||
{
|
||||
ID: "276",
|
||||
Description: "During installation, installed file permissions are set to allow anyone to modify those files.",
|
||||
Name: "Incorrect Default Permissions",
|
||||
},
|
||||
{
|
||||
ID: "295",
|
||||
Description: "The software does not validate, or incorrectly validates, a certificate.",
|
||||
Name: "Improper Certificate Validation",
|
||||
},
|
||||
{
|
||||
ID: "310",
|
||||
Description: "Weaknesses in this category are related to the design and implementation of data confidentiality and integrity. Frequently these deal with the use of encoding techniques, encryption libraries, and hashing algorithms. The weaknesses in this category could lead to a degradation of the quality data if they are not addressed.",
|
||||
Name: "Cryptographic Issues",
|
||||
},
|
||||
{
|
||||
ID: "322",
|
||||
Description: "The software performs a key exchange with an actor without verifying the identity of that actor.",
|
||||
Name: "Key Exchange without Entity Authentication",
|
||||
},
|
||||
{
|
||||
ID: "326",
|
||||
Description: "The software stores or transmits sensitive data using an encryption scheme that is theoretically sound, but is not strong enough for the level of protection required.",
|
||||
Name: "Inadequate Encryption Strength",
|
||||
},
|
||||
{
|
||||
ID: "327",
|
||||
Description: "The use of a broken or risky cryptographic algorithm is an unnecessary risk that may result in the exposure of sensitive information.",
|
||||
Name: "Use of a Broken or Risky Cryptographic Algorithm",
|
||||
},
|
||||
{
|
||||
ID: "338",
|
||||
Description: "The product uses a Pseudo-Random Number Generator (PRNG) in a security context, but the PRNG's algorithm is not cryptographically strong.",
|
||||
Name: "Use of Cryptographically Weak Pseudo-Random Number Generator (PRNG)",
|
||||
},
|
||||
{
|
||||
ID: "377",
|
||||
Description: "Creating and using insecure temporary files can leave application and system data vulnerable to attack.",
|
||||
Name: "Insecure Temporary File",
|
||||
},
|
||||
{
|
||||
ID: "400",
|
||||
Description: "The software does not properly control the allocation and maintenance of a limited resource, thereby enabling an actor to influence the amount of resources consumed, eventually leading to the exhaustion of available resources.",
|
||||
Name: "Uncontrolled Resource Consumption",
|
||||
},
|
||||
{
|
||||
ID: "409",
|
||||
Description: "The software does not handle or incorrectly handles a compressed input with a very high compression ratio that produces a large output.",
|
||||
Name: "Improper Handling of Highly Compressed Data (Data Amplification)",
|
||||
},
|
||||
{
|
||||
ID: "703",
|
||||
Description: "The software does not properly anticipate or handle exceptional conditions that rarely occur during normal operation of the software.",
|
||||
Name: "Improper Check or Handling of Exceptional Conditions",
|
||||
},
|
||||
{
|
||||
ID: "78",
|
||||
Description: "The software constructs all or part of an OS command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended OS command when it is sent to a downstream component.",
|
||||
Name: "Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')",
|
||||
},
|
||||
{
|
||||
ID: "79",
|
||||
Description: "The software does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users.",
|
||||
Name: "Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')",
|
||||
},
|
||||
{
|
||||
ID: "798",
|
||||
Description: "The software contains hard-coded credentials, such as a password or cryptographic key, which it uses for its own inbound authentication, outbound communication to external components, or encryption of internal data.",
|
||||
Name: "Use of Hard-coded Credentials",
|
||||
},
|
||||
{
|
||||
ID: "88",
|
||||
Description: "The software constructs a string for a command to executed by a separate component\nin another control sphere, but it does not properly delimit the\nintended arguments, options, or switches within that command string.",
|
||||
Name: "Improper Neutralization of Argument Delimiters in a Command ('Argument Injection')",
|
||||
},
|
||||
{
|
||||
ID: "89",
|
||||
Description: "The software constructs all or part of an SQL command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended SQL command when it is sent to a downstream component.",
|
||||
Name: "Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')",
|
||||
},
|
||||
{
|
||||
ID: "676",
|
||||
Description: "The program invokes a potentially dangerous function that could introduce a vulnerability if it is used incorrectly, but the function can also be used safely.",
|
||||
Name: "Use of Potentially Dangerous Function",
|
||||
},
|
||||
}
|
||||
DownloadURI = "https://cwe.mitre.org/data/xml/cwec_v" + Version + ".xml.zip"
|
||||
)
|
||||
|
||||
func init() {
|
||||
for _, weakness := range weaknesses {
|
||||
data[weakness.ID] = weakness
|
||||
}
|
||||
var idWeaknesses = map[string]*Weakness{
|
||||
"118": {
|
||||
ID: "118",
|
||||
Description: "The software does not restrict or incorrectly restricts operations within the boundaries of a resource that is accessed using an index or pointer, such as memory or files.",
|
||||
Name: "Incorrect Access of Indexable Resource ('Range Error')",
|
||||
},
|
||||
"190": {
|
||||
ID: "190",
|
||||
Description: "The software performs a calculation that can produce an integer overflow or wraparound, when the logic assumes that the resulting value will always be larger than the original value. This can introduce other weaknesses when the calculation is used for resource management or execution control.",
|
||||
Name: "Integer Overflow or Wraparound",
|
||||
},
|
||||
"200": {
|
||||
ID: "200",
|
||||
Description: "The product exposes sensitive information to an actor that is not explicitly authorized to have access to that information.",
|
||||
Name: "Exposure of Sensitive Information to an Unauthorized Actor",
|
||||
},
|
||||
"22": {
|
||||
ID: "22",
|
||||
Description: "The software uses external input to construct a pathname that is intended to identify a file or directory that is located underneath a restricted parent directory, but the software does not properly neutralize special elements within the pathname that can cause the pathname to resolve to a location that is outside of the restricted directory.",
|
||||
Name: "Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')",
|
||||
},
|
||||
"242": {
|
||||
ID: "242",
|
||||
Description: "The program calls a function that can never be guaranteed to work safely.",
|
||||
Name: "Use of Inherently Dangerous Function",
|
||||
},
|
||||
"276": {
|
||||
ID: "276",
|
||||
Description: "During installation, installed file permissions are set to allow anyone to modify those files.",
|
||||
Name: "Incorrect Default Permissions",
|
||||
},
|
||||
"295": {
|
||||
ID: "295",
|
||||
Description: "The software does not validate, or incorrectly validates, a certificate.",
|
||||
Name: "Improper Certificate Validation",
|
||||
},
|
||||
"310": {
|
||||
ID: "310",
|
||||
Description: "Weaknesses in this category are related to the design and implementation of data confidentiality and integrity. Frequently these deal with the use of encoding techniques, encryption libraries, and hashing algorithms. The weaknesses in this category could lead to a degradation of the quality data if they are not addressed.",
|
||||
Name: "Cryptographic Issues",
|
||||
},
|
||||
"322": {
|
||||
ID: "322",
|
||||
Description: "The software performs a key exchange with an actor without verifying the identity of that actor.",
|
||||
Name: "Key Exchange without Entity Authentication",
|
||||
},
|
||||
"326": {
|
||||
ID: "326",
|
||||
Description: "The software stores or transmits sensitive data using an encryption scheme that is theoretically sound, but is not strong enough for the level of protection required.",
|
||||
Name: "Inadequate Encryption Strength",
|
||||
},
|
||||
"327": {
|
||||
ID: "327",
|
||||
Description: "The use of a broken or risky cryptographic algorithm is an unnecessary risk that may result in the exposure of sensitive information.",
|
||||
Name: "Use of a Broken or Risky Cryptographic Algorithm",
|
||||
},
|
||||
"338": {
|
||||
ID: "338",
|
||||
Description: "The product uses a Pseudo-Random Number Generator (PRNG) in a security context, but the PRNG's algorithm is not cryptographically strong.",
|
||||
Name: "Use of Cryptographically Weak Pseudo-Random Number Generator (PRNG)",
|
||||
},
|
||||
"377": {
|
||||
ID: "377",
|
||||
Description: "Creating and using insecure temporary files can leave application and system data vulnerable to attack.",
|
||||
Name: "Insecure Temporary File",
|
||||
},
|
||||
"400": {
|
||||
ID: "400",
|
||||
Description: "The software does not properly control the allocation and maintenance of a limited resource, thereby enabling an actor to influence the amount of resources consumed, eventually leading to the exhaustion of available resources.",
|
||||
Name: "Uncontrolled Resource Consumption",
|
||||
},
|
||||
"409": {
|
||||
ID: "409",
|
||||
Description: "The software does not handle or incorrectly handles a compressed input with a very high compression ratio that produces a large output.",
|
||||
Name: "Improper Handling of Highly Compressed Data (Data Amplification)",
|
||||
},
|
||||
"703": {
|
||||
ID: "703",
|
||||
Description: "The software does not properly anticipate or handle exceptional conditions that rarely occur during normal operation of the software.",
|
||||
Name: "Improper Check or Handling of Exceptional Conditions",
|
||||
},
|
||||
"78": {
|
||||
ID: "78",
|
||||
Description: "The software constructs all or part of an OS command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended OS command when it is sent to a downstream component.",
|
||||
Name: "Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')",
|
||||
},
|
||||
"79": {
|
||||
ID: "79",
|
||||
Description: "The software does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users.",
|
||||
Name: "Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')",
|
||||
},
|
||||
"798": {
|
||||
ID: "798",
|
||||
Description: "The software contains hard-coded credentials, such as a password or cryptographic key, which it uses for its own inbound authentication, outbound communication to external components, or encryption of internal data.",
|
||||
Name: "Use of Hard-coded Credentials",
|
||||
},
|
||||
"88": {
|
||||
ID: "88",
|
||||
Description: "The software constructs a string for a command to executed by a separate component\nin another control sphere, but it does not properly delimit the\nintended arguments, options, or switches within that command string.",
|
||||
Name: "Improper Neutralization of Argument Delimiters in a Command ('Argument Injection')",
|
||||
},
|
||||
"89": {
|
||||
ID: "89",
|
||||
Description: "The software constructs all or part of an SQL command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended SQL command when it is sent to a downstream component.",
|
||||
Name: "Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')",
|
||||
},
|
||||
"676": {
|
||||
ID: "676",
|
||||
Description: "The program invokes a potentially dangerous function that could introduce a vulnerability if it is used incorrectly, but the function can also be used safely.",
|
||||
Name: "Use of Potentially Dangerous Function",
|
||||
},
|
||||
}
|
||||
|
||||
// Get Retrieves a CWE weakness by it's id
|
||||
func Get(id string) *Weakness {
|
||||
weakness, ok := data[id]
|
||||
weakness, ok := idWeaknesses[id]
|
||||
if ok && weakness != nil {
|
||||
return weakness
|
||||
}
|
||||
|
||||
4
vendor/github.com/securego/gosec/v2/helpers.go
generated
vendored
4
vendor/github.com/securego/gosec/v2/helpers.go
generated
vendored
@@ -100,7 +100,7 @@ func GetChar(n ast.Node) (byte, error) {
|
||||
// Unlike the other getters, it does _not_ raise an error for unknown ast.Node types. At the base, the recursion will hit a non-BinaryExpr type,
|
||||
// either BasicLit or other, so it's not an error case. It will only error if `strconv.Unquote` errors. This matters, because there's
|
||||
// currently functionality that relies on error values being returned by GetString if and when it hits a non-basiclit string node type,
|
||||
// hence for cases where recursion is needed, we use this separate function, so that we can still be backwards compatbile.
|
||||
// hence for cases where recursion is needed, we use this separate function, so that we can still be backwards compatible.
|
||||
//
|
||||
// This was added to handle a SQL injection concatenation case where the injected value is infixed between two strings, not at the start or end. See example below
|
||||
//
|
||||
@@ -183,7 +183,7 @@ func GetCallInfo(n ast.Node, ctx *Context) (string, string, error) {
|
||||
case *ast.CallExpr:
|
||||
switch call := expr.Fun.(type) {
|
||||
case *ast.Ident:
|
||||
if call.Name == "new" {
|
||||
if call.Name == "new" && len(expr.Args) > 0 {
|
||||
t := ctx.Info.TypeOf(expr.Args[0])
|
||||
if t != nil {
|
||||
return t.String(), fn.Sel.Name, nil
|
||||
|
||||
16
vendor/github.com/securego/gosec/v2/issue/issue.go
generated
vendored
16
vendor/github.com/securego/gosec/v2/issue/issue.go
generated
vendored
@@ -178,11 +178,7 @@ func codeSnippetEndLine(node ast.Node, fobj *token.File) int64 {
|
||||
// New creates a new Issue
|
||||
func New(fobj *token.File, node ast.Node, ruleID, desc string, severity, confidence Score) *Issue {
|
||||
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)
|
||||
}
|
||||
line := GetLine(fobj, node)
|
||||
col := strconv.Itoa(fobj.Position(node.Pos()).Column)
|
||||
|
||||
var code string
|
||||
@@ -217,3 +213,13 @@ func (i *Issue) WithSuppressions(suppressions []SuppressionInfo) *Issue {
|
||||
i.Suppressions = suppressions
|
||||
return i
|
||||
}
|
||||
|
||||
// GetLine returns the line number of a given ast.Node
|
||||
func GetLine(fobj *token.File, node ast.Node) string {
|
||||
start, end := fobj.Line(node.Pos()), fobj.Line(node.End())
|
||||
line := strconv.Itoa(start)
|
||||
if start != end {
|
||||
line = fmt.Sprintf("%d-%d", start, end)
|
||||
}
|
||||
return line
|
||||
}
|
||||
|
||||
8
vendor/github.com/securego/gosec/v2/report/html/template.html
generated
vendored
8
vendor/github.com/securego/gosec/v2/report/html/template.html
generated
vendored
@@ -5,12 +5,12 @@
|
||||
<title>Golang Security Checker</title>
|
||||
<link rel="shortcut icon" type="image/png" href="https://securego.io/img/favicon.png">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.9.4/css/bulma.min.css" integrity="sha512-HqxHUkJM0SYcbvxUw5P60SzdOTy/QVwA1JJrvaXJv4q7lmbDZCmZaqz01UPOaQveoxfYRv1tHozWGPMcuTBuvQ==" crossorigin="anonymous"/>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/styles/default.min.css" integrity="sha512-hasIneQUHlh06VNBe7f6ZcHmeRTLIaQWFd43YriJ0UND19bvYRauxthDg8E4eVNPm9bRUhr5JGeqH7FRFXQu5g==" crossorigin="anonymous"/>
|
||||
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/highlight.min.js" integrity="sha512-rdhY3cbXURo13l/WU9VlaRyaIYeJ/KBakckXIvJNAQde8DgpOmE+eZf7ha4vdqVjTtwQt69bD2wH2LXob/LB7Q==" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/languages/go.min.js" integrity="sha512-Ea+IN1qMvgwTqOnwxM38Hn54IaDS2buEvMJNTdSB5JOT4njx3RvPij353zbUMpT+zYjDqQDr2UbrbnW5+wE54A==" crossorigin="anonymous"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/default.min.css" integrity="sha512-hasIneQUHlh06VNBe7f6ZcHmeRTLIaQWFd43YriJ0UND19bvYRauxthDg8E4eVNPm9bRUhr5JGeqH7FRFXQu5g==" crossorigin="anonymous"/>
|
||||
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js" integrity="sha512-D9gUyxqja7hBtkWpPWGt9wfbfaMGVt9gnyCvYa+jojwwPHLCzUm5i8rpk7vD7wNee9bA35eYIjobYPaQuKS1MQ==" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/go.min.js" integrity="sha512-wsnZc3vH14xwbbaoAwkar86729DTpz6wx48ABISfmaKLZwP/lm8d7Z+Hmr9JKobAENs0qO/cGounL7LUEg10Pg==" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/react/15.7.0/react.min.js" integrity="sha512-+TFn1Gqbwx/qgwW3NU1/YtFYTfHGeD1e/8YfJZzkb6TFEZP4SUwp1Az9DMeWh3qC0F+YPKXbV3YclMUwBTvO3g==" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/react/15.6.1/react-dom.min.js" integrity="sha512-8C49ZG/SaQnWaUgCHTU1o8uIQNYE6R8me38SwF26g2Q0byEXF4Jlvm+T/JAMHMeTBiEVPslSZRv9Xt4AV0pfmw==" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/7.22.10/babel.min.js" integrity="sha512-UhgUmmslB4Pi7NNyzbscVQPaL3meon1WMwHwHDjCLui/kWpr2Wz4sRZ8HlG4gZIUuKkF+LWYTX55ZVPzra2HTw==" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/7.23.2/babel.min.js" integrity="sha512-ND11pbmp3M3Wldj90In1EUlHIt8T7O6FykizQ/yXrFjHtpX+D0SX+/IVeLjqAV91r/Lavq4BpWJIC0nUtw5Kvw==" crossorigin="anonymous"></script>
|
||||
<style>
|
||||
.field-label {
|
||||
min-width: 80px;
|
||||
|
||||
2
vendor/github.com/securego/gosec/v2/report/sarif/builder.go
generated
vendored
2
vendor/github.com/securego/gosec/v2/report/sarif/builder.go
generated
vendored
@@ -8,7 +8,7 @@ func NewReport(version string, schema string) *Report {
|
||||
}
|
||||
}
|
||||
|
||||
// WithRuns dafines runs for the current report
|
||||
// WithRuns defines runs for the current report
|
||||
func (r *Report) WithRuns(runs ...*Run) *Report {
|
||||
r.Runs = runs
|
||||
return r
|
||||
|
||||
46
vendor/github.com/securego/gosec/v2/rules/fileperms.go
generated
vendored
46
vendor/github.com/securego/gosec/v2/rules/fileperms.go
generated
vendored
@@ -30,6 +30,7 @@ type filePermissions struct {
|
||||
calls []string
|
||||
}
|
||||
|
||||
// ID returns the ID of the rule.
|
||||
func (r *filePermissions) ID() string {
|
||||
return r.MetaData.ID
|
||||
}
|
||||
@@ -55,6 +56,7 @@ func modeIsSubset(subset int64, superset int64) bool {
|
||||
return (subset | superset) == superset
|
||||
}
|
||||
|
||||
// Match checks if the rule is matched.
|
||||
func (r *filePermissions) Match(n ast.Node, c *gosec.Context) (*issue.Issue, error) {
|
||||
for _, pkg := range r.pkgs {
|
||||
if callexpr, matched := gosec.MatchCallByPackage(n, c, pkg, r.calls...); matched {
|
||||
@@ -116,3 +118,47 @@ func NewMkdirPerms(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
|
||||
},
|
||||
}, []ast.Node{(*ast.CallExpr)(nil)}
|
||||
}
|
||||
|
||||
type osCreatePermissions struct {
|
||||
issue.MetaData
|
||||
mode int64
|
||||
pkgs []string
|
||||
calls []string
|
||||
}
|
||||
|
||||
const defaultOsCreateMode = 0o666
|
||||
|
||||
// ID returns the ID of the rule.
|
||||
func (r *osCreatePermissions) ID() string {
|
||||
return r.MetaData.ID
|
||||
}
|
||||
|
||||
// Match checks if the rule is matched.
|
||||
func (r *osCreatePermissions) Match(n ast.Node, c *gosec.Context) (*issue.Issue, error) {
|
||||
for _, pkg := range r.pkgs {
|
||||
if _, matched := gosec.MatchCallByPackage(n, c, pkg, r.calls...); matched {
|
||||
if !modeIsSubset(defaultOsCreateMode, r.mode) {
|
||||
return c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// NewOsCreatePerms reates a rule to detect file creation with a more permissive than configured
|
||||
// permission mask.
|
||||
func NewOsCreatePerms(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
|
||||
mode := getConfiguredMode(conf, id, 0o666)
|
||||
return &osCreatePermissions{
|
||||
mode: mode,
|
||||
pkgs: []string{"os"},
|
||||
calls: []string{"Create"},
|
||||
MetaData: issue.MetaData{
|
||||
ID: id,
|
||||
Severity: issue.Medium,
|
||||
Confidence: issue.High,
|
||||
What: fmt.Sprintf("Expect file permissions to be %#o or less but os.Create used with default permissions %#o",
|
||||
mode, defaultOsCreateMode),
|
||||
},
|
||||
}, []ast.Node{(*ast.CallExpr)(nil)}
|
||||
}
|
||||
|
||||
197
vendor/github.com/securego/gosec/v2/rules/hardcoded_credentials.go
generated
vendored
197
vendor/github.com/securego/gosec/v2/rules/hardcoded_credentials.go
generated
vendored
@@ -15,6 +15,7 @@
|
||||
package rules
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/token"
|
||||
"regexp"
|
||||
@@ -26,10 +27,169 @@ import (
|
||||
"github.com/securego/gosec/v2/issue"
|
||||
)
|
||||
|
||||
type secretPattern struct {
|
||||
name string
|
||||
regexp *regexp.Regexp
|
||||
}
|
||||
|
||||
var secretsPatterns = [...]secretPattern{
|
||||
{
|
||||
name: "RSA private key",
|
||||
regexp: regexp.MustCompile(`-----BEGIN RSA PRIVATE KEY-----`),
|
||||
},
|
||||
{
|
||||
name: "SSH (DSA) private key",
|
||||
regexp: regexp.MustCompile(`-----BEGIN DSA PRIVATE KEY-----`),
|
||||
},
|
||||
{
|
||||
name: "SSH (EC) private key",
|
||||
regexp: regexp.MustCompile(`-----BEGIN EC PRIVATE KEY-----`),
|
||||
},
|
||||
{
|
||||
name: "PGP private key block",
|
||||
regexp: regexp.MustCompile(`-----BEGIN PGP PRIVATE KEY BLOCK-----`),
|
||||
},
|
||||
{
|
||||
name: "Slack Token",
|
||||
regexp: regexp.MustCompile(`xox[pborsa]-[0-9]{12}-[0-9]{12}-[0-9]{12}-[a-z0-9]{32}`),
|
||||
},
|
||||
{
|
||||
name: "AWS API Key",
|
||||
regexp: regexp.MustCompile(`AKIA[0-9A-Z]{16}`),
|
||||
},
|
||||
{
|
||||
name: "Amazon MWS Auth Token",
|
||||
regexp: regexp.MustCompile(`amzn\.mws\.[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}`),
|
||||
},
|
||||
{
|
||||
name: "AWS AppSync GraphQL Key",
|
||||
regexp: regexp.MustCompile(`da2-[a-z0-9]{26}`),
|
||||
},
|
||||
{
|
||||
name: "GitHub personal access token",
|
||||
regexp: regexp.MustCompile(`ghp_[a-zA-Z0-9]{36}`),
|
||||
},
|
||||
{
|
||||
name: "GitHub fine-grained access token",
|
||||
regexp: regexp.MustCompile(`github_pat_[a-zA-Z0-9]{22}_[a-zA-Z0-9]{59}`),
|
||||
},
|
||||
{
|
||||
name: "GitHub action temporary token",
|
||||
regexp: regexp.MustCompile(`ghs_[a-zA-Z0-9]{36}`),
|
||||
},
|
||||
{
|
||||
name: "Google API Key",
|
||||
regexp: regexp.MustCompile(`AIza[0-9A-Za-z\-_]{35}`),
|
||||
},
|
||||
{
|
||||
name: "Google Cloud Platform API Key",
|
||||
regexp: regexp.MustCompile(`AIza[0-9A-Za-z\-_]{35}`),
|
||||
},
|
||||
{
|
||||
name: "Google Cloud Platform OAuth",
|
||||
regexp: regexp.MustCompile(`[0-9]+-[0-9A-Za-z_]{32}\.apps\.googleusercontent\.com`),
|
||||
},
|
||||
{
|
||||
name: "Google Drive API Key",
|
||||
regexp: regexp.MustCompile(`AIza[0-9A-Za-z\-_]{35}`),
|
||||
},
|
||||
{
|
||||
name: "Google Drive OAuth",
|
||||
regexp: regexp.MustCompile(`[0-9]+-[0-9A-Za-z_]{32}\.apps\.googleusercontent\.com`),
|
||||
},
|
||||
{
|
||||
name: "Google (GCP) Service-account",
|
||||
regexp: regexp.MustCompile(`"type": "service_account"`),
|
||||
},
|
||||
{
|
||||
name: "Google Gmail API Key",
|
||||
regexp: regexp.MustCompile(`AIza[0-9A-Za-z\-_]{35}`),
|
||||
},
|
||||
{
|
||||
name: "Google Gmail OAuth",
|
||||
regexp: regexp.MustCompile(`[0-9]+-[0-9A-Za-z_]{32}\.apps\.googleusercontent\.com`),
|
||||
},
|
||||
{
|
||||
name: "Google OAuth Access Token",
|
||||
regexp: regexp.MustCompile(`ya29\.[0-9A-Za-z\-_]+`),
|
||||
},
|
||||
{
|
||||
name: "Google YouTube API Key",
|
||||
regexp: regexp.MustCompile(`AIza[0-9A-Za-z\-_]{35}`),
|
||||
},
|
||||
{
|
||||
name: "Google YouTube OAuth",
|
||||
regexp: regexp.MustCompile(`[0-9]+-[0-9A-Za-z_]{32}\.apps\.googleusercontent\.com`),
|
||||
},
|
||||
{
|
||||
name: "Generic API Key",
|
||||
regexp: regexp.MustCompile(`[aA][pP][iI]_?[kK][eE][yY].*[''|"][0-9a-zA-Z]{32,45}[''|"]`),
|
||||
},
|
||||
{
|
||||
name: "Generic Secret",
|
||||
regexp: regexp.MustCompile(`[sS][eE][cC][rR][eE][tT].*[''|"][0-9a-zA-Z]{32,45}[''|"]`),
|
||||
},
|
||||
{
|
||||
name: "Heroku API Key",
|
||||
regexp: regexp.MustCompile(`[hH][eE][rR][oO][kK][uU].*[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}`),
|
||||
},
|
||||
{
|
||||
name: "MailChimp API Key",
|
||||
regexp: regexp.MustCompile(`[0-9a-f]{32}-us[0-9]{1,2}`),
|
||||
},
|
||||
{
|
||||
name: "Mailgun API Key",
|
||||
regexp: regexp.MustCompile(`key-[0-9a-zA-Z]{32}`),
|
||||
},
|
||||
{
|
||||
name: "Password in URL",
|
||||
regexp: regexp.MustCompile(`[a-zA-Z]{3,10}://[^/\\s:@]{3,20}:[^/\\s:@]{3,20}@.{1,100}["'\\s]`),
|
||||
},
|
||||
{
|
||||
name: "Slack Webhook",
|
||||
regexp: regexp.MustCompile(`https://hooks\.slack\.com/services/T[a-zA-Z0-9_]{8}/B[a-zA-Z0-9_]{8}/[a-zA-Z0-9_]{24}`),
|
||||
},
|
||||
{
|
||||
name: "Stripe API Key",
|
||||
regexp: regexp.MustCompile(`sk_live_[0-9a-zA-Z]{24}`),
|
||||
},
|
||||
{
|
||||
name: "Stripe API Key",
|
||||
regexp: regexp.MustCompile(`sk_live_[0-9a-zA-Z]{24}`),
|
||||
},
|
||||
{
|
||||
name: "Stripe Restricted API Key",
|
||||
regexp: regexp.MustCompile(`rk_live_[0-9a-zA-Z]{24}`),
|
||||
},
|
||||
{
|
||||
name: "Square Access Token",
|
||||
regexp: regexp.MustCompile(`sq0atp-[0-9A-Za-z\-_]{22}`),
|
||||
},
|
||||
{
|
||||
name: "Square OAuth Secret",
|
||||
regexp: regexp.MustCompile(`sq0csp-[0-9A-Za-z\-_]{43}`),
|
||||
},
|
||||
{
|
||||
name: "Telegram Bot API Key",
|
||||
regexp: regexp.MustCompile(`[0-9]+:AA[0-9A-Za-z\-_]{33}`),
|
||||
},
|
||||
{
|
||||
name: "Twilio API Key",
|
||||
regexp: regexp.MustCompile(`SK[0-9a-fA-F]{32}`),
|
||||
},
|
||||
{
|
||||
name: "Twitter Access Token",
|
||||
regexp: regexp.MustCompile(`[tT][wW][iI][tT][tT][eE][rR].*[1-9][0-9]+-[0-9a-zA-Z]{40}`),
|
||||
},
|
||||
{
|
||||
name: "Twitter OAuth",
|
||||
regexp: regexp.MustCompile(`[tT][wW][iI][tT][tT][eE][rR].*[''|"][0-9a-zA-Z]{35,44}[''|"]`),
|
||||
},
|
||||
}
|
||||
|
||||
type credentials struct {
|
||||
issue.MetaData
|
||||
pattern *regexp.Regexp
|
||||
patternValue *regexp.Regexp // Pattern for matching string values (LHS on assign statements)
|
||||
entropyThreshold float64
|
||||
perCharThreshold float64
|
||||
truncate int
|
||||
@@ -56,6 +216,15 @@ func (r *credentials) isHighEntropyString(str string) bool {
|
||||
entropyPerChar >= r.perCharThreshold))
|
||||
}
|
||||
|
||||
func (r *credentials) isSecretPattern(str string) (bool, string) {
|
||||
for _, pattern := range secretsPatterns {
|
||||
if pattern.regexp.MatchString(str) {
|
||||
return true, pattern.name
|
||||
}
|
||||
}
|
||||
return false, ""
|
||||
}
|
||||
|
||||
func (r *credentials) Match(n ast.Node, ctx *gosec.Context) (*issue.Issue, error) {
|
||||
switch node := n.(type) {
|
||||
case *ast.AssignStmt:
|
||||
@@ -89,9 +258,9 @@ func (r *credentials) matchAssign(assign *ast.AssignStmt, ctx *gosec.Context) (*
|
||||
continue
|
||||
}
|
||||
|
||||
if r.patternValue.MatchString(val) {
|
||||
if r.ignoreEntropy || r.isHighEntropyString(val) {
|
||||
return ctx.NewIssue(assign, r.ID(), r.What, r.Severity, r.Confidence), nil
|
||||
if r.ignoreEntropy || r.isHighEntropyString(val) {
|
||||
if ok, patternName := r.isSecretPattern(val); ok {
|
||||
return ctx.NewIssue(assign, r.ID(), fmt.Sprintf("%s: %s", r.What, patternName), r.Severity, r.Confidence), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -120,9 +289,9 @@ func (r *credentials) matchValueSpec(valueSpec *ast.ValueSpec, ctx *gosec.Contex
|
||||
// Now that no variable names have been matched, match the actual values to find any creds
|
||||
for _, ident := range valueSpec.Values {
|
||||
if val, err := gosec.GetString(ident); err == nil {
|
||||
if r.patternValue.MatchString(val) {
|
||||
if r.ignoreEntropy || r.isHighEntropyString(val) {
|
||||
return ctx.NewIssue(valueSpec, r.ID(), r.What, r.Severity, r.Confidence), nil
|
||||
if r.ignoreEntropy || r.isHighEntropyString(val) {
|
||||
if ok, patternName := r.isSecretPattern(val); ok {
|
||||
return ctx.NewIssue(valueSpec, r.ID(), fmt.Sprintf("%s: %s", r.What, patternName), r.Severity, r.Confidence), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -159,9 +328,9 @@ func (r *credentials) matchEqualityCheck(binaryExpr *ast.BinaryExpr, ctx *gosec.
|
||||
|
||||
if ok && identStrConst.Kind == token.STRING {
|
||||
s, _ := gosec.GetString(identStrConst)
|
||||
if r.patternValue.MatchString(s) {
|
||||
if r.ignoreEntropy || r.isHighEntropyString(s) {
|
||||
return ctx.NewIssue(binaryExpr, r.ID(), r.What, r.Severity, r.Confidence), nil
|
||||
if r.ignoreEntropy || r.isHighEntropyString(s) {
|
||||
if ok, patternName := r.isSecretPattern(s); ok {
|
||||
return ctx.NewIssue(binaryExpr, r.ID(), fmt.Sprintf("%s: %s", r.What, patternName), r.Severity, r.Confidence), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -173,7 +342,6 @@ func (r *credentials) matchEqualityCheck(binaryExpr *ast.BinaryExpr, ctx *gosec.
|
||||
// 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|pw|apiKey|bearer|cred`
|
||||
patternValue := "(?i)(^(.*[:;,](\\s)*)?[a-f0-9]{64}$)|(AIza[0-9A-Za-z-_]{35})|(^(.*[:;,](\\s)*)?github_pat_[a-zA-Z0-9]{22}_[a-zA-Z0-9]{59}$)|(^(.*[:;,](\\s)*)?[0-9a-zA-Z-_]{24}$)"
|
||||
entropyThreshold := 80.0
|
||||
perCharThreshold := 3.0
|
||||
ignoreEntropy := false
|
||||
@@ -186,12 +354,6 @@ func NewHardcodedCredentials(id string, conf gosec.Config) (gosec.Rule, []ast.No
|
||||
}
|
||||
}
|
||||
|
||||
if configPatternValue, ok := conf["patternValue"]; ok {
|
||||
if cfgPatternValue, ok := configPatternValue.(string); ok {
|
||||
patternValue = cfgPatternValue
|
||||
}
|
||||
}
|
||||
|
||||
if configIgnoreEntropy, ok := conf["ignore_entropy"]; ok {
|
||||
if cfgIgnoreEntropy, ok := configIgnoreEntropy.(bool); ok {
|
||||
ignoreEntropy = cfgIgnoreEntropy
|
||||
@@ -222,7 +384,6 @@ func NewHardcodedCredentials(id string, conf gosec.Config) (gosec.Rule, []ast.No
|
||||
|
||||
return &credentials{
|
||||
pattern: regexp.MustCompile(pattern),
|
||||
patternValue: regexp.MustCompile(patternValue),
|
||||
entropyThreshold: entropyThreshold,
|
||||
perCharThreshold: perCharThreshold,
|
||||
ignoreEntropy: ignoreEntropy,
|
||||
|
||||
30
vendor/github.com/securego/gosec/v2/rules/implicit_aliasing.go
generated
vendored
30
vendor/github.com/securego/gosec/v2/rules/implicit_aliasing.go
generated
vendored
@@ -3,6 +3,7 @@ package rules
|
||||
import (
|
||||
"go/ast"
|
||||
"go/token"
|
||||
"go/types"
|
||||
|
||||
"github.com/securego/gosec/v2"
|
||||
"github.com/securego/gosec/v2/issue"
|
||||
@@ -28,23 +29,20 @@ func containsUnary(exprs []*ast.UnaryExpr, expr *ast.UnaryExpr) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func getIdentExpr(expr ast.Expr) *ast.Ident {
|
||||
func getIdentExpr(expr ast.Expr) (*ast.Ident, bool) {
|
||||
return doGetIdentExpr(expr, false)
|
||||
}
|
||||
|
||||
func doGetIdentExpr(expr ast.Expr, hasSelector bool) (*ast.Ident, bool) {
|
||||
switch node := expr.(type) {
|
||||
case *ast.Ident:
|
||||
return node
|
||||
return node, hasSelector
|
||||
case *ast.SelectorExpr:
|
||||
return getIdentExpr(node.X)
|
||||
return doGetIdentExpr(node.X, true)
|
||||
case *ast.UnaryExpr:
|
||||
switch e := node.X.(type) {
|
||||
case *ast.Ident:
|
||||
return e
|
||||
case *ast.SelectorExpr:
|
||||
return getIdentExpr(e.X)
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
return doGetIdentExpr(node.X, hasSelector)
|
||||
default:
|
||||
return nil
|
||||
return nil, false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,9 +90,13 @@ func (r *implicitAliasing) Match(n ast.Node, c *gosec.Context) (*issue.Issue, er
|
||||
}
|
||||
|
||||
// If we find a unary op of & (reference) of an object within r.aliases, complain.
|
||||
if identExpr := getIdentExpr(node); identExpr != nil && node.Op.String() == "&" {
|
||||
if identExpr, hasSelector := getIdentExpr(node); identExpr != nil && node.Op.String() == "&" {
|
||||
if _, contains := r.aliases[identExpr.Obj]; contains {
|
||||
return c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence), nil
|
||||
_, isPointer := c.Info.TypeOf(identExpr).(*types.Pointer)
|
||||
|
||||
if !hasSelector || !isPointer {
|
||||
return c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
case *ast.ReturnStmt:
|
||||
|
||||
2
vendor/github.com/securego/gosec/v2/rules/rulelist.go
generated
vendored
2
vendor/github.com/securego/gosec/v2/rules/rulelist.go
generated
vendored
@@ -91,6 +91,7 @@ func Generate(trackSuppressions bool, filters ...RuleFilter) RuleList {
|
||||
{"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", "Poor file permissions used when creating a file with os.Create", NewOsCreatePerms},
|
||||
|
||||
// crypto
|
||||
{"G401", "Detect the usage of DES, RC4, MD5 or SHA1", NewUsesWeakCryptography},
|
||||
@@ -107,7 +108,6 @@ func Generate(trackSuppressions bool, filters ...RuleFilter) RuleList {
|
||||
|
||||
// memory safety
|
||||
{"G601", "Implicit memory aliasing in RangeStmt", NewImplicitAliasing},
|
||||
{"G602", "Slice access out of bounds", NewSliceBoundCheck},
|
||||
}
|
||||
|
||||
ruleMap := make(map[string]RuleDefinition)
|
||||
|
||||
405
vendor/github.com/securego/gosec/v2/rules/slice_bounds.go
generated
vendored
405
vendor/github.com/securego/gosec/v2/rules/slice_bounds.go
generated
vendored
@@ -1,405 +0,0 @@
|
||||
package rules
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/types"
|
||||
|
||||
"github.com/securego/gosec/v2"
|
||||
"github.com/securego/gosec/v2/issue"
|
||||
)
|
||||
|
||||
// sliceOutOfBounds is a rule which checks for slices which are accessed outside their capacity,
|
||||
// either through indexing it out of bounds or through slice expressions whose low or high index
|
||||
// are out of bounds.
|
||||
type sliceOutOfBounds struct {
|
||||
sliceCaps map[*ast.CallExpr]map[string]*int64 // Capacities of slices. Maps function call -> var name -> value.
|
||||
currentScope *types.Scope // Current scope. Map is cleared when scope changes.
|
||||
currentFuncName string // Current function.
|
||||
funcCallArgs map[string][]*int64 // Caps to load once a func declaration is scanned.
|
||||
issue.MetaData // Metadata for this rule.
|
||||
}
|
||||
|
||||
// ID returns the rule ID for sliceOutOfBounds: G602.
|
||||
func (s *sliceOutOfBounds) ID() string {
|
||||
return s.MetaData.ID
|
||||
}
|
||||
|
||||
func (s *sliceOutOfBounds) Match(node ast.Node, ctx *gosec.Context) (*issue.Issue, error) {
|
||||
if s.currentScope == nil {
|
||||
s.currentScope = ctx.Pkg.Scope()
|
||||
} else if s.currentScope != ctx.Pkg.Scope() {
|
||||
s.currentScope = ctx.Pkg.Scope()
|
||||
|
||||
// Clear slice map, since we are in a new scope
|
||||
sliceMapNil := make(map[string]*int64)
|
||||
sliceCaps := make(map[*ast.CallExpr]map[string]*int64)
|
||||
sliceCaps[nil] = sliceMapNil
|
||||
s.sliceCaps = sliceCaps
|
||||
}
|
||||
|
||||
switch node := node.(type) {
|
||||
case *ast.AssignStmt:
|
||||
return s.matchAssign(node, ctx)
|
||||
case *ast.SliceExpr:
|
||||
return s.matchSliceExpr(node, ctx)
|
||||
case *ast.IndexExpr:
|
||||
return s.matchIndexExpr(node, ctx)
|
||||
case *ast.FuncDecl:
|
||||
s.currentFuncName = node.Name.Name
|
||||
s.loadArgCaps(node)
|
||||
case *ast.CallExpr:
|
||||
if _, ok := node.Fun.(*ast.FuncLit); ok {
|
||||
// Do nothing with func literals for now.
|
||||
break
|
||||
}
|
||||
|
||||
sliceMap := make(map[string]*int64)
|
||||
s.sliceCaps[node] = sliceMap
|
||||
s.setupCallArgCaps(node, ctx)
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// updateSliceCaps takes in a variable name and a map of calls we are updating the variables for to the updated values
|
||||
// and will add it to the sliceCaps map.
|
||||
func (s *sliceOutOfBounds) updateSliceCaps(varName string, caps map[*ast.CallExpr]*int64) {
|
||||
for callExpr, cap := range caps {
|
||||
s.sliceCaps[callExpr][varName] = cap
|
||||
}
|
||||
}
|
||||
|
||||
// getAllCalls returns all CallExprs that are calls to the given function.
|
||||
func (s *sliceOutOfBounds) getAllCalls(funcName string, ctx *gosec.Context) []*ast.CallExpr {
|
||||
calls := []*ast.CallExpr{}
|
||||
|
||||
for callExpr := range s.sliceCaps {
|
||||
if callExpr != nil {
|
||||
// Compare the names of the function the code is scanning with the current call we are iterating over
|
||||
_, callFuncName, err := gosec.GetCallInfo(callExpr, ctx)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if callFuncName == funcName {
|
||||
calls = append(calls, callExpr)
|
||||
}
|
||||
}
|
||||
}
|
||||
return calls
|
||||
}
|
||||
|
||||
// getSliceCapsForFunc gets all the capacities for slice with given name that are stored for each call to the passed function.
|
||||
func (s *sliceOutOfBounds) getSliceCapsForFunc(funcName string, varName string, ctx *gosec.Context) map[*ast.CallExpr]*int64 {
|
||||
caps := make(map[*ast.CallExpr]*int64)
|
||||
|
||||
calls := s.getAllCalls(funcName, ctx)
|
||||
for _, call := range calls {
|
||||
if callCaps, ok := s.sliceCaps[call]; ok {
|
||||
caps[call] = callCaps[varName]
|
||||
}
|
||||
}
|
||||
|
||||
return caps
|
||||
}
|
||||
|
||||
// setupCallArgCaps evaluates and saves the caps for any slices in the args so they can be validated when the function is scanned.
|
||||
func (s *sliceOutOfBounds) setupCallArgCaps(callExpr *ast.CallExpr, ctx *gosec.Context) {
|
||||
// Array of caps to be loaded once the function declaration is scanned
|
||||
funcCallArgs := []*int64{}
|
||||
|
||||
// Get function name
|
||||
_, funcName, err := gosec.GetCallInfo(callExpr, ctx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, arg := range callExpr.Args {
|
||||
switch node := arg.(type) {
|
||||
case *ast.SliceExpr:
|
||||
caps := s.evaluateSliceExpr(node, ctx)
|
||||
|
||||
// Simplifying assumption: use the lowest capacity. Storing all possible capacities for slices passed
|
||||
// to a function call would catch the most issues, but would require a data structure like a stack and a
|
||||
// reworking of the code for scanning itself. Use the lowest capacity, as this would be more likely to
|
||||
// raise an issue for being out of bounds.
|
||||
var lowestCap *int64
|
||||
for _, cap := range caps {
|
||||
if cap == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if lowestCap == nil {
|
||||
lowestCap = cap
|
||||
} else if *lowestCap > *cap {
|
||||
lowestCap = cap
|
||||
}
|
||||
}
|
||||
|
||||
if lowestCap == nil {
|
||||
funcCallArgs = append(funcCallArgs, nil)
|
||||
continue
|
||||
}
|
||||
|
||||
// Now create a map of just this value to add it to the sliceCaps
|
||||
funcCallArgs = append(funcCallArgs, lowestCap)
|
||||
case *ast.Ident:
|
||||
ident := arg.(*ast.Ident)
|
||||
caps := s.getSliceCapsForFunc(s.currentFuncName, ident.Name, ctx)
|
||||
|
||||
var lowestCap *int64
|
||||
for _, cap := range caps {
|
||||
if cap == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if lowestCap == nil {
|
||||
lowestCap = cap
|
||||
} else if *lowestCap > *cap {
|
||||
lowestCap = cap
|
||||
}
|
||||
}
|
||||
|
||||
if lowestCap == nil {
|
||||
funcCallArgs = append(funcCallArgs, nil)
|
||||
continue
|
||||
}
|
||||
|
||||
// Now create a map of just this value to add it to the sliceCaps
|
||||
funcCallArgs = append(funcCallArgs, lowestCap)
|
||||
default:
|
||||
funcCallArgs = append(funcCallArgs, nil)
|
||||
}
|
||||
}
|
||||
s.funcCallArgs[funcName] = funcCallArgs
|
||||
}
|
||||
|
||||
// loadArgCaps loads caps that were saved for a call to this function.
|
||||
func (s *sliceOutOfBounds) loadArgCaps(funcDecl *ast.FuncDecl) {
|
||||
sliceMap := make(map[string]*int64)
|
||||
funcName := funcDecl.Name.Name
|
||||
|
||||
// Create a dummmy call expr for the new function. This is so we can still store args for
|
||||
// functions which are not explicitly called in the code by other functions (specifically, main).
|
||||
ident := ast.NewIdent(funcName)
|
||||
dummyCallExpr := ast.CallExpr{
|
||||
Fun: ident,
|
||||
}
|
||||
|
||||
argCaps, ok := s.funcCallArgs[funcName]
|
||||
if !ok || len(argCaps) == 0 {
|
||||
s.sliceCaps[&dummyCallExpr] = sliceMap
|
||||
return
|
||||
}
|
||||
|
||||
params := funcDecl.Type.Params.List
|
||||
if len(params) > len(argCaps) {
|
||||
return // Length of params and args doesn't match, so don't do anything with this.
|
||||
}
|
||||
|
||||
for it := range params {
|
||||
capacity := argCaps[it]
|
||||
if capacity == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if len(params[it].Names) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
if paramName := params[it].Names[0]; paramName != nil {
|
||||
sliceMap[paramName.Name] = capacity
|
||||
}
|
||||
}
|
||||
|
||||
s.sliceCaps[&dummyCallExpr] = sliceMap
|
||||
}
|
||||
|
||||
// matchSliceMake matches calls to make() and stores the capacity of the new slice in the map to compare against future slice usage.
|
||||
func (s *sliceOutOfBounds) matchSliceMake(funcCall *ast.CallExpr, sliceName string, ctx *gosec.Context) (*issue.Issue, error) {
|
||||
_, funcName, err := gosec.GetCallInfo(funcCall, ctx)
|
||||
if err != nil || funcName != "make" {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var capacityArg int
|
||||
if len(funcCall.Args) < 2 {
|
||||
return nil, nil // No size passed
|
||||
} else if len(funcCall.Args) == 2 {
|
||||
capacityArg = 1
|
||||
} else if len(funcCall.Args) == 3 {
|
||||
capacityArg = 2
|
||||
} else {
|
||||
return nil, nil // Unexpected, args should always be 2 or 3
|
||||
}
|
||||
|
||||
// Check and get the capacity of the slice passed to make. It must be a literal value, since we aren't evaluating the expression.
|
||||
sliceCapLit, ok := funcCall.Args[capacityArg].(*ast.BasicLit)
|
||||
if !ok {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
capacity, err := gosec.GetInt(sliceCapLit)
|
||||
if err != nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
caps := s.getSliceCapsForFunc(s.currentFuncName, sliceName, ctx)
|
||||
for callExpr := range caps {
|
||||
caps[callExpr] = &capacity
|
||||
}
|
||||
|
||||
s.updateSliceCaps(sliceName, caps)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// evaluateSliceExpr takes a slice expression and evaluates what the capacity of said slice is for each of the
|
||||
// calls to the current function. Returns map of the call expressions of each call to the current function to
|
||||
// the evaluated capacities.
|
||||
func (s *sliceOutOfBounds) evaluateSliceExpr(node *ast.SliceExpr, ctx *gosec.Context) map[*ast.CallExpr]*int64 {
|
||||
// Get ident to get name
|
||||
ident, ok := node.X.(*ast.Ident)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get cap of old slice to calculate this new slice's cap
|
||||
caps := s.getSliceCapsForFunc(s.currentFuncName, ident.Name, ctx)
|
||||
for callExpr, oldCap := range caps {
|
||||
if oldCap == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// Get and check low value
|
||||
lowIdent, ok := node.Low.(*ast.BasicLit)
|
||||
if ok && lowIdent != nil {
|
||||
low, _ := gosec.GetInt(lowIdent)
|
||||
|
||||
newCap := *oldCap - low
|
||||
caps[callExpr] = &newCap
|
||||
} else if lowIdent == nil { // If no lower bound, capacity will be same
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
return caps
|
||||
}
|
||||
|
||||
// matchSliceAssignment matches slice assignments, calculates capacity of slice if possible to store it in map.
|
||||
func (s *sliceOutOfBounds) matchSliceAssignment(node *ast.SliceExpr, sliceName string, ctx *gosec.Context) (*issue.Issue, error) {
|
||||
// First do the normal match that verifies the slice expr is not out of bounds
|
||||
if i, err := s.matchSliceExpr(node, ctx); err != nil {
|
||||
return i, fmt.Errorf("There was an error while matching a slice expression to check slice bounds for %s: %w", sliceName, err)
|
||||
}
|
||||
|
||||
// Now that the assignment is (presumably) successfully, we can calculate the capacity and add this new slice to the map
|
||||
caps := s.evaluateSliceExpr(node, ctx)
|
||||
s.updateSliceCaps(sliceName, caps)
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// matchAssign matches checks if an assignment statement is making a slice, or if it is assigning a slice.
|
||||
func (s *sliceOutOfBounds) matchAssign(node *ast.AssignStmt, ctx *gosec.Context) (*issue.Issue, error) {
|
||||
// Check RHS for calls to make() so we can get the actual size of the slice
|
||||
for it, i := range node.Rhs {
|
||||
// Get the slice name so we can associate the cap with the slice in the map
|
||||
sliceIdent, ok := node.Lhs[it].(*ast.Ident)
|
||||
if !ok {
|
||||
return nil, nil
|
||||
}
|
||||
sliceName := sliceIdent.Name
|
||||
|
||||
switch expr := i.(type) {
|
||||
case *ast.CallExpr: // Check for and handle call to make()
|
||||
return s.matchSliceMake(expr, sliceName, ctx)
|
||||
case *ast.SliceExpr: // Handle assignments to a slice
|
||||
return s.matchSliceAssignment(expr, sliceName, ctx)
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// matchSliceExpr validates that a given slice expression (eg, slice[10:30]) is not out of bounds.
|
||||
func (s *sliceOutOfBounds) matchSliceExpr(node *ast.SliceExpr, ctx *gosec.Context) (*issue.Issue, error) {
|
||||
// First get the slice name so we can check the size in our map
|
||||
ident, ok := node.X.(*ast.Ident)
|
||||
if !ok {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Get slice cap from the map to compare it against high and low
|
||||
caps := s.getSliceCapsForFunc(s.currentFuncName, ident.Name, ctx)
|
||||
|
||||
for _, cap := range caps {
|
||||
if cap == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// Get and check high value
|
||||
highIdent, ok := node.High.(*ast.BasicLit)
|
||||
if ok && highIdent != nil {
|
||||
high, _ := gosec.GetInt(highIdent)
|
||||
if high > *cap {
|
||||
return ctx.NewIssue(node, s.ID(), s.What, s.Severity, s.Confidence), nil
|
||||
}
|
||||
}
|
||||
|
||||
// Get and check low value
|
||||
lowIdent, ok := node.Low.(*ast.BasicLit)
|
||||
if ok && lowIdent != nil {
|
||||
low, _ := gosec.GetInt(lowIdent)
|
||||
if low > *cap {
|
||||
return ctx.NewIssue(node, s.ID(), s.What, s.Severity, s.Confidence), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// matchIndexExpr validates that an index into a slice is not out of bounds.
|
||||
func (s *sliceOutOfBounds) matchIndexExpr(node *ast.IndexExpr, ctx *gosec.Context) (*issue.Issue, error) {
|
||||
// First get the slice name so we can check the size in our map
|
||||
ident, ok := node.X.(*ast.Ident)
|
||||
if !ok {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Get slice cap from the map to compare it against high and low
|
||||
caps := s.getSliceCapsForFunc(s.currentFuncName, ident.Name, ctx)
|
||||
|
||||
for _, cap := range caps {
|
||||
if cap == nil {
|
||||
continue
|
||||
}
|
||||
// Get the index literal
|
||||
indexIdent, ok := node.Index.(*ast.BasicLit)
|
||||
if ok && indexIdent != nil {
|
||||
index, _ := gosec.GetInt(indexIdent)
|
||||
if index >= *cap {
|
||||
return ctx.NewIssue(node, s.ID(), s.What, s.Severity, s.Confidence), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// NewSliceBoundCheck attempts to find any slices being accessed out of bounds
|
||||
// by reslicing or by being indexed.
|
||||
func NewSliceBoundCheck(id string, _ gosec.Config) (gosec.Rule, []ast.Node) {
|
||||
sliceMap := make(map[*ast.CallExpr]map[string]*int64)
|
||||
|
||||
return &sliceOutOfBounds{
|
||||
sliceCaps: sliceMap,
|
||||
currentFuncName: "",
|
||||
funcCallArgs: make(map[string][]*int64),
|
||||
MetaData: issue.MetaData{
|
||||
ID: id,
|
||||
Severity: issue.Medium,
|
||||
Confidence: issue.Medium,
|
||||
What: "Potentially accessing slice out of bounds",
|
||||
},
|
||||
}, []ast.Node{(*ast.CallExpr)(nil), (*ast.FuncDecl)(nil), (*ast.AssignStmt)(nil), (*ast.SliceExpr)(nil), (*ast.IndexExpr)(nil)}
|
||||
}
|
||||
2
vendor/github.com/securego/gosec/v2/rules/unsafe.go
generated
vendored
2
vendor/github.com/securego/gosec/v2/rules/unsafe.go
generated
vendored
@@ -43,7 +43,7 @@ func (r *usingUnsafe) Match(n ast.Node, c *gosec.Context) (gi *issue.Issue, err
|
||||
func NewUsingUnsafe(id string, _ gosec.Config) (gosec.Rule, []ast.Node) {
|
||||
return &usingUnsafe{
|
||||
pkg: "unsafe",
|
||||
calls: []string{"Alignof", "Offsetof", "Sizeof", "Pointer"},
|
||||
calls: []string{"Pointer", "String", "StringData", "Slice", "SliceData"},
|
||||
MetaData: issue.MetaData{
|
||||
ID: id,
|
||||
What: "Use of unsafe calls should be audited",
|
||||
|
||||
4
vendor/golang.org/x/mod/modfile/rule.go
generated
vendored
4
vendor/golang.org/x/mod/modfile/rule.go
generated
vendored
@@ -367,7 +367,7 @@ func (f *File) add(errs *ErrorList, block *LineBlock, line *Line, verb string, a
|
||||
}
|
||||
}
|
||||
if !fixed {
|
||||
errorf("invalid go version '%s': must match format 1.23", args[0])
|
||||
errorf("invalid go version '%s': must match format 1.23.0", args[0])
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -384,7 +384,7 @@ func (f *File) add(errs *ErrorList, block *LineBlock, line *Line, verb string, a
|
||||
errorf("toolchain directive expects exactly one argument")
|
||||
return
|
||||
} else if strict && !ToolchainRE.MatchString(args[0]) {
|
||||
errorf("invalid toolchain version '%s': must match format go1.23 or local", args[0])
|
||||
errorf("invalid toolchain version '%s': must match format go1.23.0 or local", args[0])
|
||||
return
|
||||
}
|
||||
f.Toolchain = &Toolchain{Syntax: line}
|
||||
|
||||
5
vendor/golang.org/x/tools/cmd/stringer/stringer.go
generated
vendored
5
vendor/golang.org/x/tools/cmd/stringer/stringer.go
generated
vendored
@@ -188,6 +188,8 @@ type Generator struct {
|
||||
|
||||
trimPrefix string
|
||||
lineComment bool
|
||||
|
||||
logf func(format string, args ...interface{}) // test logging hook; nil when not testing
|
||||
}
|
||||
|
||||
func (g *Generator) Printf(format string, args ...interface{}) {
|
||||
@@ -221,13 +223,14 @@ func (g *Generator) parsePackage(patterns []string, tags []string) {
|
||||
// in a separate pass? For later.
|
||||
Tests: false,
|
||||
BuildFlags: []string{fmt.Sprintf("-tags=%s", strings.Join(tags, " "))},
|
||||
Logf: g.logf,
|
||||
}
|
||||
pkgs, err := packages.Load(cfg, patterns...)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if len(pkgs) != 1 {
|
||||
log.Fatalf("error: %d packages found", len(pkgs))
|
||||
log.Fatalf("error: %d packages matching %v", len(pkgs), strings.Join(patterns, " "))
|
||||
}
|
||||
g.addPackage(pkgs[0])
|
||||
}
|
||||
|
||||
2
vendor/golang.org/x/tools/go/analysis/doc.go
generated
vendored
2
vendor/golang.org/x/tools/go/analysis/doc.go
generated
vendored
@@ -191,7 +191,7 @@ and buildtag, inspect the raw text of Go source files or even non-Go
|
||||
files such as assembly. To report a diagnostic against a line of a
|
||||
raw text file, use the following sequence:
|
||||
|
||||
content, err := ioutil.ReadFile(filename)
|
||||
content, err := os.ReadFile(filename)
|
||||
if err != nil { ... }
|
||||
tf := fset.AddFile(filename, -1, len(content))
|
||||
tf.SetLinesForContent(content)
|
||||
|
||||
2
vendor/golang.org/x/tools/go/packages/doc.go
generated
vendored
2
vendor/golang.org/x/tools/go/packages/doc.go
generated
vendored
@@ -35,7 +35,7 @@ The Package struct provides basic information about the package, including
|
||||
- Imports, a map from source import strings to the Packages they name;
|
||||
- Types, the type information for the package's exported symbols;
|
||||
- Syntax, the parsed syntax trees for the package's source code; and
|
||||
- TypeInfo, the result of a complete type-check of the package syntax trees.
|
||||
- TypesInfo, the result of a complete type-check of the package syntax trees.
|
||||
|
||||
(See the documentation for type Package for the complete list of fields
|
||||
and more detailed descriptions.)
|
||||
|
||||
7
vendor/golang.org/x/tools/go/packages/golist.go
generated
vendored
7
vendor/golang.org/x/tools/go/packages/golist.go
generated
vendored
@@ -9,7 +9,6 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
@@ -1109,7 +1108,7 @@ func (state *golistState) writeOverlays() (filename string, cleanup func(), err
|
||||
if len(state.cfg.Overlay) == 0 {
|
||||
return "", func() {}, nil
|
||||
}
|
||||
dir, err := ioutil.TempDir("", "gopackages-*")
|
||||
dir, err := os.MkdirTemp("", "gopackages-*")
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
@@ -1128,7 +1127,7 @@ func (state *golistState) writeOverlays() (filename string, cleanup func(), err
|
||||
// Create a unique filename for the overlaid files, to avoid
|
||||
// creating nested directories.
|
||||
noSeparator := strings.Join(strings.Split(filepath.ToSlash(k), "/"), "")
|
||||
f, err := ioutil.TempFile(dir, fmt.Sprintf("*-%s", noSeparator))
|
||||
f, err := os.CreateTemp(dir, fmt.Sprintf("*-%s", noSeparator))
|
||||
if err != nil {
|
||||
return "", func() {}, err
|
||||
}
|
||||
@@ -1146,7 +1145,7 @@ func (state *golistState) writeOverlays() (filename string, cleanup func(), err
|
||||
}
|
||||
// Write out the overlay file that contains the filepath mappings.
|
||||
filename = filepath.Join(dir, "overlay.json")
|
||||
if err := ioutil.WriteFile(filename, b, 0665); err != nil {
|
||||
if err := os.WriteFile(filename, b, 0665); err != nil {
|
||||
return "", func() {}, err
|
||||
}
|
||||
return filename, cleanup, nil
|
||||
|
||||
3
vendor/golang.org/x/tools/go/packages/packages.go
generated
vendored
3
vendor/golang.org/x/tools/go/packages/packages.go
generated
vendored
@@ -16,7 +16,6 @@ import (
|
||||
"go/token"
|
||||
"go/types"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@@ -1127,7 +1126,7 @@ func (ld *loader) parseFile(filename string) (*ast.File, error) {
|
||||
var err error
|
||||
if src == nil {
|
||||
ioLimit <- true // wait
|
||||
src, err = ioutil.ReadFile(filename)
|
||||
src, err = os.ReadFile(filename)
|
||||
<-ioLimit // signal
|
||||
}
|
||||
if err != nil {
|
||||
|
||||
3
vendor/golang.org/x/tools/internal/gcimporter/gcimporter.go
generated
vendored
3
vendor/golang.org/x/tools/internal/gcimporter/gcimporter.go
generated
vendored
@@ -29,7 +29,6 @@ import (
|
||||
"go/token"
|
||||
"go/types"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
@@ -221,7 +220,7 @@ func Import(packages map[string]*types.Package, path, srcDir string, lookup func
|
||||
switch hdr {
|
||||
case "$$B\n":
|
||||
var data []byte
|
||||
data, err = ioutil.ReadAll(buf)
|
||||
data, err = io.ReadAll(buf)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
|
||||
16
vendor/modules.txt
generated
vendored
16
vendor/modules.txt
generated
vendored
@@ -449,7 +449,7 @@ github.com/google/pprof/profile
|
||||
# github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
|
||||
## explicit; go 1.13
|
||||
github.com/google/shlex
|
||||
# github.com/google/uuid v1.3.0
|
||||
# github.com/google/uuid v1.3.1
|
||||
## explicit
|
||||
github.com/google/uuid
|
||||
# github.com/gookit/color v1.5.4
|
||||
@@ -603,7 +603,7 @@ github.com/onsi/ginkgo/formatter
|
||||
github.com/onsi/ginkgo/reporters
|
||||
github.com/onsi/ginkgo/reporters/stenographer
|
||||
github.com/onsi/ginkgo/types
|
||||
# github.com/onsi/ginkgo/v2 v2.12.1
|
||||
# github.com/onsi/ginkgo/v2 v2.13.0
|
||||
## explicit; go 1.18
|
||||
github.com/onsi/ginkgo/v2
|
||||
github.com/onsi/ginkgo/v2/config
|
||||
@@ -625,7 +625,7 @@ github.com/onsi/ginkgo/v2/internal/parallel_support
|
||||
github.com/onsi/ginkgo/v2/internal/testingtproxy
|
||||
github.com/onsi/ginkgo/v2/reporters
|
||||
github.com/onsi/ginkgo/v2/types
|
||||
# github.com/onsi/gomega v1.27.10
|
||||
# github.com/onsi/gomega v1.28.1
|
||||
## explicit; go 1.18
|
||||
github.com/onsi/gomega
|
||||
github.com/onsi/gomega/format
|
||||
@@ -779,7 +779,7 @@ github.com/russross/blackfriday
|
||||
# github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06
|
||||
## explicit; go 1.13
|
||||
github.com/sabhiram/go-gitignore
|
||||
# github.com/securego/gosec/v2 v2.17.0
|
||||
# github.com/securego/gosec/v2 v2.18.2
|
||||
## explicit; go 1.20
|
||||
github.com/securego/gosec/v2
|
||||
github.com/securego/gosec/v2/analyzers
|
||||
@@ -898,8 +898,8 @@ golang.org/x/crypto/ssh
|
||||
golang.org/x/crypto/ssh/agent
|
||||
golang.org/x/crypto/ssh/internal/bcrypt_pbkdf
|
||||
golang.org/x/crypto/ssh/knownhosts
|
||||
# golang.org/x/mod v0.12.0
|
||||
## explicit; go 1.17
|
||||
# golang.org/x/mod v0.13.0
|
||||
## explicit; go 1.18
|
||||
golang.org/x/mod/internal/lazyregexp
|
||||
golang.org/x/mod/modfile
|
||||
golang.org/x/mod/module
|
||||
@@ -921,7 +921,7 @@ golang.org/x/net/proxy
|
||||
## explicit; go 1.17
|
||||
golang.org/x/oauth2
|
||||
golang.org/x/oauth2/internal
|
||||
# golang.org/x/sync v0.3.0
|
||||
# golang.org/x/sync v0.4.0
|
||||
## explicit; go 1.17
|
||||
golang.org/x/sync/errgroup
|
||||
golang.org/x/sync/semaphore
|
||||
@@ -964,7 +964,7 @@ golang.org/x/text/width
|
||||
# golang.org/x/time v0.3.0
|
||||
## explicit
|
||||
golang.org/x/time/rate
|
||||
# golang.org/x/tools v0.13.0
|
||||
# golang.org/x/tools v0.14.0
|
||||
## explicit; go 1.18
|
||||
golang.org/x/tools/cmd/stringer
|
||||
golang.org/x/tools/go/analysis
|
||||
|
||||
Reference in New Issue
Block a user