lint: enable errcheck; add allowlist and explicit checks (#3403)

* lint: enable errcheck with explicit allow list
* add explicit error checks
* windows tests
* windows nolint
This commit is contained in:
mmetc 2025-01-16 16:13:10 +01:00 committed by GitHub
parent fe931af5ca
commit 49fb24c3b1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 112 additions and 52 deletions

View file

@ -5,6 +5,37 @@ run:
- expr_debug - expr_debug
linters-settings: linters-settings:
errcheck:
# Report about not checking of errors in type assertions: `a := b.(MyStruct)`.
# Such cases aren't reported by default.
# Default: false
check-type-assertions: false
# List of functions to exclude from checking, where each entry is a single function to exclude.
# See https://github.com/kisielk/errcheck#excluding-functions for details.
exclude-functions:
- (*bytes.Buffer).ReadFrom # TODO:
- io.Copy # TODO:
- (net/http.ResponseWriter).Write # TODO:
- (*os/exec.Cmd).Start
- (*os/exec.Cmd).Wait
- (*os.Process).Kill
- (*text/template.Template).ExecuteTemplate
- syscall.FreeLibrary
- golang.org/x/sys/windows.CloseHandle
- golang.org/x/sys/windows.ResetEvent
- (*golang.org/x/sys/windows/svc/eventlog.Log).Info
- (*golang.org/x/sys/windows/svc/mgr.Mgr).Disconnect
- (github.com/bluele/gcache.Cache).Set
- (github.com/gin-gonic/gin.ResponseWriter).WriteString
- (*github.com/segmentio/kafka-go.Reader).SetOffsetAt
- (*gopkg.in/tomb.v2.Tomb).Wait
- (*github.com/crowdsecurity/crowdsec/pkg/appsec.ReqDumpFilter).FilterArgs
- (*github.com/crowdsecurity/crowdsec/pkg/appsec.ReqDumpFilter).FilterBody
- (*github.com/crowdsecurity/crowdsec/pkg/appsec.ReqDumpFilter).FilterHeaders
- (*github.com/crowdsecurity/crowdsec/pkg/longpollclient.LongPollClient).Stop
gci: gci:
sections: sections:
- standard - standard
@ -318,10 +349,6 @@ issues:
- govet - govet
text: "shadow: declaration of \"(err|ctx)\" shadows declaration" text: "shadow: declaration of \"(err|ctx)\" shadows declaration"
- linters:
- errcheck
text: "Error return value of `.*` is not checked"
# Will fix, trivial - just beware of merge conflicts # Will fix, trivial - just beware of merge conflicts
- linters: - linters:

View file

@ -73,7 +73,9 @@ func (cli *cliMachines) add(ctx context.Context, args []string, machinePassword
qs := &survey.Password{ qs := &survey.Password{
Message: "Please provide a password for the machine:", Message: "Please provide a password for the machine:",
} }
survey.AskOne(qs, &machinePassword) if err := survey.AskOne(qs, &machinePassword); err != nil {
return err
}
} }
password := strfmt.Password(machinePassword) password := strfmt.Password(machinePassword)
@ -147,9 +149,9 @@ cscli machines add -f- --auto > /tmp/mycreds.yaml`,
flags.VarP(&password, "password", "p", "machine password to login to the API") flags.VarP(&password, "password", "p", "machine password to login to the API")
flags.StringVarP(&dumpFile, "file", "f", "", "output file destination (defaults to "+csconfig.DefaultConfigPath("local_api_credentials.yaml")+")") flags.StringVarP(&dumpFile, "file", "f", "", "output file destination (defaults to "+csconfig.DefaultConfigPath("local_api_credentials.yaml")+")")
flags.StringVarP(&apiURL, "url", "u", "", "URL of the local API") flags.StringVarP(&apiURL, "url", "u", "", "URL of the local API")
flags.BoolVarP(&interactive, "interactive", "i", false, "interfactive mode to enter the password") flags.BoolVarP(&interactive, "interactive", "i", false, "interactive mode to enter the password")
flags.BoolVarP(&autoAdd, "auto", "a", false, "automatically generate password (and username if not provided)") flags.BoolVarP(&autoAdd, "auto", "a", false, "automatically generate password (and username if not provided)")
flags.BoolVar(&force, "force", false, "will force add the machine if it already exist") flags.BoolVar(&force, "force", false, "will force add the machine if it already exists")
return cmd return cmd
} }

View file

@ -71,13 +71,13 @@ func NewCompletionCmd() *cobra.Command {
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
switch args[0] { switch args[0] {
case "bash": case "bash":
cmd.Root().GenBashCompletion(os.Stdout) _ = cmd.Root().GenBashCompletion(os.Stdout)
case "zsh": case "zsh":
cmd.Root().GenZshCompletion(os.Stdout) _ = cmd.Root().GenZshCompletion(os.Stdout)
case "powershell": case "powershell":
cmd.Root().GenPowerShellCompletion(os.Stdout) _ = cmd.Root().GenPowerShellCompletion(os.Stdout)
case "fish": case "fish":
cmd.Root().GenFishCompletion(os.Stdout, true) _ = cmd.Root().GenFishCompletion(os.Stdout, true)
} }
}, },
} }

View file

@ -419,7 +419,7 @@ func Serve(cConfig *csconfig.Config, agentReady chan bool) error {
} }
if cConfig.Common != nil && cConfig.Common.Daemonize { if cConfig.Common != nil && cConfig.Common.Daemonize {
csdaemon.Notify(csdaemon.Ready, log.StandardLogger()) _ = csdaemon.Notify(csdaemon.Ready, log.StandardLogger())
// wait for signals // wait for signals
return HandleSignals(cConfig) return HandleSignals(cConfig)
} }

View file

@ -330,7 +330,10 @@ func (w *AppsecSource) StreamingAcquisition(ctx context.Context, out chan types.
w.logger.Info("Shutting down Appsec server") w.logger.Info("Shutting down Appsec server")
// xx let's clean up the appsec runners :) // xx let's clean up the appsec runners :)
appsec.AppsecRulesDetails = make(map[int]appsec.RulesDetails) appsec.AppsecRulesDetails = make(map[int]appsec.RulesDetails)
w.server.Shutdown(ctx)
if err := w.server.Shutdown(ctx); err != nil {
w.logger.Errorf("Error shutting down Appsec server: %s", err.Error())
}
return nil return nil
}) })

View file

@ -154,7 +154,9 @@ func (ka *KubernetesAuditSource) StreamingAcquisition(ctx context.Context, out c
}) })
<-t.Dying() <-t.Dying()
ka.logger.Infof("Stopping k8s-audit server on %s:%d%s", ka.config.ListenAddr, ka.config.ListenPort, ka.config.WebhookPath) ka.logger.Infof("Stopping k8s-audit server on %s:%d%s", ka.config.ListenAddr, ka.config.ListenPort, ka.config.WebhookPath)
ka.server.Shutdown(ctx) if err := ka.server.Shutdown(ctx); err != nil {
ka.logger.Errorf("Error shutting down k8s-audit server: %s", err.Error())
}
return nil return nil
}) })

View file

@ -7,18 +7,22 @@ import (
"testing" "testing"
"time" "time"
"github.com/crowdsecurity/crowdsec/pkg/acquisition/configuration"
"github.com/crowdsecurity/crowdsec/pkg/exprhelpers"
"github.com/crowdsecurity/crowdsec/pkg/types"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"golang.org/x/sys/windows/svc/eventlog" "golang.org/x/sys/windows/svc/eventlog"
"gopkg.in/tomb.v2" "gopkg.in/tomb.v2"
"github.com/crowdsecurity/go-cs-lib/cstest"
"github.com/crowdsecurity/crowdsec/pkg/acquisition/configuration"
"github.com/crowdsecurity/crowdsec/pkg/exprhelpers"
"github.com/crowdsecurity/crowdsec/pkg/types"
) )
func TestBadConfiguration(t *testing.T) { func TestBadConfiguration(t *testing.T) {
exprhelpers.Init(nil) err := exprhelpers.Init(nil)
require.NoError(t, err)
tests := []struct { tests := []struct {
config string config string
@ -62,7 +66,8 @@ xpath_query: test`,
} }
func TestQueryBuilder(t *testing.T) { func TestQueryBuilder(t *testing.T) {
exprhelpers.Init(nil) err := exprhelpers.Init(nil)
require.NoError(t, err)
tests := []struct { tests := []struct {
config string config string
@ -111,23 +116,26 @@ event_level: bla`,
} }
subLogger := log.WithField("type", "windowseventlog") subLogger := log.WithField("type", "windowseventlog")
for _, test := range tests { for _, test := range tests {
t.Run(test.config, func(t *testing.T) {
f := WinEventLogSource{} f := WinEventLogSource{}
f.Configure([]byte(test.config), subLogger, configuration.METRICS_NONE)
q, err := f.buildXpathQuery() err := f.Configure([]byte(test.config), subLogger, configuration.METRICS_NONE)
cstest.AssertErrorContains(t, err, test.expectedErr)
if test.expectedErr != "" { if test.expectedErr != "" {
if err == nil { return
t.Fatalf("expected error '%s' but got none", test.expectedErr)
} }
assert.Contains(t, err.Error(), test.expectedErr)
} else { q, err := f.buildXpathQuery()
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, test.expectedQuery, q) assert.Equal(t, test.expectedQuery, q)
} })
} }
} }
func TestLiveAcquisition(t *testing.T) { func TestLiveAcquisition(t *testing.T) {
exprhelpers.Init(nil) err := exprhelpers.Init(nil)
require.NoError(t, err)
ctx := context.Background() ctx := context.Background()
tests := []struct { tests := []struct {
@ -185,8 +193,13 @@ event_ids:
to := &tomb.Tomb{} to := &tomb.Tomb{}
c := make(chan types.Event) c := make(chan types.Event)
f := WinEventLogSource{} f := WinEventLogSource{}
f.Configure([]byte(test.config), subLogger, configuration.METRICS_NONE)
f.StreamingAcquisition(ctx, c, to) err := f.Configure([]byte(test.config), subLogger, configuration.METRICS_NONE)
require.NoError(t, err)
err = f.StreamingAcquisition(ctx, c, to)
require.NoError(t, err)
time.Sleep(time.Second) time.Sleep(time.Second)
lines := test.expectedLines lines := test.expectedLines
go func() { go func() {
@ -261,7 +274,8 @@ func TestOneShotAcquisition(t *testing.T) {
}, },
} }
exprhelpers.Init(nil) err := exprhelpers.Init(nil)
require.NoError(t, err)
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
@ -269,15 +283,13 @@ func TestOneShotAcquisition(t *testing.T) {
to := &tomb.Tomb{} to := &tomb.Tomb{}
c := make(chan types.Event) c := make(chan types.Event)
f := WinEventLogSource{} f := WinEventLogSource{}
err := f.ConfigureByDSN(test.dsn, map[string]string{"type": "wineventlog"}, log.WithField("type", "windowseventlog"), "")
err := f.ConfigureByDSN(test.dsn, map[string]string{"type": "wineventlog"}, log.WithField("type", "windowseventlog"), "")
cstest.AssertErrorContains(t, err, test.expectedConfigureErr)
if test.expectedConfigureErr != "" { if test.expectedConfigureErr != "" {
assert.Contains(t, err.Error(), test.expectedConfigureErr)
return return
} }
require.NoError(t, err)
go func() { go func() {
for { for {
select { select {

View file

@ -57,6 +57,12 @@ func main() {
}) })
} }
} }
csvWriter.Write(csvHeader)
csvWriter.WriteAll(allItems) if err = csvWriter.Write(csvHeader); err != nil {
panic(err)
}
if err = csvWriter.WriteAll(allItems); err != nil {
panic(err)
}
} }

View file

@ -29,8 +29,6 @@ import (
"github.com/umahmood/haversine" "github.com/umahmood/haversine"
"github.com/wasilibs/go-re2" "github.com/wasilibs/go-re2"
"github.com/crowdsecurity/go-cs-lib/ptr"
"github.com/crowdsecurity/crowdsec/pkg/cache" "github.com/crowdsecurity/crowdsec/pkg/cache"
"github.com/crowdsecurity/crowdsec/pkg/database" "github.com/crowdsecurity/crowdsec/pkg/database"
"github.com/crowdsecurity/crowdsec/pkg/fflag" "github.com/crowdsecurity/crowdsec/pkg/fflag"
@ -146,17 +144,19 @@ func RegexpCacheInit(filename string, cacheCfg types.DataSource) error {
} }
// cache is enabled // cache is enabled
if cacheCfg.Size == nil { size := 50
cacheCfg.Size = ptr.Of(50) if cacheCfg.Size != nil {
size = *cacheCfg.Size
} }
gc := gcache.New(*cacheCfg.Size) gc := gcache.New(size)
if cacheCfg.Strategy == nil { strategy := "LRU"
cacheCfg.Strategy = ptr.Of("LRU") if cacheCfg.Strategy != nil {
strategy = *cacheCfg.Strategy
} }
switch *cacheCfg.Strategy { switch strategy {
case "LRU": case "LRU":
gc = gc.LRU() gc = gc.LRU()
case "LFU": case "LFU":
@ -164,7 +164,7 @@ func RegexpCacheInit(filename string, cacheCfg types.DataSource) error {
case "ARC": case "ARC":
gc = gc.ARC() gc = gc.ARC()
default: default:
return fmt.Errorf("unknown cache strategy '%s'", *cacheCfg.Strategy) return fmt.Errorf("unknown cache strategy '%s'", strategy)
} }
if cacheCfg.TTL != nil { if cacheCfg.TTL != nil {

View file

@ -458,7 +458,9 @@ func LoadBucket(bucketFactory *BucketFactory, tomb *tomb.Tomb) error {
} }
if data.Type == "regexp" { // cache only makes sense for regexp if data.Type == "regexp" { // cache only makes sense for regexp
exprhelpers.RegexpCacheInit(data.DestPath, *data) if err := exprhelpers.RegexpCacheInit(data.DestPath, *data); err != nil {
bucketFactory.logger.Error(err.Error())
}
} }
} }

View file

@ -353,7 +353,9 @@ func (n *Node) process(p *types.Event, ctx UnixParserCtx, expressionEnv map[stri
clog.Warningf("unexpected type %t (%v) while running '%s'", output, output, stash.Key) clog.Warningf("unexpected type %t (%v) while running '%s'", output, output, stash.Key)
continue continue
} }
cache.SetKey(stash.Name, key, value, &stash.TTLVal) if err = cache.SetKey(stash.Name, key, value, &stash.TTLVal); err != nil {
clog.Warningf("failed to store data in cache: %s", err.Error())
}
} }
} }

View file

@ -114,10 +114,12 @@ func LoadStages(stageFiles []Stagefile, pctx *UnixParserCtx, ectx EnricherCtx) (
for _, data := range node.Data { for _, data := range node.Data {
err = exprhelpers.FileInit(pctx.DataFolder, data.DestPath, data.Type) err = exprhelpers.FileInit(pctx.DataFolder, data.DestPath, data.Type)
if err != nil { if err != nil {
log.Error(err) log.Error(err.Error())
} }
if data.Type == "regexp" { //cache only makes sense for regexp if data.Type == "regexp" { //cache only makes sense for regexp
exprhelpers.RegexpCacheInit(data.DestPath, *data) if err = exprhelpers.RegexpCacheInit(data.DestPath, *data); err != nil {
log.Error(err.Error())
}
} }
} }

View file

@ -192,7 +192,9 @@ func marshalAcquisDocuments(ads []AcquisDocument, toDir string) (string, error)
return "", fmt.Errorf("while writing to %s: %w", ad.AcquisFilename, err) return "", fmt.Errorf("while writing to %s: %w", ad.AcquisFilename, err)
} }
f.Sync() if err = f.Sync(); err != nil {
return "", fmt.Errorf("while syncing %s: %w", ad.AcquisFilename, err)
}
continue continue
} }