Skip to content

Commit d076e01

Browse files
authored
add integrity checks for openssl (#701)
1 parent 43edbf6 commit d076e01

File tree

7 files changed

+136
-1
lines changed

7 files changed

+136
-1
lines changed

.github/workflows/ci_linux_alpine_x86_64_musl_complementary.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ on:
4848
pull_request:
4949
paths:
5050
- '.github/workflows/ci_linux_alpine_x86_64_musl_complementary.yml'
51+
- 'spec/integrations/**'
5152
branches: [ main ]
5253
push:
5354
branches:

.github/workflows/ci_linux_debian_x86_64_gnu_complementary.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ on:
5454
pull_request:
5555
paths:
5656
- '.github/workflows/ci_linux_debian_x86_64_gnu_complementary.yml'
57+
- 'spec/integrations/**'
5758
branches: [ main ]
5859
push:
5960
branches:

.github/workflows/ci_linux_ubuntu_aarch64_gnu_complementary.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ on:
4949
pull_request:
5050
paths:
5151
- '.github/workflows/ci_linux_ubuntu_aarch64_gnu_complementary.yml'
52+
- 'spec/integrations/**'
5253
branches: [ main ]
5354
push:
5455
branches:

.github/workflows/ci_linux_ubuntu_x86_64_gnu_complementary.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ on:
4848
pull_request:
4949
paths:
5050
- '.github/workflows/ci_linux_ubuntu_x86_64_gnu_complementary.yml'
51+
- 'spec/integrations/**'
5152
branches: [ main ]
5253
push:
5354
branches:

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Rdkafka Changelog
22

3+
## 0.23.1 (Unreleased)
4+
- [Fix] Fix incorrectly set default SSL certs dir.
5+
- [Fix] Disable OpenSSL Heartbeats during compilation.
6+
37
## 0.23.0 (2025-09-04)
48
- **[Breaking]** Drop support for Ruby 3.1 to move forward with the fiber scheduler work.
59
- [Enhancement] Bump librdkafka to `2.11.0`

lib/rdkafka/version.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# frozen_string_literal: true
22

33
module Rdkafka
4-
VERSION = "0.23.0"
4+
VERSION = "0.23.1"
55
LIBRDKAFKA_VERSION = "2.11.0"
66
LIBRDKAFKA_SOURCE_SHA256 = "592a823dc7c09ad4ded1bc8f700da6d4e0c88ffaf267815c6f25e7450b9395ca"
77
end
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
# frozen_string_literal: true
2+
3+
# This integration test verifies that rdkafka properly detects and reports specific SSL
4+
# configuration errors when attempting to connect to an SSL-enabled Kafka broker.
5+
#
6+
# It also ensures that we do not statically link ssl certs into incorrect tmp cert location.
7+
#
8+
# These errors occur when rdkafka's underlying OpenSSL library encounters issues
9+
# with SSL certificate validation, particularly related to file scheme handling
10+
# and missing certificate directories.
11+
#
12+
# Exit codes:
13+
# - 0: Target error messages NOT detected after 5 seconds (test fails - errors missing)
14+
# - 1: Target error messages detected (test passes - errors are present as expected)
15+
# - 2: Unexpected exception occurred during test execution
16+
17+
require 'rdkafka'
18+
require 'socket'
19+
require 'openssl'
20+
require 'stringio'
21+
require 'logger'
22+
23+
$stdout.sync = true
24+
25+
captured_output = StringIO.new
26+
Rdkafka::Config.logger = Logger.new(captured_output)
27+
28+
# Start a dummy SSL server with self-signed certificate
29+
ssl_server_thread = Thread.new do
30+
begin
31+
# Create TCP server
32+
tcp_server = TCPServer.new('localhost', 9099)
33+
34+
# Generate self-signed certificate
35+
key = OpenSSL::PKey::RSA.new(2048)
36+
cert = OpenSSL::X509::Certificate.new
37+
cert.version = 2
38+
cert.serial = 1
39+
cert.subject = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-test/CN=localhost")
40+
cert.issuer = cert.subject
41+
cert.public_key = key.public_key
42+
cert.not_before = Time.now
43+
cert.not_after = cert.not_before + 365 * 24 * 60 * 60 # 1 year
44+
45+
# Add extensions
46+
ef = OpenSSL::X509::ExtensionFactory.new
47+
ef.subject_certificate = cert
48+
ef.issuer_certificate = cert
49+
cert.add_extension(ef.create_extension('basicConstraints', 'CA:TRUE', true))
50+
cert.add_extension(ef.create_extension('keyUsage', 'keyCertSign, cRLSign', true))
51+
cert.add_extension(ef.create_extension('subjectKeyIdentifier', 'hash', false))
52+
cert.add_extension(ef.create_extension('authorityKeyIdentifier', 'keyid:always', false))
53+
54+
cert.sign(key, OpenSSL::Digest::SHA256.new)
55+
56+
# Create SSL context
57+
ssl_context = OpenSSL::SSL::SSLContext.new
58+
ssl_context.cert = cert
59+
ssl_context.key = key
60+
61+
# Wrap TCP server with SSL
62+
ssl_server = OpenSSL::SSL::SSLServer.new(tcp_server, ssl_context)
63+
64+
loop do
65+
begin
66+
client = ssl_server.accept
67+
client.puts('Invalid Kafka broker')
68+
client.close
69+
rescue => e
70+
# Ignore SSL server errors - they're expected
71+
end
72+
end
73+
rescue => e
74+
puts "SSL server error: #{e.message}"
75+
end
76+
end
77+
78+
# Give the server time to start
79+
sleep 1
80+
81+
# Try connecting to the dummy SSL server
82+
config = Rdkafka::Config.new(
83+
'bootstrap.servers': 'localhost:9099',
84+
"security.protocol": 'SSL',
85+
"client.id": "test-client",
86+
"group.id": "test-group"
87+
)
88+
89+
begin
90+
consumer = config.consumer
91+
puts 'Consumer created, attempting to consume...'
92+
consumer.subscribe('test-topic')
93+
94+
# Try to poll for messages - this triggers SSL errors
95+
start_time = Time.now
96+
timeout = 5
97+
98+
while Time.now - start_time < timeout
99+
begin
100+
consumer.poll(1000)
101+
rescue => poll_error
102+
puts "Caught expected SSL error: #{poll_error.class}"
103+
break
104+
end
105+
end
106+
107+
puts 'Test completed'
108+
109+
# Wait for rdkafka to finish logging errors
110+
sleep 2
111+
112+
# Check captured logs for target error patterns
113+
captured_output.rewind
114+
captured_output.readlines.each do |line|
115+
exit(1) if line.include?('routines::unregistered scheme')
116+
exit(1) if line.include?('system library::No such file or directory')
117+
end
118+
rescue => e
119+
puts "SSL certificate validation error: #{e.class}"
120+
exit(2)
121+
ensure
122+
consumer&.close if defined?(consumer) && consumer
123+
ssl_server_thread.kill if ssl_server_thread
124+
end
125+
126+
# Exit with 0 if target errors not detected
127+
exit(0)

0 commit comments

Comments
 (0)