Skip to content

feat(cassandra): add ssl option cassandra#3151

Merged
mdelapenya merged 35 commits intotestcontainers:mainfrom
MitulShah1:add-ssl-option-cassandra
Dec 12, 2025
Merged

feat(cassandra): add ssl option cassandra#3151
mdelapenya merged 35 commits intotestcontainers:mainfrom
MitulShah1:add-ssl-option-cassandra

Conversation

@MitulShah1
Copy link
Contributor

@MitulShah1 MitulShah1 commented May 2, 2025

#3124

What does this PR do?

Why is it important?

Related issues

@mdelapenya Can you please review

@MitulShah1 MitulShah1 requested a review from a team as a code owner May 2, 2025 09:36
@netlify
Copy link

netlify bot commented May 2, 2025

Deploy Preview for testcontainers-go ready!

Name Link
🔨 Latest commit 42f32ec
🔍 Latest deploy log https://app.netlify.com/projects/testcontainers-go/deploys/693bdf13ac24320008b7e50c
😎 Deploy Preview https://deploy-preview-3151--testcontainers-go.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@MitulShah1 MitulShah1 changed the title Add ssl option cassandra feat(cassandra): Add ssl option cassandra May 2, 2025
@mdelapenya mdelapenya changed the title feat(cassandra): Add ssl option cassandra feat(cassandra): add ssl option cassandra May 3, 2025
Copy link
Member

@mdelapenya mdelapenya left a comment

Choose a reason for hiding this comment

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

Looking good, although I added some comments about using the same approach as in the Redis module. Could you please take a look?

Cheers!

@MitulShah1 MitulShah1 requested a review from mdelapenya May 7, 2025 07:05
@MitulShah1
Copy link
Contributor Author

Looking good, although I added some comments about using the same approach as in the Redis module. Could you please take a look?

Cheers!

I made changes, can you please check again?

Copy link
Contributor

@stevenh stevenh left a comment

Choose a reason for hiding this comment

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

Thanks for the quick updates, here's some suggestion which focus on simplification and reducing API surface area.

@gaby
Copy link

gaby commented Oct 13, 2025

@mdelapenya @MitulShah1 any progress on this?

@MitulShah1
Copy link
Contributor Author

@mdelapenya @MitulShah1 any progress on this?

Hey @gaby @mdelapenya sorry for delay but i tried with simple tlc certy which @stevenh mentioned with @mdelapenya library seems its not working with cassandra. so just stuck on this point only.

# Conflicts:
#	modules/cassandra/cassandra.go
@coderabbitai
Copy link

coderabbitai bot commented Oct 14, 2025

Summary by CodeRabbit

  • New Features

    • TLS/SSL support for Cassandra containers with automatic self-signed certificate and keystore generation
    • New option to enable TLS and expose SSL port (9142) when enabled
    • New method to obtain the container's TLS configuration for secure client connections
  • Tests

    • Added integration test exercising TLS-protected operations
    • Added example demonstrating TLS usage
  • Documentation

    • Added TLS configuration guide with examples

✏️ Tip: You can customize this high-level summary in your review settings.

Walkthrough

Adds optional TLS support to Cassandra containers: generates CA and server certificates, creates a PKCS#12 keystore, exposes SSL port 9142, introduces WithTLS() option and TLSConfig() accessor, mounts SSL config and keystore into the container, and adds tests/examples validating TLS client connections.

Changes

Cohort / File(s) Summary
Core Cassandra TLS Integration
modules/cassandra/cassandra.go
Adds TLS awareness (sslPort 9142), embeds SSL YAML, adds settings options field, switches connection host/port when TLS enabled, adds TLSConfig() method, and updates Run to generate certs, mount SSL files, adjust env/networking, expose SSL port, and extend wait strategy.
TLS Materials & Creation
modules/cassandra/tls.go
Implements internal tlsCerts and createTLSCerts() to generate a CA and server cert, encode a PKCS#12 keystore (password "cassandra"), and construct a tls.Config with CA pool and ServerName "localhost".
Options Pattern / Public API
modules/cassandra/options.go
Adds Option type, WithTLS() option, a Customize NOOP to satisfy testcontainers.ContainerCustomizer, and default options to carry runtime tlsEnabled state.
Cassandra SSL Configuration
modules/cassandra/testdata/cassandra-ssl.yaml
Adds a Cassandra YAML configured for client encryption (client_encryption_options), native_transport_port_ssl, keystore references, and related SSL/security settings.
Tests & Examples
modules/cassandra/cassandra_test.go, modules/cassandra/examples_test.go
Adds TestCassandraWithTLS and ExampleRun_withTLS to start a TLS-enabled container, obtain TLSConfig(), create a TLS-enabled gocql session, and perform end-to-end TLS-protected operations.
Dependencies
modules/cassandra/go.mod
Adds dependencies github.com/mdelapenya/tlscert v0.2.0 and software.sslmate.com/src/go-pkcs12 v0.6.0 for certificate generation and PKCS#12 encoding.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant Test as Test / Client
    participant Runner as CassandraContainer.Run
    participant TLSGen as createTLSCerts()
    participant Container as Testcontainers GenericContainer
    participant Cassandra as Cassandra process
    participant ClientLib as gocql (TLS client)

    Test->>Runner: Run(..., WithTLS())
    Runner->>TLSGen: generate CA, server cert, PKCS#12 keystore
    TLSGen-->>Runner: tlsCerts (keystore bytes, tls.Config)
    Runner->>Container: Start with mounted keystore & cassandra-ssl.yaml, expose 9142
    Container->>Cassandra: Cassandra starts using client_encryption_options (keystore)
    Runner->>Runner: store settings.TLSConfig
    Test->>ClientLib: build cluster using TLSConfig()
    ClientLib->>Cassandra: Establish TLS connection on 9142
    Cassandra-->>ClientLib: TLS handshake + query responses
    ClientLib-->>Test: Query results
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Inspect modules/cassandra/tls.go for cert parameters, CA trust handling, and PKCS#12 encoding errors.
  • Verify options.go Customize integration with testcontainers and propagation of tlsEnabled.
  • Review cassandra.go changes: env var adjustments, mounts, exposed ports, wait strategy, and storage/exposure of TLSConfig.
  • Run new tests/examples to validate end-to-end TLS behavior.

Poem

🐇 I hopped in with a tiny CA and key,

I bundled a keystore snug for localhost to see,
Port nine-one-four-two now whispers encrypted light,
Cassandra greets clients under TLS at night,
A rabbit's quiet cheer for secure bytes in flight.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Description check ❓ Inconclusive The description is incomplete, containing only a template with empty sections for what the PR does and why it's important, without substantive implementation details. Fill in the mandatory 'What does this PR do?' and 'Why is it important?' sections with concrete details about the SSL/TLS implementation and motivation.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: adding SSL/TLS option support to the Cassandra module, matching the substantial TLS implementation across multiple files.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 178c16f and 42f32ec.

📒 Files selected for processing (4)
  • docs/modules/cassandra.md (2 hunks)
  • modules/cassandra/cassandra.go (4 hunks)
  • modules/cassandra/cassandra_test.go (1 hunks)
  • modules/cassandra/examples_test.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • modules/cassandra/examples_test.go
  • modules/cassandra/cassandra_test.go
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-09-29T13:57:14.636Z
Learnt from: mdelapenya
Repo: testcontainers/testcontainers-go PR: 3319
File: modules/arangodb/arangodb.go:46-57
Timestamp: 2025-09-29T13:57:14.636Z
Learning: In testcontainers-go ArangoDB module, the wait strategy combines port listening check with HTTP readiness check using wait.ForAll - both strategies are required and complementary, not redundant.

Applied to files:

  • modules/cassandra/cassandra.go
📚 Learning: 2025-09-29T15:08:18.694Z
Learnt from: mdelapenya
Repo: testcontainers/testcontainers-go PR: 3320
File: modules/artemis/artemis.go:98-103
Timestamp: 2025-09-29T15:08:18.694Z
Learning: In testcontainers-go, nat.Port is a type alias for string, so untyped string constants can be passed directly to functions expecting nat.Port (like wait.ForListeningPort) without explicit type conversion - the Go compiler handles the implicit conversion automatically.

Applied to files:

  • modules/cassandra/cassandra.go
📚 Learning: 2025-11-05T11:57:09.224Z
Learnt from: natsoman
Repo: testcontainers/testcontainers-go PR: 3452
File: modules/cosmosdb/cosmosdb.go:11-14
Timestamp: 2025-11-05T11:57:09.224Z
Learning: In the testcontainers-go CosmosDB module (modules/azure/cosmosdb/), the defaultProtocol is intentionally set to "http" (not "https") to avoid requiring users to perform certificate setup steps (downloading and trusting the emulator's self-signed certificate). This design prioritizes ease of use for test containers over strict emulator fidelity.

Applied to files:

  • modules/cassandra/cassandra.go
  • docs/modules/cassandra.md
🪛 LanguageTool
docs/modules/cassandra.md

[grammar] ~73-~73: Ensure spelling is correct
Context: ...the container will fail to start. #### WithTLS - Not available until the next release <a ...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: test (1.24.x, modules/cassandra) / test: modules/cassandra/1.24.x
  • GitHub Check: test (1.25.x, modules/cassandra) / test: modules/cassandra/1.25.x
  • GitHub Check: Analyze (go)
🔇 Additional comments (10)
docs/modules/cassandra.md (2)

73-89: LGTM! Clear and comprehensive TLS documentation.

The documentation accurately describes the WithTLS feature, including automatic certificate generation, SSL port exposure, and proper error handling. The code inclusion references and examples are appropriate.


107-115: LGTM! TLSConfig documentation is accurate.

The method documentation clearly explains the TLSConfig accessor and its requirements. The static analysis spelling warning for "WithTLS" on line 73 is a false positive—it's a valid Go method name, not a spelling error.

modules/cassandra/cassandra.go (8)

4-8: LGTM! All imports are necessary.

The new imports support TLS functionality: bytes for mounting files, crypto/tls for the TLS config type, embed for the SSL config YAML, and errors for error construction (addressing the linting feedback from previous reviews).


19-20: LGTM! Port constants are appropriate.

The standard Cassandra ports are correctly defined: 9042 for native transport and 9142 for SSL connections.


23-24: LGTM! Embedding SSL config is the right approach.

Using go:embed for the SSL configuration YAML is a good pattern—it bundles the config with the module and simplifies deployment.


29-29: LGTM! Settings field follows module patterns.

The settings field appropriately stores TLS state, following the pattern established in other testcontainers modules like Redis and Valkey.


35-38: LGTM! Port selection logic is correct.

The ConnectionHost method appropriately selects the SSL port when TLS is enabled, maintaining backward compatibility for non-TLS usage.


41-48: LGTM! TLSConfig method correctly returns error.

The method signature and error handling address previous review feedback, returning a clear error when TLS is not enabled rather than just returning nil.


95-103: LGTM! Option processing follows established patterns.

The option processing logic correctly filters custom options via type assertion and applies them to settings, matching the pattern used in the Redis module as discussed in previous reviews.


124-165: No actionable changes needed. The CASSANDRA_BROADCAST_RPC_ADDRESS setting to "127.0.0.1" is intentional and correct for test containers. Clients connect via the address returned by ctr.ConnectionHost(), which provides the Docker port mapping, not the broadcast address. The cassandra-ssl.yaml configuration explicitly documents this pattern, and the TestCassandraWithTLS test suite confirms TLS connections work correctly with full data operations (CREATE, INSERT, SELECT) completing successfully.

Likely an incorrect or invalid review comment.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (3)
modules/cassandra/options.go (3)

15-20: Make TLSConfig fields private to reduce API surface area.

The public fields increase the API surface area and make future refactoring difficult. Since these fields are accessed through the TLSConfig() method, they should be private.

Based on past review feedback, if the tlscert library is adopted (as requested), the paths may not be needed at all—only the *tls.Config would be necessary.

Apply this diff to make the fields private:

 // TLSConfig represents the TLS configuration for Cassandra
 type TLSConfig struct {
-	KeystorePath    string
-	CertificatePath string
-	Config          *tls.Config
+	keystorePath    string
+	certificatePath string
+	config          *tls.Config
 }

Then update the accessor method and any references accordingly.


31-33: Critical bug: Options are discarded on every call.

Line 32 creates a fresh Options{} instead of accumulating settings across multiple option calls. This means any TLS configuration set by WithSSL() will be lost, and the container won't have access to the TLS settings.

This exact issue was flagged in previous reviews: "while this will run there options won't be accessible."

The current implementation should be treated as a no-op until the broader options refactoring is completed. However, to make it functional in the interim, the accumulated settings need to be passed through. The WithSSL function should directly modify the GenericContainerRequest without relying on the Options struct being carried forward by Customize.

One interim approach is to store the accumulated options outside the Customize call chain, but this requires broader changes to how Run accesses the settings. See modules/cassandra/cassandra.go lines 79-135 for how settings are currently extracted.


81-122: Make function private and plan for removal.

This function was requested to be made private in previous reviews to reduce API surface area. More importantly, it should be removed entirely once the tlscert library is adopted (see comment on lines 35-79).

The reliance on external keytool creates several issues:

  • Not available on all platforms (requires Java/JDK installation)
  • Harder to maintain and test
  • Inconsistent with other testcontainers-go modules

If keeping this temporarily during the transition:

-// GenerateJKSKeystore generates a JKS keystore with a self-signed cert using keytool, and extracts the public cert for Go client trust.
-func GenerateJKSKeystore() (keystorePath, certPath string, err error) {
+// generateJKSKeystore generates a JKS keystore with a self-signed cert using keytool, and extracts the public cert for Go client trust.
+// Deprecated: Will be removed once tlscert-based implementation is complete.
+func generateJKSKeystore() (keystorePath, certPath string, err error) {

Then update the call in WithSSL (line 40) accordingly. However, prioritize replacing this entirely with the tlscert approach.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ae0c648 and 86f661b.

📒 Files selected for processing (6)
  • modules/cassandra/cassandra.go (3 hunks)
  • modules/cassandra/cassandra_test.go (7 hunks)
  • modules/cassandra/examples_test.go (2 hunks)
  • modules/cassandra/options.go (1 hunks)
  • modules/cassandra/options_test.go (1 hunks)
  • modules/cassandra/testdata/cassandra-ssl.yaml (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (5)
modules/cassandra/examples_test.go (4)
modules/cassandra/cassandra.go (2)
  • Run (80-136)
  • WithConfigFile (42-52)
modules/cassandra/options.go (2)
  • WithSSL (36-79)
  • TLSConfig (16-20)
cleanup.go (1)
  • TerminateContainer (97-108)
log/logger.go (1)
  • Printf (47-49)
modules/cassandra/options.go (3)
generic.go (1)
  • GenericContainerRequest (21-27)
container.go (1)
  • ContainerFile (110-115)
modules/cassandra/cassandra.go (1)
  • Run (80-136)
modules/cassandra/cassandra_test.go (3)
modules/cassandra/cassandra.go (3)
  • Run (80-136)
  • WithConfigFile (42-52)
  • WithInitScripts (55-71)
modules/cassandra/options.go (2)
  • WithSSL (36-79)
  • TLSConfig (16-20)
testing.go (1)
  • CleanupContainer (91-97)
modules/cassandra/cassandra.go (7)
modules/cassandra/options.go (2)
  • Options (23-25)
  • TLSConfig (16-20)
container.go (1)
  • ContainerRequest (131-171)
generic.go (2)
  • GenericContainerRequest (21-27)
  • GenericContainer (52-98)
wait/host_port.go (1)
  • ForListeningPort (67-69)
wait/exec.go (1)
  • ForExec (71-73)
options.go (1)
  • WithWaitStrategy (366-368)
wait/all.go (1)
  • ForAll (44-48)
modules/cassandra/options_test.go (3)
generic.go (1)
  • GenericContainerRequest (21-27)
container.go (1)
  • ContainerRequest (131-171)
modules/cassandra/options.go (4)
  • Options (23-25)
  • WithSSL (36-79)
  • TLSConfig (16-20)
  • GenerateJKSKeystore (82-122)
🪛 GitHub Actions: Main pipeline
modules/cassandra/cassandra.go

[error] 17-17: undefined: nat

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (go)
🔇 Additional comments (1)
modules/cassandra/options.go (1)

35-79: Cannot confirm PEM-based TLS support in test data
I didn’t find any store_type: PEM entries in modules/cassandra/testdata. Please verify that your Cassandra version (4.0+) and testdata configuration support PEM-based TLS or update the testdata accordingly.

@mdelapenya
Copy link
Member

@gaby @MitulShah1 thanks for the ping. I'll resolve the conflicts locally and will try to check the TLS issues mentioned above.

@MitulShah1 can you elaborate on those issues with tlscert?

# Conflicts:
#	modules/cassandra/cassandra.go
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
modules/cassandra/cassandra.go (1)

80-107: Run has multiple compile-time and logic issues (invalid literal, unused vars, wrong identifiers)

This block currently won’t compile and also doesn’t appear to use the new ContainerRequest:

  • req := testcontainers.ContainerRequest{ ... }:
    • The struct literal is syntactically invalid: Env: map[string]string{...}), testcontainers.WithWaitStrategy(...), leaves an extra ) after the map literal and introduces testcontainers.WithWaitStrategy(...) as a bare value in the struct, which is not keyed to any field. This matches the golangci-lint “unexpected ) in composite literal” error.
    • req is never used, so even once syntax is fixed you’ll get req declared and not used.
  • ctr, err := testcontainers.Run(ctx, img, moduleOpts...):
    • ctr is never used; later you reference container instead, which is undefined in this function.
  • In the next lines:
    • if container != nil { c = &CassandraContainer{Container: container, settings: settings} }
      • container isn’t declared in this scope; you probably meant ctr.
      • settings must come from the Options processing path; make sure it’s in scope here and set accordingly.

You’ll need to decide whether Run should:

  1. Use testcontainers.Run(ctx, img, ...) with ContainerCustomizers that set env and wait strategy (in which case you should remove the unused req entirely), or
  2. Build and pass a ContainerRequest through the lower-level API (GenericContainerRequest), in which case testcontainers.Run’s signature might not be the right call.

At minimum, to fix the immediate issues:

  • Make the struct literal valid or remove req if not used.
  • Replace container with ctr (and actually use ctr), and ensure settings is in scope and populated.
  • Confirm moduleOpts is defined in this package and includes any TLS/SSL customizers you intend.

Until these are addressed, this function will not compile.

♻️ Duplicate comments (2)
modules/cassandra/cassandra.go (2)

115-121: Consider returning (*tls.Config, error) from TLSConfig instead of a bare pointer

The new TLSConfig() accessor returns nil when TLS is not enabled. That works, but callers then have to remember to check for nil vs. treat it as a hard error.

Given prior discussion on similar methods in Redis/Valkey, it would be more explicit to return an error when TLS isn’t enabled, e.g.:

func (c *CassandraContainer) TLSConfig() (*tls.Config, error) {
	if c.settings.tlsConfig == nil {
		return nil, errors.New("tls not enabled")
	}
	return c.settings.tlsConfig.Config, nil
}

This makes misuse easier to detect and keeps patterns consistent across modules.

Check the current Redis and Valkey modules in testcontainers-go to confirm the preferred TLSConfig API shape (returning (*tls.Config, error) vs *tls.Config).

3-19: Missing nat import breaks the new port constants

port and securePort are declared as nat.Port("9042/tcp") / "9142/tcp", but github.com/docker/go-connections/nat is not imported. This file will not compile (undefined: nat).

Add the missing import to the import block:

 import (
 	"context"
 	"crypto/tls"
 	"fmt"
 	"io"
 	"path/filepath"
 	"strings"
 	"time"

+	"github.com/docker/go-connections/nat"
 	"github.com/testcontainers/testcontainers-go"
 	"github.com/testcontainers/testcontainers-go/wait"
 )
🧹 Nitpick comments (1)
modules/cassandra/cassandra.go (1)

21-37: Ensure settings is correctly initialised before using it in ConnectionHost

The new TLS-aware ConnectionHost picks securePort when c.settings.tlsConfig != nil, otherwise falls back to the plain port. That logic is fine, but it assumes:

  • c.settings is always initialised with the effective Options when the container is created.
  • tlsConfig is only non‑nil when TLS is actually enabled.

Please double-check that Run (and any other constructors) always populate settings correctly, including the non‑TLS path, so ConnectionHost never sees a zero‑value Options due to missed wiring. This will also keep behavior consistent with the TLSConfig accessor below.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 86f661b and 879e285.

📒 Files selected for processing (1)
  • modules/cassandra/cassandra.go (4 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-09-29T13:57:14.636Z
Learnt from: mdelapenya
Repo: testcontainers/testcontainers-go PR: 3319
File: modules/arangodb/arangodb.go:46-57
Timestamp: 2025-09-29T13:57:14.636Z
Learning: In testcontainers-go ArangoDB module, the wait strategy combines port listening check with HTTP readiness check using wait.ForAll - both strategies are required and complementary, not redundant.

Applied to files:

  • modules/cassandra/cassandra.go
📚 Learning: 2025-09-29T15:08:18.694Z
Learnt from: mdelapenya
Repo: testcontainers/testcontainers-go PR: 3320
File: modules/artemis/artemis.go:98-103
Timestamp: 2025-09-29T15:08:18.694Z
Learning: In testcontainers-go, nat.Port is a type alias for string, so untyped string constants can be passed directly to functions expecting nat.Port (like wait.ForListeningPort) without explicit type conversion - the Go compiler handles the implicit conversion automatically.

Applied to files:

  • modules/cassandra/cassandra.go
🪛 GitHub Actions: Main pipeline
modules/cassandra/cassandra.go

[error] 1-1: syntax error: unexpected ) in composite literal; possibly missing comma or } (from golangci-lint)


[error] 90-90: syntax error: unexpected ) in composite literal; possibly missing comma or } (from golangci-lint)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (go)

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
modules/cassandra/cassandra.go (1)

40-44: Consider returning (*tls.Config, error) instead of *tls.Config

Right now callers have to infer “TLS not enabled” from a nil pointer. Exposing:

func (c *CassandraContainer) TLSConfig() (*tls.Config, error)

with an explicit error when TLS wasn’t enabled would align better with the pattern discussed for other modules (e.g. Redis/Valkey) and avoid silent misuse.

🧹 Nitpick comments (1)
modules/cassandra/cassandra.go (1)

120-161: Clarify interaction between WithTLS and WithConfigFile for cassandra.yaml

In the TLS branch you mount an embedded cassandra-ssl.yaml to /etc/cassandra/cassandra.yaml, and user options are appended afterwards:

moduleOpts = append(moduleOpts, opts...)

WithConfigFile also writes to /etc/cassandra/cassandra.yaml, so combining WithTLS() and WithConfigFile(...) means whichever runs last wins, which could silently disable the TLS configuration.

Consider either:

  • documenting that WithTLS should not be combined with WithConfigFile, or
  • detecting this combination and returning an error (or choosing a clear precedence) to avoid surprising behavior.
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 879e285 and fd5772d.

⛔ Files ignored due to path filters (1)
  • modules/cassandra/go.sum is excluded by !**/*.sum
📒 Files selected for processing (7)
  • modules/cassandra/cassandra.go (4 hunks)
  • modules/cassandra/cassandra_test.go (1 hunks)
  • modules/cassandra/examples_test.go (1 hunks)
  • modules/cassandra/go.mod (1 hunks)
  • modules/cassandra/options.go (1 hunks)
  • modules/cassandra/testdata/cassandra-ssl.yaml (1 hunks)
  • modules/cassandra/tls.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • modules/cassandra/testdata/cassandra-ssl.yaml
  • modules/cassandra/options.go
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-09-18T08:24:27.479Z
Learnt from: mdelapenya
Repo: testcontainers/testcontainers-go PR: 3254
File: .github/dependabot.yml:21-21
Timestamp: 2025-09-18T08:24:27.479Z
Learning: In the testcontainers-go repository, submodules like atlaslocal that are part of a parent module (e.g., mongodb) share the same go.mod file and should not have separate Dependabot entries. They are already monitored through the parent module's Dependabot configuration entry.

Applied to files:

  • modules/cassandra/go.mod
📚 Learning: 2025-09-29T13:57:14.636Z
Learnt from: mdelapenya
Repo: testcontainers/testcontainers-go PR: 3319
File: modules/arangodb/arangodb.go:46-57
Timestamp: 2025-09-29T13:57:14.636Z
Learning: In testcontainers-go ArangoDB module, the wait strategy combines port listening check with HTTP readiness check using wait.ForAll - both strategies are required and complementary, not redundant.

Applied to files:

  • modules/cassandra/cassandra.go
📚 Learning: 2025-09-29T15:08:18.694Z
Learnt from: mdelapenya
Repo: testcontainers/testcontainers-go PR: 3320
File: modules/artemis/artemis.go:98-103
Timestamp: 2025-09-29T15:08:18.694Z
Learning: In testcontainers-go, nat.Port is a type alias for string, so untyped string constants can be passed directly to functions expecting nat.Port (like wait.ForListeningPort) without explicit type conversion - the Go compiler handles the implicit conversion automatically.

Applied to files:

  • modules/cassandra/cassandra.go
🧬 Code graph analysis (3)
modules/cassandra/examples_test.go (3)
modules/cassandra/cassandra.go (1)
  • Run (90-176)
modules/cassandra/options.go (1)
  • WithTLS (42-47)
cleanup.go (1)
  • TerminateContainer (97-108)
modules/cassandra/cassandra_test.go (2)
modules/cassandra/cassandra.go (1)
  • Run (90-176)
modules/cassandra/options.go (1)
  • WithTLS (42-47)
modules/cassandra/cassandra.go (3)
modules/cassandra/options.go (1)
  • Option (19-19)
options.go (1)
  • WithFiles (524-529)
modules/redis/redis.go (1)
  • Run (58-139)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: test (1.24.x, modules/cassandra) / test: modules/cassandra/1.24.x
  • GitHub Check: test (1.25.x, modules/cassandra) / test: modules/cassandra/1.25.x
  • GitHub Check: Analyze (go)
🔇 Additional comments (5)
modules/cassandra/go.mod (1)

7-13: TLS dependencies for Cassandra module look appropriate

The added module dependencies line up with the new TLS certificate and PKCS#12 handling in this module; no issues from a modularity or usage standpoint.

modules/cassandra/cassandra_test.go (1)

121-170: TLS integration test gives good end‑to‑end coverage

This test exercises the TLS option, validates that a TLS config is exposed, and runs real queries over the TLS connection, which is exactly what we need to guard the new behavior.

modules/cassandra/examples_test.go (1)

71-133: TLS example is clear and consistent with the non‑TLS example

The example mirrors the existing non‑TLS flow while showing how to enable TLS and use the exposed TLSConfig, so it’s a useful and consistent addition.

modules/cassandra/tls.go (1)

80-96: The proposed change to remove InsecureSkipVerify may introduce hostname verification failures

Setting InsecureSkipVerify: true is generally a security concern, but removing it without ensuring the self-signed certificate includes "localhost" as a Subject Alternative Name (SAN) or Common Name (CN) will cause TLS handshake failures. Certificates generated in container environments are typically issued for the container's hostname, not "localhost".

To properly address this:

  • Either regenerate the self-signed certificate to include "localhost" as a SAN, then remove InsecureSkipVerify: true
  • Or document why InsecureSkipVerify: true is necessary for this test-only setup and consider an alternative hostname that matches the cert

Simply removing the line without fixing the underlying hostname mismatch will break the tests.

modules/cassandra/cassandra.go (1)

91-99: Verify that the Option type includes the Customize method to implement ContainerCustomizer

The code at lines 91-99 correctly performs a type assertion to apply module-specific options, but this pattern requires Option to implement the testcontainers.ContainerCustomizer interface. According to the testcontainers-go module pattern, Option must define a Customize(req *testcontainers.GenericContainerRequest) error method (typically a no-op that returns nil) alongside its function signature type Option func(*options) error.

Without this method, callers passing cassandra.WithTLS() and similar option functions to Run as testcontainers.ContainerCustomizer parameters will either fail to compile or silently skip the option, leaving settings like tlsEnabled unset.

@MitulShah1
Copy link
Contributor Author

@mdelapenya @stevenh thanks for patience, i've fixed all issues please have a look again and let me know if any changes :)

@MitulShah1 MitulShah1 requested a review from stevenh December 5, 2025 07:35
mdelapenya
mdelapenya previously approved these changes Dec 5, 2025
Copy link
Member

@mdelapenya mdelapenya left a comment

Choose a reason for hiding this comment

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

LGTM! Thanks @MitulShah1 for your work and sorry for the late review. I just added a few comments regarding the missing docs, which are needed. But I'm already approving the PR waiting for the docs to be in place.

Cheers!

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 545a00e and ab26e27.

📒 Files selected for processing (4)
  • docs/modules/cassandra.md (1 hunks)
  • modules/cassandra/cassandra.go (4 hunks)
  • modules/cassandra/cassandra_test.go (1 hunks)
  • modules/cassandra/examples_test.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • modules/cassandra/examples_test.go
  • modules/cassandra/cassandra_test.go
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-09-29T13:57:14.636Z
Learnt from: mdelapenya
Repo: testcontainers/testcontainers-go PR: 3319
File: modules/arangodb/arangodb.go:46-57
Timestamp: 2025-09-29T13:57:14.636Z
Learning: In testcontainers-go ArangoDB module, the wait strategy combines port listening check with HTTP readiness check using wait.ForAll - both strategies are required and complementary, not redundant.

Applied to files:

  • modules/cassandra/cassandra.go
📚 Learning: 2025-09-29T15:08:18.694Z
Learnt from: mdelapenya
Repo: testcontainers/testcontainers-go PR: 3320
File: modules/artemis/artemis.go:98-103
Timestamp: 2025-09-29T15:08:18.694Z
Learning: In testcontainers-go, nat.Port is a type alias for string, so untyped string constants can be passed directly to functions expecting nat.Port (like wait.ForListeningPort) without explicit type conversion - the Go compiler handles the implicit conversion automatically.

Applied to files:

  • modules/cassandra/cassandra.go
📚 Learning: 2025-11-05T11:57:09.224Z
Learnt from: natsoman
Repo: testcontainers/testcontainers-go PR: 3452
File: modules/cosmosdb/cosmosdb.go:11-14
Timestamp: 2025-11-05T11:57:09.224Z
Learning: In the testcontainers-go CosmosDB module (modules/azure/cosmosdb/), the defaultProtocol is intentionally set to "http" (not "https") to avoid requiring users to perform certificate setup steps (downloading and trusting the emulator's self-signed certificate). This design prioritizes ease of use for test containers over strict emulator fidelity.

Applied to files:

  • modules/cassandra/cassandra.go
🪛 GitHub Actions: Main pipeline
modules/cassandra/cassandra.go

[error] 44-44: golangci-lint: error-format: fmt.Errorf can be replaced with errors.New (perfsprint)

🪛 LanguageTool
docs/modules/cassandra.md

[grammar] ~73-~73: Ensure spelling is correct
Context: ...the container will fail to start. #### WithTLS - Not available until the next release <a ...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (go)
🔇 Additional comments (9)
modules/cassandra/cassandra.go (9)

4-7: LGTM!

The added imports support the TLS implementation correctly: bytes for config reader, crypto/tls for TLS types, and embed for bundling the SSL config file.


18-19: LGTM!

Standard Cassandra port definitions: 9042 for native protocol and 9142 for SSL-enabled native protocol.


22-23: LGTM!

Embedding the SSL configuration file is a good practice that ensures the TLS setup is self-contained within the module.


28-28: LGTM!

The settings field stores the container's options, including TLS state, which is necessary for the TLS feature implementation.


34-36: LGTM!

Correctly routes connection requests to the SSL port when TLS is enabled.


94-102: LGTM!

The option processing correctly implements the options pattern, extracting and applying custom options before container creation.


159-162: LGTM!

Adding a wait strategy for the SSL port ensures the container is fully ready before client connections are attempted. The use of WithAdditionalWaitStrategy properly complements the existing wait strategies.


105-105: Verify whether the non-SSL port should remain exposed when TLS is enabled.

Both the regular port (9042) and SSL port (9142) are exposed when TLS is enabled. If the non-SSL port remains functional, clients could bypass encryption, creating a security gap.

Confirm whether:

  1. The embedded cassandra-ssl.yaml configuration disables the non-SSL port (9042)
  2. It is intentional to allow both SSL and non-SSL connections simultaneously

Also applies to: 136-136


138-138: Confirm whether CASSANDRA_BROADCAST_RPC_ADDRESS should be "127.0.0.1" in a testcontainers context.

Setting CASSANDRA_BROADCAST_RPC_ADDRESS to 127.0.0.1 will cause clients connecting from the host machine to attempt connecting back to their own localhost when using Cassandra's cluster metadata discovery. While this may work for single-node test setups where clients don't rely on cluster metadata, it will break multi-node configurations and certain Cassandra driver behaviors that fetch node information from the cluster.

The standard pattern for testcontainers is to either use the container's internal bridge network address or rely on port mapping for discovery. Verify with a test that clients can successfully connect and discover nodes when this configuration is active.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8d54d5f and 178c16f.

📒 Files selected for processing (1)
  • docs/modules/cassandra.md (1 hunks)
🧰 Additional context used
🪛 LanguageTool
docs/modules/cassandra.md

[grammar] ~73-~73: Ensure spelling is correct
Context: ...the container will fail to start. #### WithTLS - Not available until the next release <a ...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: test (1.25.x, modules/cassandra) / test: modules/cassandra/1.25.x
  • GitHub Check: test (1.24.x, modules/cassandra) / test: modules/cassandra/1.24.x
  • GitHub Check: Analyze (go)

@MitulShah1 MitulShah1 force-pushed the add-ssl-option-cassandra branch from 178c16f to 50579f9 Compare December 8, 2025 05:50
@MitulShah1 MitulShah1 requested a review from mdelapenya December 8, 2025 05:52
Copy link
Member

@mdelapenya mdelapenya left a comment

Choose a reason for hiding this comment

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

LGTM, thanks for the great hard work during the review.

Cheers!

@mdelapenya mdelapenya merged commit 75fb701 into testcontainers:main Dec 12, 2025
17 checks passed
@mdelapenya mdelapenya added the feature New functionality or new behaviors on the existing one label Dec 12, 2025
@mdelapenya mdelapenya self-assigned this Dec 12, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature New functionality or new behaviors on the existing one

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants