Skip to content
Closed
Changes from all 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
115 changes: 47 additions & 68 deletions modules/valkey/valkey.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,26 +61,19 @@ func RunContainer(ctx context.Context, opts ...testcontainers.ContainerCustomize

// Run creates an instance of the Valkey container type
func Run(ctx context.Context, img string, opts ...testcontainers.ContainerCustomizer) (*ValkeyContainer, error) {
req := testcontainers.ContainerRequest{
Image: img,
ExposedPorts: []string{valkeyPort},
}

genericContainerReq := testcontainers.GenericContainerRequest{
ContainerRequest: req,
Started: true,
}

// Process custom options first
var settings options
for _, opt := range opts {
if opt, ok := opt.(Option); ok {
if err := opt(&settings); err != nil {
return nil, err
return nil, fmt.Errorf("apply option: %w", err)
}
}
}

tcOpts := []testcontainers.ContainerCustomizer{}
moduleOpts := []testcontainers.ContainerCustomizer{
testcontainers.WithExposedPorts(valkeyPort),
}

waitStrategies := []wait.Strategy{
wait.ForListeningPort(valkeyPort).WithStartupTimeout(time.Second * 10),
Expand Down Expand Up @@ -109,23 +102,25 @@ func Run(ctx context.Context, img string, opts ...testcontainers.ContainerCustom
"--tls-auth-clients", "yes",
}

tcOpts = append(tcOpts, testcontainers.WithCmdArgs(cmds...)) // Append the default CMD with the TLS certificates.
tcOpts = append(tcOpts, testcontainers.WithFiles(
testcontainers.ContainerFile{
Reader: bytes.NewReader(caCert.Bytes),
ContainerFilePath: "/tls/ca.crt",
FileMode: 0o644,
},
testcontainers.ContainerFile{
Reader: bytes.NewReader(serverCert.Bytes),
ContainerFilePath: "/tls/server.crt",
FileMode: 0o644,
},
testcontainers.ContainerFile{
Reader: bytes.NewReader(serverCert.KeyBytes),
ContainerFilePath: "/tls/server.key",
FileMode: 0o644,
}))
moduleOpts = append(moduleOpts,
testcontainers.WithCmdArgs(cmds...),
testcontainers.WithFiles(
testcontainers.ContainerFile{
Reader: bytes.NewReader(caCert.Bytes),
ContainerFilePath: "/tls/ca.crt",
FileMode: 0o644,
},
testcontainers.ContainerFile{
Reader: bytes.NewReader(serverCert.Bytes),
ContainerFilePath: "/tls/server.crt",
FileMode: 0o644,
},
testcontainers.ContainerFile{
Reader: bytes.NewReader(serverCert.KeyBytes),
ContainerFilePath: "/tls/server.key",
FileMode: 0o644,
}),
Comment on lines +118 to +122
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

server.key should be 0600 (private key).

Current 0644 makes the key world-readable in the container. Tighten permissions.

-				testcontainers.ContainerFile{
-					Reader:            bytes.NewReader(serverCert.KeyBytes),
-					ContainerFilePath: "/tls/server.key",
-					FileMode:          0o644,
-				}),
+				testcontainers.ContainerFile{
+					Reader:            bytes.NewReader(serverCert.KeyBytes),
+					ContainerFilePath: "/tls/server.key",
+					FileMode:          0o600,
+				}),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
testcontainers.ContainerFile{
Reader: bytes.NewReader(serverCert.KeyBytes),
ContainerFilePath: "/tls/server.key",
FileMode: 0o644,
}),
testcontainers.ContainerFile{
Reader: bytes.NewReader(serverCert.KeyBytes),
ContainerFilePath: "/tls/server.key",
FileMode: 0o600,
}),
🤖 Prompt for AI Agents
In modules/valkey/valkey.go around lines 118 to 122, the server private key file
is being written into the container with mode 0644 which makes it
world-readable; change the FileMode for "/tls/server.key" to 0600 (use Go octal
0o600) so the key is only readable/writable by the owner. Ensure the value is
the correct octal literal and rebuild/tests to verify permissions.

)

settings.tlsConfig = &tls.Config{
MinVersion: tls.VersionTLS12,
Expand All @@ -135,26 +130,16 @@ func Run(ctx context.Context, img string, opts ...testcontainers.ContainerCustom
}
}

tcOpts = append(tcOpts, testcontainers.WithWaitStrategy(waitStrategies...))

// Append the customizers passed to the Run function.
tcOpts = append(tcOpts, opts...)
moduleOpts = append(moduleOpts, testcontainers.WithWaitStrategy(waitStrategies...))

// Apply the testcontainers customizers.
for _, opt := range tcOpts {
if err := opt.Customize(&genericContainerReq); err != nil {
return nil, err
}
}

container, err := testcontainers.GenericContainer(ctx, genericContainerReq)
ctr, err := testcontainers.Run(ctx, img, append(moduleOpts, opts...)...)
var c *ValkeyContainer
if container != nil {
c = &ValkeyContainer{Container: container, settings: settings}
if ctr != nil {
c = &ValkeyContainer{Container: ctr, settings: settings}
}

if err != nil {
return c, fmt.Errorf("generic container: %w", err)
return c, fmt.Errorf("run valkey: %w", err)
}

return c, nil
Expand All @@ -171,33 +156,31 @@ func WithConfigFile(configFile string) testcontainers.CustomizeRequestOption {
ContainerFilePath: defaultConfigFile,
FileMode: 0o755,
}
req.Files = append(req.Files, cf)

if err := testcontainers.WithFiles(cf)(req); err != nil {
return err
}

if len(req.Cmd) == 0 {
req.Cmd = []string{valkeyServerProcess, defaultConfigFile}
return nil
return testcontainers.WithCmd(valkeyServerProcess, defaultConfigFile)(req)
}

// prepend the command to run the redis server with the config file, which must be the first argument of the redis server process
// prepend the command to run the valkey server with the config file, which must be the first argument of the valkey server process
if req.Cmd[0] == valkeyServerProcess {
// just insert the config file, then the rest of the args
req.Cmd = append([]string{valkeyServerProcess, defaultConfigFile}, req.Cmd[1:]...)
} else if req.Cmd[0] != valkeyServerProcess {
// prepend the redis server and the config file, then the rest of the args
req.Cmd = append([]string{valkeyServerProcess, defaultConfigFile}, req.Cmd...)
return testcontainers.WithCmd(append([]string{valkeyServerProcess, defaultConfigFile}, req.Cmd[1:]...)...)(req)
}

return nil
// prepend the valkey server and the config file, then the rest of the args
return testcontainers.WithCmd(append([]string{valkeyServerProcess, defaultConfigFile}, req.Cmd...)...)(req)
}
}

// WithLogLevel sets the log level for the valkey server process
// See https://redis.io/docs/reference/modules/modules-api-ref/#redismodule_log for more information.
func WithLogLevel(level LogLevel) testcontainers.CustomizeRequestOption {
return func(req *testcontainers.GenericContainerRequest) error {
processValkeyServerArgs(req, []string{"--loglevel", string(level)})

return nil
return processValkeyServerArgs(req, []string{"--loglevel", string(level)})
}
}

Expand All @@ -214,24 +197,20 @@ func WithSnapshotting(seconds int, changedKeys int) testcontainers.CustomizeRequ
}

return func(req *testcontainers.GenericContainerRequest) error {
processValkeyServerArgs(req, []string{"--save", strconv.Itoa(seconds), strconv.Itoa(changedKeys)})
return nil
return processValkeyServerArgs(req, []string{"--save", strconv.Itoa(seconds), strconv.Itoa(changedKeys)})
}
}

func processValkeyServerArgs(req *testcontainers.GenericContainerRequest, args []string) {
func processValkeyServerArgs(req *testcontainers.GenericContainerRequest, args []string) error {
if len(req.Cmd) == 0 {
req.Cmd = append([]string{valkeyServerProcess}, args...)
return
return testcontainers.WithCmd(append([]string{valkeyServerProcess}, args...)...)(req)
}

// prepend the command to run the valkey server with the config file
// If valkey server is already set as the first argument, just append the args
if req.Cmd[0] == valkeyServerProcess {
// valkey server is already set as the first argument, so just append the config file
req.Cmd = append(req.Cmd, args...)
} else if req.Cmd[0] != valkeyServerProcess {
// valkey server is not set as the first argument, so prepend it alongside the config file
req.Cmd = append([]string{valkeyServerProcess}, req.Cmd...)
req.Cmd = append(req.Cmd, args...)
return testcontainers.WithCmdArgs(args...)(req)
}

// valkey server is not set as the first argument, so prepend it alongside the existing command and args
return testcontainers.WithCmd(append(append([]string{valkeyServerProcess}, req.Cmd...), args...)...)(req)
}
Loading