feat(consumer): build TLS and SASL from config - #166
Conversation
The producer Builder applies the STREAMING_TLS_* / STREAMING_SASL_* surface through TLSFromConfig / SASLFromConfig; the ConsumerBuilder only took a built *tls.Config and sasl.Mechanism, so every consuming service re-implemented the mechanism switch and CA decoding to reach the same broker. ConsumerBuilder.TLSFromConfig and .SASLFromConfig now call the same Config.BuildTLSConfig and kafkasec.BuildSASLMechanism the producer calls, with the producer's semantics: disabled TLS and an empty mechanism are no-ops, an empty mechanism never opens the plaintext gate, and a malformed CA or invalid mechanism is deferred to Build (first error wins) as ErrInvalidTLSConfig / ErrInvalidSASLMechanism. The deferred error surfaces only on an enabled Build, so the Enabled(false) kill switch stays a pure no-op.
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Essentials Run ID: 📒 Files selected for processing (2)
Included review availability: This review used your included allowance. 0 included reviews remain after this review. Your included PR review attempts over the past 7 days set your current allowance at 1 review per hour. 📝 WalkthroughWalkthroughConsumerBuilder can now apply TLS and SASL settings from shared configuration. It defers configuration errors until an enabled build and skips this check for disabled builds. Tests and documentation cover the new methods and behavior. ChangesConsumer Configuration
Priority: ⬇️ Low Merge Risk: ⚪ Minimal · up to The consumer TLS and SASL configuration behavior matches its documented contract, with no identified issue that should block merging. ✨ Finishing Touches✨ Simplify code
Comment |
🔒 Security Scan Results —
|
| Stage | Status | Blocking? |
|---|---|---|
| Filesystem Scan | ✅ Clean | — |
| Docker Image Scan | ➖ Skipped | — |
| Docker Hub Health Score | ➖ Skipped | — |
| Pre-release Version Check | ✅ Clean | — |
Trivy
Filesystem Scan
✅ No vulnerabilities or secrets found.
Pre-release Version Check
✅ No unstable version pins found.
🔍 PR Validation Summary✅ PR Mergeable — no blocking failures
|
📊 Unit Test Coverage Report:
|
| Metric | Value |
|---|---|
| Overall Coverage | 86.9% ✅ PASS |
| Threshold | 80% |
Coverage by Package
| Package | Coverage |
|---|---|
github.com/LerianStudio/lib-streaming/v4/billing |
97.3% |
github.com/LerianStudio/lib-streaming/v4/internal/buildmeta |
100.0% |
github.com/LerianStudio/lib-streaming/v4/internal/cloudevents |
93.7% |
github.com/LerianStudio/lib-streaming/v4/internal/config |
86.8% |
github.com/LerianStudio/lib-streaming/v4/internal/consumer |
92.3% |
github.com/LerianStudio/lib-streaming/v4/internal/contract |
85.0% |
github.com/LerianStudio/lib-streaming/v4/internal/dlqheader |
33.3% |
github.com/LerianStudio/lib-streaming/v4/internal/emitter |
100.0% |
github.com/LerianStudio/lib-streaming/v4/internal/kafkasec |
84.9% |
github.com/LerianStudio/lib-streaming/v4/internal/manifest |
84.0% |
github.com/LerianStudio/lib-streaming/v4/internal/producer |
89.2% |
github.com/LerianStudio/lib-streaming/v4/internal/transport/eventbridge |
87.3% |
github.com/LerianStudio/lib-streaming/v4/internal/transport/kafka |
56.4% |
github.com/LerianStudio/lib-streaming/v4/internal/transport/rabbitmq |
93.2% |
github.com/LerianStudio/lib-streaming/v4/internal/transport/sqs |
84.4% |
github.com/LerianStudio/lib-streaming/v4/internal/transport |
96.7% |
github.com/LerianStudio/lib-streaming/v4/streamingtest |
90.7% |
github.com/LerianStudio/lib-streaming/v4 |
86.4% |
Generated by Go PR Analysis workflow
|
@coderabbitai approve |
✅ Action performedComments resolved and changes approved. |
Problem
The producer
Builderapplies theSTREAMING_TLS_*/STREAMING_SASL_*surface withTLSFromConfig(cfg)/SASLFromConfig(cfg). TheConsumerBuilderonly takes a built*tls.Config(TLS) and a builtsasl.Mechanism(SASL), so every consuming service rebuilds the mechanism switch, the credential check and the plaintext opt-in by hand. Three consumers in br-sfn already do this (services/siloc/internal/silocstream/consumer_security.go,services/spb/internal/streamingcompat/consumer_security.go,services/spi/internal/spistream/consumer.go), each a copy of the lib's own producer logic.API added
ConsumerBuilder.TLSFromConfig(cfg Config) *ConsumerBuilderConsumerBuilder.SASLFromConfig(cfg Config) *ConsumerBuilderBoth call the construction the producer already calls (
Config.BuildTLSConfig,kafkasec.BuildSASLMechanism), so nothing was extracted or copied. Semantics match the producer:Buildreturns (ErrInvalidTLSConfig/ErrInvalidSASLMechanism); the first one wins.BuildwithErrPlaintextSASLNotAllowedunlessSASLAllowPlaintextis set.Build:Enabled(false)stays a pure no-op, matching how the disabled consumer already skipsValidate.Order note, unchanged:
FromConfig(consumerCfg)replaces the whole consumer config, so callTLSFromConfig/SASLFromConfigafter it (same asTLS/SASLtoday).Tests
api_consumer_tls_sasl_from_config_test.go(mirrorsbuilder_tls_sasl_from_config_test.go):TLSFromConfigwires TLS)SASL(...)still refused)TestConsumerBuilder_NilReceiverGuardscovers both new setters on a nil receiver.A mutation check made each of these five broken versions fail at least one case: TLS not wired, deferred error not surfaced, plaintext gate opened on an empty mechanism, last error wins, error surfaced on a disabled consumer.
Gates (local, at 35238da)
golangci-lint run ./...(v2.12.2, CI pin):0 issues.make test-unit:DONE 1988 tests,[ok] Unit tests passedmake check-tests:[ok] Tagged test package verification completedmake sec(gosec):Issues : 0go vet ./...,go vet -tags=unit ./...,go vet -tags=integration ./...: clean;gofmt -l .: emptyTLSFromConfig100%,SASLFromConfig100%Line delta
api_consumer.go)AGENTS.md,doc.go,docs/design/consumer.md)Once released, each br-sfn consumer deletes its hand-built SASL/TLS helper and calls
.TLSFromConfig(cfg).SASLFromConfig(cfg)on the builder.🤖 Generated with Claude Code