Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gosec: convert global settings as map with proper key type #3779

Merged
merged 8 commits into from
Apr 21, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 51 additions & 13 deletions pkg/golinters/gosec.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,24 +22,62 @@ import (

const gosecName = "gosec"

func NewGosec(settings *config.GoSecSettings) *goanalysis.Linter {
var mu sync.Mutex
var resIssues []goanalysis.Issue
// see gosec#Config.convertGlobals
func convertGosecGlobals(settings *config.GoSecSettings, conf gosec.Config) {
bcho marked this conversation as resolved.
Show resolved Hide resolved
if len(settings.Config) < 1 {
return
}

globalOptionFromConfig, exists := settings.Config[gosec.Globals]
if !exists {
return
}

globalOptionMap, ok := globalOptionFromConfig.(map[string]any)
if !ok {
return
}
for k, v := range globalOptionMap {
conf.SetGlobal(gosec.GlobalOption(k), fmt.Sprintf("%v", v))
}
}

func toGosecConfig(settings *config.GoSecSettings) gosec.Config {
conf := gosec.NewConfig()

var filters []rules.RuleFilter
if settings != nil {
filters = gosecRuleFilters(settings.Includes, settings.Excludes)
if len(settings.Config) < 1 {
return conf
}

for k, v := range settings.Config {
if k != gosec.Globals {
// Uses ToUpper because the parsing of the map's key change the key to lowercase.
// The value is not impacted by that: the case is respected.
k = strings.ToUpper(k)
}
conf.Set(k, v)
// global section
convertGosecGlobals(settings, conf)

// non-global section
for k, v := range settings.Config {
if k == gosec.Globals {
continue
}

// Uses ToUpper because the parsing of the map's key change the key to lowercase.
// The value is not impacted by that: the case is respected.
k = strings.ToUpper(k)
conf.Set(k, v)
}

return conf
}

func NewGosec(settings *config.GoSecSettings) *goanalysis.Linter {
var (
mu sync.Mutex
resIssues []goanalysis.Issue
filters []rules.RuleFilter
conf gosec.Config
)

if settings != nil {
filters = gosecRuleFilters(settings.Includes, settings.Excludes)
conf = toGosecConfig(settings)
}

logger := log.New(io.Discard, "", 0)
Expand Down
69 changes: 69 additions & 0 deletions pkg/golinters/gosec_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package golinters

import (
"fmt"
"testing"

"github.com/golangci/golangci-lint/pkg/config"
"github.com/securego/gosec/v2"
"github.com/stretchr/testify/assert"
)
bcho marked this conversation as resolved.
Show resolved Hide resolved

func TestToGosecConfig(t *testing.T) {
t.Run("empty config map", func(t *testing.T) {
settings := &config.GoSecSettings{}

gosecConfig := toGosecConfig(settings)
assert.Len(t, gosecConfig, 1)
assert.Contains(t, gosecConfig, gosec.Globals)
})

t.Run("with global settings", func(t *testing.T) {
globalsSettings := map[string]any{
string(gosec.Nosec): true,
string(gosec.Audit): "true",
}
settings := &config.GoSecSettings{
Config: map[string]any{
gosec.Globals: globalsSettings,
},
}

gosecConfig := toGosecConfig(settings)
assert.Len(t, gosecConfig, 1)
assert.Contains(t, gosecConfig, gosec.Globals)

for _, k := range []gosec.GlobalOption{gosec.Nosec, gosec.Audit} {
v, err := gosecConfig.GetGlobal(k)
assert.NoError(t, err, "error getting global option %s", k)
assert.Equal(
t,
fmt.Sprintf("%v", globalsSettings[string(k)]),
v,
"global option %s is not set to expected value", k,
)
}

for _, k := range []gosec.GlobalOption{gosec.NoSecAlternative} {
_, err := gosecConfig.GetGlobal(k)
assert.Error(t, err, "should not set global option %s", k)
}
})

t.Run("rule specified settings", func(t *testing.T) {
settings := &config.GoSecSettings{
Config: map[string]any{
"g101": map[string]any{
"pattern": "(?i)example",
},
"G301": "0750",
},
}

gosecConfig := toGosecConfig(settings)
assert.Len(t, gosecConfig, 3)
assert.Contains(t, gosecConfig, gosec.Globals)
assert.Contains(t, gosecConfig, "G101")
assert.Contains(t, gosecConfig, "G301")
bcho marked this conversation as resolved.
Show resolved Hide resolved
})
}
5 changes: 5 additions & 0 deletions test/testdata/configs/gosec_global_option.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
linters-settings:
gosec:
config:
global:
nosec: true
14 changes: 14 additions & 0 deletions test/testdata/gosec_global_option.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//golangcitest:args -Egosec
//golangcitest:config_path testdata/configs/gosec_global_option.yml
package testdata

import (
"crypto/md5" // want "G501: Blocklisted import crypto/md5: weak cryptographic primitive"
"log"
)

func Gosec() {
// #nosec G401
h := md5.New() // want "G401: Use of weak cryptographic primitive"
log.Print(h)
}