diff --git a/go.mod b/go.mod index 8a67388f3..6f2be7f70 100644 --- a/go.mod +++ b/go.mod @@ -254,6 +254,7 @@ require ( github.com/shoenig/go-m1cpu v0.1.6 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/skeema/knownhosts v1.2.2 // indirect + github.com/testcontainers/testcontainers-go/modules/redis v0.31.0 // indirect github.com/tetratelabs/wazero v1.7.1 // indirect github.com/therootcompany/xz v1.0.1 // indirect github.com/tklauser/go-sysconf v0.3.12 // indirect diff --git a/go.sum b/go.sum index 5758b7378..caab2258a 100644 --- a/go.sum +++ b/go.sum @@ -716,6 +716,8 @@ github.com/testcontainers/testcontainers-go/modules/mysql v0.31.0 h1:790+S8ewZYC github.com/testcontainers/testcontainers-go/modules/mysql v0.31.0/go.mod h1:REFmO+lSG9S6uSBEwIMZCxeI36uhScjTwChYADeO3JA= github.com/testcontainers/testcontainers-go/modules/postgres v0.31.0 h1:isAwFS3KNKRbJMbWv+wolWqOFUECmjYZ+sIRZCIBc/E= github.com/testcontainers/testcontainers-go/modules/postgres v0.31.0/go.mod h1:ZNYY8vumNCEG9YI59A9d6/YaMY49uwRhmeU563EzFGw= +github.com/testcontainers/testcontainers-go/modules/redis v0.31.0 h1:5X6GhOdLwV86zcW8sxppJAMtsDC9u+r9tb3biBc9GKs= +github.com/testcontainers/testcontainers-go/modules/redis v0.31.0/go.mod h1:dKi5xBwy1k4u8yb3saQHu7hMEJwewHXxzbcMAuLiA6o= github.com/tetratelabs/wazero v1.7.1 h1:QtSfd6KLc41DIMpDYlJdoMc6k7QTN246DM2+n2Y/Dx8= github.com/tetratelabs/wazero v1.7.1/go.mod h1:ytl6Zuh20R/eROuyDaGPkp82O9C/DJfXAwJfQ3X6/7Y= github.com/therootcompany/xz v1.0.1 h1:CmOtsn1CbtmyYiusbfmhmkpAAETj0wBIH6kCYaX+xzw= diff --git a/pkg/detectors/redis/redis_integration_test.go b/pkg/detectors/redis/redis_integration_test.go new file mode 100644 index 000000000..caebf3bb8 --- /dev/null +++ b/pkg/detectors/redis/redis_integration_test.go @@ -0,0 +1,156 @@ +//go:build detectors && integration +// +build detectors,integration + +package redis + +import ( + "context" + "fmt" + "io/ioutil" + "os" + "testing" + "time" + + "github.com/brianvoe/gofakeit/v7" + "github.com/kylelemons/godebug/pretty" + "github.com/testcontainers/testcontainers-go" + "github.com/testcontainers/testcontainers-go/wait" + "github.com/trufflesecurity/trufflehog/v3/pkg/detectors" + "github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb" +) + +func setupACLConfigFile(redisUser, redisPass string) (*os.File, error) { + + aclString := fmt.Sprintf(` + user default on >%s ~* +@all + user %s on >%s ~* +@all + `, redisPass, redisUser, redisPass) + + aclFile, err := ioutil.TempFile("", "redis_users.acl") + if err != nil { + return nil, err + } + + if _, err := aclFile.Write([]byte(aclString)); err != nil { + return nil, err + } + + return aclFile, nil +} + +func TestRedisIntegration_FromChunk(t *testing.T) { + redisUser := gofakeit.Username() + redisPass := gofakeit.Password(true, true, true, false, false, 10) + + ctx := context.Background() + + aclFile, err := setupACLConfigFile(redisUser, redisPass) + if err != nil { + t.Fatal(err) + } + defer aclFile.Close() + + redisContainerRequest := testcontainers.ContainerRequest{ + Image: "redis:7-alpine", + ExposedPorts: []string{"6379/tcp"}, + Mounts: testcontainers.ContainerMounts{ + testcontainers.BindMount(aclFile.Name(), "/usr/local/etc/redis/users.acl"), + }, + Cmd: []string{"redis-server", "--aclfile", "/usr/local/etc/redis/users.acl"}, + WaitingFor: wait.ForLog("Ready to accept connections").WithStartupTimeout(10 * time.Second), + } + + redisC, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ + ContainerRequest: redisContainerRequest, + Started: true, + }) + + if err != nil { + t.Fatal(err) + } + + port, err := redisC.MappedPort(ctx, "6379") + if err != nil { + t.Fatal(err) + } + host, err := redisC.Host(ctx) + if err != nil { + t.Fatal(err) + } + + defer redisC.Terminate(ctx) + + type args struct { + ctx context.Context + data []byte + verify bool + } + tests := []struct { + name string + s Scanner + args args + want []detectors.Result + wantErr bool + }{ + { + name: "bad scheme", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte("file://user:pass@foo.com:123/wh/at/ever"), + verify: true, + }, + wantErr: false, + }, + { + name: "unverified Redis", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("redis://%s:%s@%s:%s", redisUser, "wrongpass", host, port.Port())), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_Redis, + Verified: false, + Redacted: fmt.Sprintf("redis://%s:*******@%s:%s", redisUser, host, port.Port()), + }, + }, + wantErr: false, + }, + { + name: "verified Redis", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("redis://%s:%s@%s:%s", redisUser, redisPass, host, port.Port())), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_Redis, + Verified: true, + Redacted: fmt.Sprintf("redis://%s:*******@%s:%s", redisUser, host, port.Port()), + }, + }, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := Scanner{} + got, err := s.FromData(tt.args.ctx, tt.args.verify, tt.args.data) + if (err != nil) != tt.wantErr { + t.Errorf("URI.FromData() error = %v, wantErr %v", err, tt.wantErr) + return + } + for i := range got { + got[i].Raw = nil + } + if diff := pretty.Compare(got, tt.want); diff != "" { + t.Errorf("URI.FromData() %s diff: (-got +want)\n%s", tt.name, diff) + } + }) + } +}