Add Semgrep Rules to OSS (#14513)
* add semgrep yml * add semgrep ci job * remove replication semgrep rule in oss * fix makefile * add semgrep to ci * upwind triple if in ui.go semgrep refactoring
This commit is contained in:
parent
07044fd701
commit
7e0abe3c7e
|
@ -798,6 +798,28 @@ jobs:
|
|||
environment:
|
||||
- CIRCLECI_CLI_VERSION: 0.1.5546
|
||||
- GO_TAGS: ''
|
||||
semgrep:
|
||||
docker:
|
||||
- image: docker.mirror.hashicorp.services/alpine:3.13
|
||||
shell: /bin/sh
|
||||
working_directory: /home/circleci/go/src/github.com/hashicorp/vault
|
||||
steps:
|
||||
- run:
|
||||
command: |
|
||||
apk add --no-cache python3 py3-pip make
|
||||
python3 -m pip install --user semgrep
|
||||
export PATH="$HOME/.local/bin:$PATH"
|
||||
|
||||
echo "$ semgrep --version"
|
||||
semgrep --version
|
||||
name: Setup Semgrep
|
||||
working_directory: ~/
|
||||
- checkout
|
||||
- attach_workspace:
|
||||
at: .
|
||||
- run:
|
||||
command: "# Alpine images can't run the make file due to a bash requirement. Run\n# semgrep explicitly here. \nexport PATH=\"$HOME/.local/bin:$PATH\" \nsemgrep --error --include '*.go' --exclude 'vendor' -f tools/semgrep/ci .\n"
|
||||
name: Run Semgrep Rules
|
||||
pre-flight-checks:
|
||||
machine: true
|
||||
shell: /usr/bin/env bash -euo pipefail -c
|
||||
|
@ -1127,4 +1149,7 @@ workflows:
|
|||
only:
|
||||
- stable-website
|
||||
context: vault-docs
|
||||
- semgrep:
|
||||
requires:
|
||||
- pre-flight-checks
|
||||
version: 2
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
---
|
||||
description: >
|
||||
Ensure semgrep is installed.
|
||||
steps:
|
||||
- run:
|
||||
working_directory: ~/
|
||||
name: Setup Semgrep
|
||||
command: |
|
||||
apk add --no-cache python3 py3-pip make
|
||||
python3 -m pip install --user semgrep
|
||||
export PATH="$HOME/.local/bin:$PATH"
|
||||
|
||||
echo "$ semgrep --version"
|
||||
semgrep --version
|
|
@ -0,0 +1,14 @@
|
|||
---
|
||||
executor: alpine
|
||||
steps:
|
||||
- setup-semgrep
|
||||
- checkout
|
||||
- attach_workspace:
|
||||
at: .
|
||||
- run:
|
||||
name: Run Semgrep Rules
|
||||
command: |
|
||||
# Alpine images can't run the make file due to a bash requirement. Run
|
||||
# semgrep explicitly here.
|
||||
export PATH="$HOME/.local/bin:$PATH"
|
||||
semgrep --error --include '*.go' --exclude 'vendor' -f tools/semgrep/ci .
|
|
@ -50,3 +50,6 @@ jobs:
|
|||
branches:
|
||||
only:
|
||||
- stable-website
|
||||
- semgrep:
|
||||
requires:
|
||||
- pre-flight-checks
|
||||
|
|
8
Makefile
8
Makefile
|
@ -214,6 +214,12 @@ fmtcheck:
|
|||
fmt:
|
||||
find . -name '*.go' | grep -v pb.go | grep -v vendor | xargs gofumpt -w
|
||||
|
||||
semgrep:
|
||||
semgrep --include '*.go' --exclude 'vendor' -a -f tools/semgrep .
|
||||
|
||||
semgrep-ci:
|
||||
semgrep --error --include '*.go' --exclude 'vendor' -f tools/semgrep/ci .
|
||||
|
||||
assetcheck:
|
||||
@echo "==> Checking compiled UI assets..."
|
||||
@sh -c "'$(CURDIR)/scripts/assetcheck.sh'"
|
||||
|
@ -253,7 +259,7 @@ ci-config:
|
|||
ci-verify:
|
||||
@$(MAKE) -C .circleci ci-verify
|
||||
|
||||
.PHONY: bin default prep test vet bootstrap ci-bootstrap fmt fmtcheck mysql-database-plugin mysql-legacy-database-plugin cassandra-database-plugin influxdb-database-plugin postgresql-database-plugin mssql-database-plugin hana-database-plugin mongodb-database-plugin ember-dist ember-dist-dev static-dist static-dist-dev assetcheck check-vault-in-path check-browserstack-creds test-ui-browserstack packages build build-ci
|
||||
.PHONY: bin default prep test vet bootstrap ci-bootstrap fmt fmtcheck mysql-database-plugin mysql-legacy-database-plugin cassandra-database-plugin influxdb-database-plugin postgresql-database-plugin mssql-database-plugin hana-database-plugin mongodb-database-plugin ember-dist ember-dist-dev static-dist static-dist-dev assetcheck check-vault-in-path check-browserstack-creds test-ui-browserstack packages build build-ci semgrep semgrep-ci
|
||||
|
||||
.NOTPARALLEL: ember-dist ember-dist-dev
|
||||
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
set -x
|
||||
|
||||
## Make a temp dir
|
||||
tempdir=$(mktemp -d plugin-semgrep.XXXXXX)
|
||||
vaultdir=$(pwd)
|
||||
## Set paths
|
||||
cd $tempdir
|
||||
|
||||
for plugin in $(grep github.com/hashicorp/vault-plugin- $vaultdir/go.mod | cut -f 2 | cut -d ' ' -f 1 | cut -d '/' -f 3)
|
||||
do
|
||||
if [ -z $SKIP_MODULE_UPDATING ]
|
||||
then
|
||||
echo "Fetching $plugin..."
|
||||
git clone https://github.com/hashicorp/$plugin
|
||||
semgrep --include '*.go' --exclude 'vendor' -a -f $vaultdir/tools/semgrep/ci/ $plugin/. > $plugin.semgrep.txt
|
||||
fi
|
||||
done
|
|
@ -0,0 +1,17 @@
|
|||
rules:
|
||||
- id: atomics-64bit-safety
|
||||
patterns:
|
||||
- pattern: |
|
||||
type $TYPE struct {
|
||||
...
|
||||
$VAR atomic.$ATOMIC_TYPE
|
||||
...
|
||||
}
|
||||
- metavariable-regex:
|
||||
# We only care about 64 bit atomic types
|
||||
metavariable: "$ATOMIC_TYPE"
|
||||
regex: ".*64"
|
||||
message: "Use pointers with member variables of uber-go/atomic types"
|
||||
languages: [go]
|
||||
severity: ERROR
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
rules:
|
||||
- id: bad-multierror-append
|
||||
patterns:
|
||||
- pattern-either:
|
||||
- pattern: $ERR = multierror.Append($ERRORS, $ERR)
|
||||
- pattern: $ERR = multierror.Append($ERR, $ERR)
|
||||
- pattern: $ERRORS = multierror.Append($ERR, $ERR)
|
||||
- pattern: $ERRORS = multierror.Append($ERR, $ERRORS)
|
||||
message: Bad Multierror Append
|
||||
languages:
|
||||
- go
|
||||
severity: ERROR
|
||||
metadata:
|
||||
license: MIT
|
|
@ -0,0 +1,17 @@
|
|||
rules:
|
||||
- id: bad-nil-guard
|
||||
patterns:
|
||||
- pattern-either:
|
||||
- pattern: $X == nil && <... $X.$F ...>
|
||||
- pattern: $X != nil || <... $X.$F ...>
|
||||
- pattern: <... $X.$F ...> && $X != nil
|
||||
- pattern: <... $X.$F ...> || $X == nil
|
||||
- pattern: <... $X.$F ...> && $X == nil
|
||||
- pattern: <... $X.$F ...> || $X != nil
|
||||
message: Bad nil guard
|
||||
languages:
|
||||
- go
|
||||
severity: ERROR
|
||||
metadata:
|
||||
license: MIT
|
||||
|
|
@ -0,0 +1,123 @@
|
|||
rules:
|
||||
- id: error-shadow-check-types
|
||||
patterns:
|
||||
- pattern: |
|
||||
..., ($ERR: error) = $FUNC(...)
|
||||
...
|
||||
..., $ERR = ...
|
||||
- pattern-not: |
|
||||
..., ($ERR: error) = $FUNC(...)
|
||||
...
|
||||
if <... $ERR == nil ...> {
|
||||
...
|
||||
}
|
||||
...
|
||||
..., $ERR = ...
|
||||
- pattern-not: |
|
||||
..., ($ERR: error) = $FUNC(...)
|
||||
...
|
||||
if <... $ERR != nil ...> {
|
||||
...
|
||||
}
|
||||
...
|
||||
..., $ERR = ...
|
||||
- pattern-not: |
|
||||
..., ($ERR: error) = $FUNC(...)
|
||||
...
|
||||
$ERRCHECK(..., $ERR, ...)
|
||||
...
|
||||
..., $ERR = ...
|
||||
# This case is not specific enough but semgrep doesn't let you do any
|
||||
# special searching within a switch statement. We will assume if there
|
||||
# is a switch statement it's doing error checking, though this isn't
|
||||
# guaranteed.
|
||||
- pattern-not: |
|
||||
..., ($ERR: error) = $FUNC(...)
|
||||
...
|
||||
switch {
|
||||
case ...
|
||||
}
|
||||
...
|
||||
..., $ERR = ...
|
||||
message: Potential Error Shadowing
|
||||
languages:
|
||||
- go
|
||||
severity: ERROR
|
||||
|
||||
|
||||
- id: error-shadow-check-regex
|
||||
patterns:
|
||||
- pattern: |
|
||||
..., $ERR = $FUNC(...)
|
||||
...
|
||||
..., $ERR = ...
|
||||
- pattern-not: |
|
||||
..., $ERR = $FUNC(...)
|
||||
...
|
||||
if <... $ERR == nil ...> {
|
||||
...
|
||||
}
|
||||
...
|
||||
..., $ERR = ...
|
||||
- pattern-not: |
|
||||
..., $ERR = $FUNC(...)
|
||||
...
|
||||
if <... $ERR != nil ...> {
|
||||
...
|
||||
}
|
||||
...
|
||||
..., $ERR = ...
|
||||
- pattern-not: |
|
||||
..., $ERR = $FUNC(...)
|
||||
...
|
||||
$ERRCHECK(..., $ERR, ...)
|
||||
...
|
||||
..., $ERR = ...
|
||||
|
||||
# This pattern is used in as a itteration mechanism for a test
|
||||
- pattern-not: |
|
||||
..., $ERR = $FUNC(...)
|
||||
...
|
||||
for $ERR == nil {
|
||||
...
|
||||
}
|
||||
...
|
||||
..., $ERR = ...
|
||||
|
||||
# A few places we test against logical.Err* types
|
||||
- pattern-not: |
|
||||
..., $ERR = $FUNC(...)
|
||||
...
|
||||
if $ERR != logical.$ERRTYPE {
|
||||
...
|
||||
}
|
||||
...
|
||||
..., $ERR = ...
|
||||
# This case is not specific enough but semgrep doesn't let you do any
|
||||
# special searching within a switch statement. We will assume if there
|
||||
# is a switch statement it's doing error checking, though this isn't
|
||||
# guaranteed.
|
||||
- pattern-not: |
|
||||
..., $ERR = $FUNC(...)
|
||||
...
|
||||
switch ... {
|
||||
case ...
|
||||
}
|
||||
...
|
||||
..., $ERR = ...
|
||||
- pattern-not: |
|
||||
..., $ERR = $FUNC(...)
|
||||
...
|
||||
switch {
|
||||
case ...
|
||||
}
|
||||
...
|
||||
..., $ERR = ...
|
||||
- metavariable-regex:
|
||||
metavariable: $ERR
|
||||
regex: "err"
|
||||
message: Potential Error Shadowing (regex)
|
||||
languages:
|
||||
- go
|
||||
severity: ERROR
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
rules:
|
||||
- id: hash-sum-without-write
|
||||
patterns:
|
||||
- pattern-either:
|
||||
- pattern: |
|
||||
$HASH.New().Sum($SLICE)
|
||||
- pattern: |
|
||||
$H := $HASH.New()
|
||||
...
|
||||
$H.Sum($SLICE)
|
||||
- pattern-not: |
|
||||
$H := $HASH.New()
|
||||
...
|
||||
$H.Write(...)
|
||||
...
|
||||
$H.Sum($SLICE)
|
||||
- pattern-not: |
|
||||
$H := $HASH.New()
|
||||
...
|
||||
$FUNC(..., $H, ...)
|
||||
...
|
||||
$H.Sum($SLICE)
|
||||
message: "odd hash.Sum call flow"
|
||||
languages: [go]
|
||||
severity: ERROR
|
|
@ -0,0 +1,19 @@
|
|||
rules:
|
||||
- id: use-hmac-equal
|
||||
patterns:
|
||||
- pattern-either:
|
||||
- pattern: |
|
||||
$MAC = hmac.New(...)
|
||||
...
|
||||
$H = $MAC.Sum(...)
|
||||
...
|
||||
bytes.Equal($H, ...)
|
||||
- pattern: |
|
||||
$MAC = hmac.New(...)
|
||||
...
|
||||
$H = $MAC.Sum(...)
|
||||
...
|
||||
bytes.Equal(..., $H)
|
||||
message: "Comparing a MAC with bytes.Equal()"
|
||||
languages: [go]
|
||||
severity: ERROR
|
|
@ -0,0 +1,21 @@
|
|||
rules:
|
||||
- id: hmac-needs-new
|
||||
patterns:
|
||||
- pattern-either:
|
||||
- pattern: |
|
||||
$H := $HASH.New()
|
||||
...
|
||||
$FUNC := func() hash.Hash { return $H }
|
||||
...
|
||||
hmac.New($FUNC, ...)
|
||||
- pattern: |
|
||||
$H := $HASH.New()
|
||||
...
|
||||
hmac.New(func() hash.Hash { return $H }, ...)
|
||||
|
||||
- pattern: |
|
||||
hmac.New(func() hash.Hash { return ( $H : hash.Hash) }, ...)
|
||||
|
||||
message: "calling hmac.New with unchanging hash.New"
|
||||
languages: [go]
|
||||
severity: ERROR
|
|
@ -0,0 +1,22 @@
|
|||
rules:
|
||||
- id: logger-used-with-format-string
|
||||
patterns:
|
||||
- pattern-either:
|
||||
- pattern: |
|
||||
$LOGGER.Trace("=~/.*%[v#T%tbcdoOqxXUbeEfFgGps].*/",...)
|
||||
- pattern: |
|
||||
$LOGGER.Debug("=~/.*%[v#T%tbcdoOqxXUbeEfFgGps].*/",...)
|
||||
- pattern: |
|
||||
$LOGGER.Info("=~/.*%[v#T%tbcdoOqxXUbeEfFgGps].*/",...)
|
||||
- pattern: |
|
||||
$LOGGER.Warn("=~/.*%[v#T%tbcdoOqxXUbeEfFgGps].*/",...)
|
||||
- pattern: |
|
||||
$LOGGER.Error("=~/.*%[v#T%tbcdoOqxXUbeEfFgGps].*/",...)
|
||||
- pattern-inside: |
|
||||
import $LOG "github.com/hashicorp/go-hclog"
|
||||
...
|
||||
message: "Logger message looks like format string"
|
||||
languages: [go]
|
||||
severity: ERROR
|
||||
|
||||
|
|
@ -0,0 +1,147 @@
|
|||
rules:
|
||||
- id: nil-check-logical-storage
|
||||
patterns:
|
||||
- pattern-either:
|
||||
- pattern: |
|
||||
$VAR, $ERR = ($S : logical.Storage).Get(...)
|
||||
...
|
||||
$VAR.$FOO
|
||||
- pattern: |
|
||||
$VAR, $ERR = ($S : logical.Storage).Get(...)
|
||||
...
|
||||
$FUNC2(..., $VAR, ...)
|
||||
- pattern-not: |
|
||||
$VAR, $ERR = ($S : logical.Storage).Get(...)
|
||||
...
|
||||
if <... $VAR == nil ...> {
|
||||
...
|
||||
}
|
||||
...
|
||||
- pattern-not: |
|
||||
$VAR, $ERR = ($S : logical.Storage).Get(...)
|
||||
...
|
||||
if <... $VAR != nil ...> {
|
||||
...
|
||||
}
|
||||
...
|
||||
message: missed nil check
|
||||
languages:
|
||||
- go
|
||||
severity: ERROR
|
||||
|
||||
|
||||
# physical.Storage.Get
|
||||
- id: nil-check-physical-storage
|
||||
patterns:
|
||||
- pattern-either:
|
||||
- pattern: |
|
||||
$VAR, $ERR = ($S : physical.Storage).Get(...)
|
||||
...
|
||||
$VAR.$FOO
|
||||
- pattern: |
|
||||
$VAR, $ERR = ($S : physical.Storage).Get(...)
|
||||
...
|
||||
$FUNC2(..., $VAR, ...)
|
||||
- pattern-not: |
|
||||
$VAR, $ERR = ($S : physical.Storage).Get(...)
|
||||
...
|
||||
if <... $VAR == nil ...> {
|
||||
...
|
||||
}
|
||||
...
|
||||
- pattern-not: |
|
||||
$VAR, $ERR = ($S : physical.Storage).Get(...)
|
||||
...
|
||||
if <... $VAR != nil ...> {
|
||||
...
|
||||
}
|
||||
...
|
||||
message: missed nil check
|
||||
languages:
|
||||
- go
|
||||
severity: ERROR
|
||||
|
||||
# NamespaceByID
|
||||
- id: nil-check-physical-storage
|
||||
patterns:
|
||||
- pattern-either:
|
||||
- pattern: |
|
||||
$VAR, $ERR = NamespaceByID(...)
|
||||
...
|
||||
$VAR.$FOO
|
||||
- pattern: |
|
||||
$VAR, $ERR = NamespaceByID(...)
|
||||
...
|
||||
$FUNC2(..., $VAR, ...)
|
||||
- pattern-not: |
|
||||
$VAR, $ERR = NamespaceByID(...)
|
||||
...
|
||||
if <... $VAR == nil ...> {
|
||||
...
|
||||
}
|
||||
...
|
||||
- pattern-not: |
|
||||
$VAR, $ERR = NamespaceByID(...)
|
||||
...
|
||||
if <... $VAR != nil ...> {
|
||||
...
|
||||
}
|
||||
...
|
||||
# this is a special case for custom nil namespace handling logic in
|
||||
# activity log
|
||||
- pattern-not: |
|
||||
$VAR, $ERR = NamespaceByID(...)
|
||||
...
|
||||
if a.includeInResponse(..., $VAR) {
|
||||
...
|
||||
}
|
||||
...
|
||||
message: missed nil check
|
||||
languages:
|
||||
- go
|
||||
severity: ERROR
|
||||
|
||||
- id: nil-check-logical-storage-regex
|
||||
paths:
|
||||
exclude:
|
||||
# This file has a valid case that I couldn't work around easily in the
|
||||
# semgrep rule. Ignore it for now
|
||||
- "vault/ui.go"
|
||||
patterns:
|
||||
- pattern-either:
|
||||
- pattern: |
|
||||
$VAR, $ERR = $STORAGE.Get(...)
|
||||
...
|
||||
$VAR.$FOO
|
||||
- pattern: |
|
||||
$VAR, $ERR = $STORAGE.Get(...)
|
||||
...
|
||||
$FUNC2(..., $VAR, ...)
|
||||
- pattern-not: |
|
||||
$VAR, $ERR = $STORAGE.Get(...)
|
||||
...
|
||||
if <... $VAR == nil ...> {
|
||||
...
|
||||
}
|
||||
...
|
||||
- pattern-not: |
|
||||
$VAR, $ERR = $STORAGE.Get(...)
|
||||
...
|
||||
if <... $VAR != nil ...> {
|
||||
...
|
||||
}
|
||||
...
|
||||
- pattern-not: |
|
||||
$VAR, $ERR = $STORAGE.Get(...)
|
||||
...
|
||||
switch $VAR {
|
||||
case ...
|
||||
}
|
||||
...
|
||||
- metavariable-regex:
|
||||
metavariable: $STORAGE
|
||||
regex: ((.*)Storage|(.*)\.s|(.*)\.barrier|(.*)\.view|(.*)\.barrierView|(.*)\.physical|(.*)\.underlying)
|
||||
message: missed nil check
|
||||
languages:
|
||||
- go
|
||||
severity: ERROR
|
|
@ -0,0 +1,95 @@
|
|||
rules:
|
||||
- id: odd-sequence-ifs
|
||||
patterns:
|
||||
- pattern-either:
|
||||
- pattern: |
|
||||
if $X { return ... }
|
||||
if $X { ... }
|
||||
- pattern: |
|
||||
if ! $X { return ... }
|
||||
if $X { ... }
|
||||
- pattern: |
|
||||
if $X { return ... }
|
||||
if ! $X { ... }
|
||||
- pattern: |
|
||||
if $X == $Y { return ... }
|
||||
if $X != $Y { ... }
|
||||
- pattern: |
|
||||
if $X != $Y { return ... }
|
||||
if $X == $Y { ... }
|
||||
- pattern: |
|
||||
if $X { return ... }
|
||||
for $X { ... }
|
||||
- pattern: |
|
||||
if $X {
|
||||
if $X { ... }
|
||||
...
|
||||
}
|
||||
- pattern: |
|
||||
if $X {
|
||||
if ! $X { ... }
|
||||
...
|
||||
}
|
||||
- pattern: |
|
||||
if ! $X {
|
||||
if $X { ... }
|
||||
...
|
||||
}
|
||||
- pattern: |
|
||||
if $X == $Y {
|
||||
if $X != $Y { ... }
|
||||
...
|
||||
}
|
||||
- pattern: |
|
||||
if $X != $Y {
|
||||
if $X == $Y { ... }
|
||||
...
|
||||
}
|
||||
- pattern: |
|
||||
if $X {
|
||||
for ! $X { ... }
|
||||
...
|
||||
}
|
||||
- pattern: |
|
||||
if ! $X {
|
||||
for $X { ... }
|
||||
...
|
||||
}
|
||||
- pattern: |
|
||||
if $X == $Y {
|
||||
for $X != $Y { ... }
|
||||
...
|
||||
}
|
||||
- pattern: |
|
||||
if $X != $Y {
|
||||
for $X == $Y { ... }
|
||||
...
|
||||
}
|
||||
- pattern: |
|
||||
for $X {
|
||||
if $X { ... }
|
||||
...
|
||||
}
|
||||
- pattern: |
|
||||
for $X {
|
||||
if ! $X { ... }
|
||||
...
|
||||
}
|
||||
- pattern: |
|
||||
for ! $X {
|
||||
if $X { ... }
|
||||
...
|
||||
}
|
||||
- pattern: |
|
||||
for $X == $Y {
|
||||
if $X != $Y { ... }
|
||||
...
|
||||
}
|
||||
- pattern: |
|
||||
for $X != $Y {
|
||||
if $X == $Y { ... }
|
||||
...
|
||||
}
|
||||
message: "Odd sequence of ifs"
|
||||
languages: [go]
|
||||
severity: ERROR
|
|
@ -0,0 +1,18 @@
|
|||
rules:
|
||||
- id: return-nil
|
||||
patterns:
|
||||
- pattern-either:
|
||||
- pattern: |
|
||||
if err == nil {
|
||||
return err
|
||||
}
|
||||
- pattern: |
|
||||
if err == nil {
|
||||
return ..., err
|
||||
}
|
||||
message: return nil err instead of nil value
|
||||
languages:
|
||||
- go
|
||||
severity: ERROR
|
||||
metadata:
|
||||
license: MIT
|
|
@ -0,0 +1,19 @@
|
|||
rules:
|
||||
- id: return-nil
|
||||
patterns:
|
||||
- pattern-either:
|
||||
- pattern: |
|
||||
if $X == nil {
|
||||
return $X
|
||||
}
|
||||
- pattern: |
|
||||
if $X != nil {
|
||||
return ...
|
||||
}
|
||||
return $X
|
||||
message: return nil instead of nil value
|
||||
languages:
|
||||
- go
|
||||
severity: ERROR
|
||||
metadata:
|
||||
license: MIT
|
|
@ -0,0 +1,16 @@
|
|||
rules:
|
||||
- id: maybe-wrong-err
|
||||
patterns:
|
||||
- pattern-either:
|
||||
- pattern: |
|
||||
if $F.Err() != nil {
|
||||
return ..., <... err ...>
|
||||
}
|
||||
- pattern: |
|
||||
if $F.Err() != nil {
|
||||
return <... err ...>
|
||||
}
|
||||
|
||||
message: "maybe returning wrong error"
|
||||
languages: [go]
|
||||
severity: WARNING
|
|
@ -0,0 +1,19 @@
|
|||
rules:
|
||||
- id: wrong-lock-unlock
|
||||
patterns:
|
||||
- pattern-either:
|
||||
- pattern: |
|
||||
$M.Lock()
|
||||
defer $M.RUnlock()
|
||||
- pattern: |
|
||||
$M.RLock()
|
||||
defer $M.Unlock()
|
||||
- pattern: |
|
||||
$M.Lock()
|
||||
defer $M.Lock()
|
||||
- pattern: |
|
||||
$M.RLock()
|
||||
defer $M.RLock()
|
||||
message: "Wrong lock/unlock pair?"
|
||||
languages: [go]
|
||||
severity: ERROR
|
|
@ -0,0 +1,28 @@
|
|||
# https://github.com/golang/go/issues/28308, from @stapelberg
|
||||
rules:
|
||||
- id: sprintf-host-port
|
||||
pattern-either:
|
||||
- patterns:
|
||||
- pattern-either:
|
||||
- pattern: fmt.Sprintf("%s:%s", $NET, $XX)
|
||||
- pattern: fmt.Sprintf("%s:%d", $NET, $XX)
|
||||
- pattern: fmt.Sprintf("%s:%s", $XX, $NET)
|
||||
- pattern: fmt.Sprintf("%s:%d", $XX, $NET)
|
||||
- pattern: $NET = fmt.Sprintf("%s:%d", ..., ...)
|
||||
- pattern: $NET = fmt.Sprintf("%s:%s", ..., ...)
|
||||
- metavariable-regex:
|
||||
metavariable: '$NET'
|
||||
regex: '(?i).*(port|addr|host|listen|bind|ip)'
|
||||
- patterns:
|
||||
- pattern: fmt.Sprintf($XX, $NET)
|
||||
- metavariable-regex:
|
||||
metavariable: '$XX'
|
||||
regex: '"%s:[0-9]+"'
|
||||
- metavariable-regex:
|
||||
metavariable: '$NET'
|
||||
regex: '(?i).*(port|addr|host|listen|bind|ip)'
|
||||
message: |
|
||||
use net.JoinHostPort instead of fmt.Sprintf($XX, $NET)
|
||||
languages: [go]
|
||||
severity: ERROR
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
rules:
|
||||
- id: use-strings-join-path
|
||||
patterns:
|
||||
- pattern-either:
|
||||
- pattern: strings.Join(..., "/")
|
||||
- pattern: strings.Join(..., "\\")
|
||||
- pattern: strings.Join(..., `\`)
|
||||
message: "did you want path.Join() or filepath.Join()?"
|
||||
languages: [go]
|
||||
severity: ERROR
|
|
@ -0,0 +1,293 @@
|
|||
rules:
|
||||
- id: lock_not_unlocked
|
||||
message: |
|
||||
Lock $LOCK not unlocked on branch with $COND
|
||||
languages: [go]
|
||||
severity: WARNING
|
||||
patterns:
|
||||
- pattern: |
|
||||
$LOCK.Lock()
|
||||
...
|
||||
if $COND {
|
||||
...
|
||||
return ...
|
||||
}
|
||||
# manual unlock before return
|
||||
- pattern-not: |
|
||||
$LOCK.Lock()
|
||||
...
|
||||
if $COND {
|
||||
...
|
||||
$LOCK.Unlock()
|
||||
...
|
||||
return ...
|
||||
}
|
||||
- pattern-not: |
|
||||
$LOCK.Lock()
|
||||
...
|
||||
$LOCK.Unlock()
|
||||
...
|
||||
if $COND {
|
||||
...
|
||||
return ...
|
||||
}
|
||||
# manual unlock with release function
|
||||
- pattern-not: |
|
||||
$LOCK.Lock()
|
||||
...
|
||||
$UNLOCKFN = $LOCK.Unlock
|
||||
...
|
||||
if $COND {
|
||||
...
|
||||
$UNLOCKFN()
|
||||
...
|
||||
return ...
|
||||
}
|
||||
- pattern-not: |
|
||||
$LOCK.Lock()
|
||||
...
|
||||
$UNLOCKFN := $LOCK.Unlock
|
||||
...
|
||||
if $COND {
|
||||
...
|
||||
$UNLOCKFN()
|
||||
...
|
||||
return ...
|
||||
}
|
||||
# defered unlock
|
||||
- pattern-not: |
|
||||
$LOCK.Lock()
|
||||
...
|
||||
defer $LOCK.Unlock()
|
||||
...
|
||||
if $COND {
|
||||
...
|
||||
return ...
|
||||
}
|
||||
- pattern-not: |
|
||||
$LOCK.Lock()
|
||||
...
|
||||
if $COND {
|
||||
...
|
||||
defer $LOCK.Unlock()
|
||||
...
|
||||
return ...
|
||||
}
|
||||
- pattern-not: |
|
||||
$LOCK.Lock()
|
||||
...
|
||||
defer func(){
|
||||
...
|
||||
$LOCK.Unlock()
|
||||
...
|
||||
}()
|
||||
...
|
||||
if $COND {
|
||||
...
|
||||
return ...
|
||||
}
|
||||
# deferred unlock with release function
|
||||
- pattern-not: |
|
||||
$LOCK.Lock()
|
||||
...
|
||||
$UNLOCKFN := $LOCK.Unlock
|
||||
...
|
||||
defer func() {
|
||||
...
|
||||
$UNLOCKFN()
|
||||
...
|
||||
}()
|
||||
...
|
||||
if $COND {
|
||||
...
|
||||
return ...
|
||||
}
|
||||
- pattern-not: |
|
||||
$LOCK.Lock()
|
||||
...
|
||||
$UNLOCKFN = $LOCK.Unlock
|
||||
...
|
||||
defer func() {
|
||||
...
|
||||
$UNLOCKFN()
|
||||
...
|
||||
}()
|
||||
...
|
||||
if $COND {
|
||||
...
|
||||
return ...
|
||||
}
|
||||
# variation where defer is called first,
|
||||
# unlock function is changed afterwards
|
||||
- pattern-not-inside: |
|
||||
defer func() {
|
||||
...
|
||||
$UNLOCKFN()
|
||||
...
|
||||
}()
|
||||
...
|
||||
$LOCK.Lock()
|
||||
...
|
||||
$UNLOCKFN = $LOCK.Unlock
|
||||
...
|
||||
if $COND {
|
||||
...
|
||||
return ...
|
||||
}
|
||||
# variation where defer is called previously, lock is reacquired
|
||||
# maybe include the Unlock call here?
|
||||
- pattern-not-inside: |
|
||||
defer $LOCK.Unlock()
|
||||
...
|
||||
$LOCK.Lock()
|
||||
...
|
||||
if $COND {
|
||||
...
|
||||
return ...
|
||||
}
|
||||
- id: read_lock_not_unlocked
|
||||
message: |
|
||||
Lock $LOCK not unlocked on branch with $COND
|
||||
languages: [go]
|
||||
severity: WARNING
|
||||
patterns:
|
||||
- pattern: |
|
||||
$LOCK.RLock()
|
||||
...
|
||||
if $COND {
|
||||
...
|
||||
return ...
|
||||
}
|
||||
# manual unlock before return
|
||||
- pattern-not: |
|
||||
$LOCK.RLock()
|
||||
...
|
||||
if $COND {
|
||||
...
|
||||
$LOCK.RUnlock()
|
||||
...
|
||||
return ...
|
||||
}
|
||||
- pattern-not: |
|
||||
$LOCK.RLock()
|
||||
...
|
||||
$LOCK.RUnlock()
|
||||
...
|
||||
if $COND {
|
||||
...
|
||||
return ...
|
||||
}
|
||||
# manual unlock with release function
|
||||
- pattern-not: |
|
||||
$LOCK.RLock()
|
||||
...
|
||||
$UNLOCKFN = $LOCK.RUnlock
|
||||
...
|
||||
if $COND {
|
||||
...
|
||||
$UNLOCKFN()
|
||||
...
|
||||
return ...
|
||||
}
|
||||
- pattern-not: |
|
||||
$LOCK.RLock()
|
||||
...
|
||||
$UNLOCKFN := $LOCK.RUnlock
|
||||
...
|
||||
if $COND {
|
||||
...
|
||||
$UNLOCKFN()
|
||||
...
|
||||
return ...
|
||||
}
|
||||
# defered unlock
|
||||
- pattern-not: |
|
||||
$LOCK.RLock()
|
||||
...
|
||||
defer $LOCK.RUnlock()
|
||||
...
|
||||
if $COND {
|
||||
...
|
||||
return ...
|
||||
}
|
||||
- pattern-not: |
|
||||
$LOCK.RLock()
|
||||
...
|
||||
if $COND {
|
||||
...
|
||||
defer $LOCK.RUnlock()
|
||||
...
|
||||
return ...
|
||||
}
|
||||
- pattern-not: |
|
||||
$LOCK.RLock()
|
||||
...
|
||||
defer func(){
|
||||
...
|
||||
$LOCK.RUnlock()
|
||||
...
|
||||
}()
|
||||
...
|
||||
if $COND {
|
||||
...
|
||||
return ...
|
||||
}
|
||||
# deferred unlock with release function
|
||||
- pattern-not: |
|
||||
$LOCK.RLock()
|
||||
...
|
||||
$UNLOCKFN := $LOCK.RUnlock
|
||||
...
|
||||
defer func() {
|
||||
...
|
||||
$UNLOCKFN()
|
||||
...
|
||||
}()
|
||||
...
|
||||
if $COND {
|
||||
...
|
||||
return ...
|
||||
}
|
||||
- pattern-not: |
|
||||
$LOCK.RLock()
|
||||
...
|
||||
$UNLOCKFN = $LOCK.RUnlock
|
||||
...
|
||||
defer func() {
|
||||
...
|
||||
$UNLOCKFN()
|
||||
...
|
||||
}()
|
||||
...
|
||||
if $COND {
|
||||
...
|
||||
return ...
|
||||
}
|
||||
# variation where defer is called first,
|
||||
# unlock function is changed afterwards
|
||||
- pattern-not-inside: |
|
||||
defer func() {
|
||||
...
|
||||
$UNLOCKFN()
|
||||
...
|
||||
}()
|
||||
...
|
||||
$LOCK.RLock()
|
||||
...
|
||||
$UNLOCKFN = $LOCK.RUnlock
|
||||
...
|
||||
if $COND {
|
||||
...
|
||||
return ...
|
||||
}
|
||||
# variation where defer is called previously, lock is reacquired
|
||||
# maybe include the Unlock call here?
|
||||
- pattern-not-inside: |
|
||||
defer $LOCK.RUnlock()
|
||||
...
|
||||
$LOCK.RLock()
|
||||
...
|
||||
if $COND {
|
||||
...
|
||||
return ...
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
rules:
|
||||
- id: logger-used-with-sprintf
|
||||
patterns:
|
||||
- pattern-either:
|
||||
- pattern: |
|
||||
logger.Trace(fmt.Sprintf(...))
|
||||
- pattern: |
|
||||
logger.Debug(fmt.Sprintf(...))
|
||||
- pattern: |
|
||||
logger.Info(fmt.Sprintf(...))
|
||||
- pattern: |
|
||||
logger.Warn(fmt.Sprintf(...))
|
||||
- pattern: |
|
||||
logger.Error(fmt.Sprintf(...))
|
||||
- pattern: |
|
||||
$PARENT.logger.Trace(fmt.Sprintf(...))
|
||||
- pattern: |
|
||||
$PARENT.logger.Debug(fmt.Sprintf(...))
|
||||
- pattern: |
|
||||
$PARENT.logger.Info(fmt.Sprintf(...))
|
||||
- pattern: |
|
||||
$PARENT.logger.Warn(fmt.Sprintf(...))
|
||||
- pattern: |
|
||||
$PARENT.logger.Error(fmt.Sprintf(...))
|
||||
message: "Logger message generated by Sprintf"
|
||||
languages: [go]
|
||||
severity: WARNING
|
||||
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
rules:
|
||||
- id: path-has-both-callbacks-and-operations
|
||||
patterns:
|
||||
- pattern-either:
|
||||
- pattern: |
|
||||
[]*framework.Path{..., {..., Pattern: $PATTERN, ..., Callbacks:$CALL, ..., Operations:$OP, ... }, ...}
|
||||
- pattern: |
|
||||
[]*framework.Path{..., {..., Pattern: $PATTERN, ..., Operations:$OP, ..., Callbacks:$CALL, ... }, ...}
|
||||
|
||||
message: "Path has both Callbacks and Operations for pattern $PATTERN"
|
||||
languages: [go]
|
||||
severity: ERROR
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
rules:
|
||||
- id: uses-path-callbacks
|
||||
patterns:
|
||||
- pattern: |
|
||||
[]*framework.Path{..., {..., Pattern: $PATTERN, ..., Callbacks:$CALL, ...}, ...}
|
||||
|
||||
message: "Path has a Callback for pattern $PATTERN"
|
||||
languages: [go]
|
||||
severity: WARNING
|
|
@ -0,0 +1,9 @@
|
|||
rules:
|
||||
- id: physical-storage-bypass-encryption
|
||||
patterns:
|
||||
- pattern-either:
|
||||
- pattern: $CORE.physical.Put(...)
|
||||
- pattern: $CORE.underlyingPhysical.Put(...)
|
||||
message: "Bypassing encryption by accessing physical storage directly"
|
||||
languages: [go]
|
||||
severity: WARNING
|
|
@ -0,0 +1,9 @@
|
|||
rules:
|
||||
- id: self-equals
|
||||
patterns:
|
||||
- pattern-either:
|
||||
- pattern: $X == $X
|
||||
- pattern: $X != $X
|
||||
message: "Comparing with self"
|
||||
languages: [go]
|
||||
severity: ERROR
|
12
vault/ui.go
12
vault/ui.go
|
@ -175,12 +175,12 @@ func (c *UIConfig) get(ctx context.Context) (*uiConfigEntry, error) {
|
|||
if err := json.Unmarshal(configRaw.Value, config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if uiConfigGetErr == nil {
|
||||
// Check that plaintext value matches barrier value, if not sync values
|
||||
if plaintextConfigRaw == nil || bytes.Compare(plaintextConfigRaw.Value, configRaw.Value) != 0 {
|
||||
if err := c.save(ctx, config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Check that plaintext value matches barrier value, if not sync values
|
||||
if uiConfigGetErr == nil && (plaintextConfigRaw == nil ||
|
||||
!bytes.Equal(plaintextConfigRaw.Value, configRaw.Value)) {
|
||||
if err := c.save(ctx, config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return config, nil
|
||||
|
|
Loading…
Reference in New Issue