diff --git a/go.mod b/go.mod index be9e131850130..d3c198daf978d 100644 --- a/go.mod +++ b/go.mod @@ -428,7 +428,7 @@ replace ( // replace module github.com/moby/spdystream until https://github.com/moby/spdystream/pull/91 merges and deps are updated // otherwise tests fail with a data race detection. github.com/moby/spdystream => github.com/gravitational/spdystream v0.0.0-20230512133543-4e46862ca9bf - github.com/redis/go-redis/v9 => github.com/gravitational/redis/v9 v9.0.2-teleport.1 + github.com/redis/go-redis/v9 => github.com/gravitational/redis/v9 v9.0.2-teleport.2 github.com/sijms/go-ora/v2 => github.com/gravitational/go-ora/v2 v2.0.0-20230821114616-e2a9f1131a46 github.com/vulcand/predicate => github.com/gravitational/predicate v1.3.1 ) diff --git a/go.sum b/go.sum index 1de3db50abaec..103526c9393f8 100644 --- a/go.sum +++ b/go.sum @@ -825,8 +825,8 @@ github.com/gravitational/predicate v1.3.1 h1:f1uGg2FF6z5wZbcafYpLZJ1gl+82I0MlSd0 github.com/gravitational/predicate v1.3.1/go.mod h1:H5e9dUW7zb/cuKkkhfnyT9SsI/WHWJ8Ra011La16DTY= github.com/gravitational/protobuf v1.3.2-teleport.1 h1:h5mh+UOKPurqDxn1hRVcr1WzSkmBi+D9qkXpaXA9PFM= github.com/gravitational/protobuf v1.3.2-teleport.1/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/gravitational/redis/v9 v9.0.2-teleport.1 h1:BYrMUySxKFOkZ/4XjKEIvkDYqBBBeRGs3eVLLS9btrA= -github.com/gravitational/redis/v9 v9.0.2-teleport.1/go.mod h1:/xDTe9EF1LM61hek62Poq2nzQSGj0xSrEtEHbBQevps= +github.com/gravitational/redis/v9 v9.0.2-teleport.2 h1:br9gSGJLpfrIoKsF5N99zWgjPpQpsQiCeN5HmAbYpio= +github.com/gravitational/redis/v9 v9.0.2-teleport.2/go.mod h1:/xDTe9EF1LM61hek62Poq2nzQSGj0xSrEtEHbBQevps= github.com/gravitational/roundtrip v1.0.2 h1:eOCY0NEKKaB0ksJmvhO6lPMFz1pIIef+vyPBTBROQ5c= github.com/gravitational/roundtrip v1.0.2/go.mod h1:fuI1booM2hLRA/B/m5MRAPOU6mBZNYcNycono2UuTw0= github.com/gravitational/spdystream v0.0.0-20230512133543-4e46862ca9bf h1:aXnqDSit8L1qhI0+QdbJh+MTUFKXG7qbkZXnfr7L96A= diff --git a/lib/srv/db/access_test.go b/lib/srv/db/access_test.go index 13839a7e28621..5ce8b85873815 100644 --- a/lib/srv/db/access_test.go +++ b/lib/srv/db/access_test.go @@ -17,6 +17,7 @@ limitations under the License. package db import ( + "bytes" "context" "crypto/tls" "database/sql" @@ -80,6 +81,7 @@ import ( "github.com/gravitational/teleport/lib/srv/db/opensearch" "github.com/gravitational/teleport/lib/srv/db/postgres" "github.com/gravitational/teleport/lib/srv/db/redis" + redisprotocol "github.com/gravitational/teleport/lib/srv/db/redis/protocol" "github.com/gravitational/teleport/lib/srv/db/secrets" "github.com/gravitational/teleport/lib/srv/db/snowflake" "github.com/gravitational/teleport/lib/srv/db/sqlserver" @@ -437,6 +439,54 @@ func TestAccessRedis(t *testing.T) { } } +// TestRedisCommandDocs is a regression test to verify if simple/status strings +// (+) are returned to Redis client for "COMMAND DOCS" command. +// +// "redis-cli" expects command info flags in simple/status strings (+), +// not regular ones ($). An error is thrown by "redis-cli" if + +// is not received. +func TestRedisCommandDocs(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + t.Cleanup(cancel) + testCtx := setupTestContext(ctx, t, withSelfHostedRedis("redis")) + go testCtx.startHandlingConnections() + + // Create user/role with the requested permissions. + testCtx.createUserAndRole(ctx, t, "alice", "admin", []string{types.Wildcard}, []string{types.Wildcard}) + + // Try to connect to the database as this user. + redisClient, err := testCtx.redisClient(ctx, "alice", "redis", "default") + require.NoError(t, err) + + // Miniredis returns a sample command result: + // https://github.com/alicebob/miniredis/blob/master/cmd_command.go + // + // Unlike "redis-cli", redisClient.Command accepts any kind of string + // regardless whether the flag is in + or in $. This should + // always succeeds but it will be used as a reference to test the raw + // output. + parsedCommandInfos := redisClient.Command(ctx) + require.NoError(t, parsedCommandInfos.Err()) + + // Capture the raw bytes. + rawCommandInfos := goredis.NewCmd(ctx, "COMMAND", "DOCS") + require.NoError(t, redisClient.Process(ctx, rawCommandInfos)) + rawCommandInfosBuffer := &bytes.Buffer{} + require.NoError(t, redisprotocol.WriteCmd(goredis.NewWriter(rawCommandInfosBuffer), rawCommandInfos.Val())) + + // Loop each flag to make sure + is written to the raw bytes. + rawCommandInfosOutput := rawCommandInfosBuffer.String() + var flagsVerified int + for _, commandInfo := range parsedCommandInfos.Val() { + for _, flag := range commandInfo.Flags { + require.Contains(t, rawCommandInfosOutput, "+"+flag) + flagsVerified += 1 + } + } + // Just to make sure miniredis is returning a command info with some flags. + require.Greater(t, flagsVerified, 0) +} + // TestMySQLBadHandshake verifies MySQL proxy can gracefully handle truncated // client handshake messages. func TestMySQLBadHandshake(t *testing.T) {