Skip to content

Commit dba87e9

Browse files
authored
Ensure openssl 3.0 compatibility of released packages (#476)
Fixes: #455 ## Problem recap #455 correctly observed that linking the static driver library included in release 1.0.0 (1.0.1 is also impacted) against an older OpenSSL fails, because the lib has undefined symbols that are only supplied by OpenSSL 3.3/3.4/3.5 or newer. Considering our OpenSSL minimum requirements is 3.0.2 (should be enough - this is present on Ubuntu 22.04, so quite an old one), this should be considered a bug in our build/release CI. There are three problems in particular: #### Problem 1: We have built packages with **_too new_** OpenSSL headers. This led to including functions not available at 3.0.x as unresolved symbols. #### Problem 2: We haven't verified that the released packages link against OpenSSL 3.0.x correctly. #### Problem 3: We didn't put any build info manifest in the released package. This @vladzcloudius noted in #455 as the minimum to address the issue. ## Solution ### Problem 2: OpenSSL 3.0.2 linking verification This PR introduces an OpenSSL verification Makefile recipe. Outline: 1. copy the already-built static archive and pkg-config metadata into a sysroot; 2. alongside, put OpenSSL 3.0.2 headers and static libraries from a pinned Launchpad deb; 3. attempt to compile and link `examples/ssl/ssl.c`. If the build environment was contaminated (e.g. by a newer OpenSSL with IDEA or 3.3+ APIs), the archive will contain symbol references that don't exist in OpenSSL 3.0 and the link will fail — catching the regression from issue #455. The verification runs in both PR CI (after `build-integration-test-bin`) and packaging CI (after `test-package-deb`), since both produce the static archive in `build/`. ### Problem 1: _too new_ OpenSSL in the building/packaging CI workflow The plot twist is that one week after we released 1.0.1 with **no** support for OpenSSL 3.0.x, once I freshly rebuilt the 1.0.1 package (in the same CI workflow) and attempted linkage against OpenSSL 3.0.2 using the new verification procedure, **it succeeded**. Investigation revealed that the fresh lib has much different _cgus_ (compile gen units) - different number and sizes. Most likely explanation: LTO in the Rust toolchain improved during that week, fixing the problem in our building/packaging CI. If the problem happens to strike back, our verification step will immediately catch it. We're thus guarded and safe. ### Problem 3: lack of build info in the package It makes sense to generate plaintext build info manifest (`Key: Value` lines) during build and put it in the built dev package. Exact contents of this build info is subject to discussion; this PR introduces what Opus came up with (and I believe it's a fine list of properties). ## PR contents in detail ### First 3 commits They are extracted from #438. These are small fixes. ### Next 3 commits Also extracted from #438. 1. Adds comments to existing logic in `scylla-rust-wrapper/CMakeLists.txt`. 2. Registers transitive deps for the driver in the CMake dep resolution subsystem, so that those who use the driver as a CMake dependency will get driver's deps pulled in into the dependency graph, resulting in correct linker invocation. 3. Publishes transitive deps in `scylladb_static.pc` (`pkg-config` manifest). This supports a common (according to my research) way that people configure their compiler & linker. More details in the commit message. ### Next commit Introduces the OpenSSL 3.0.2 compatibility verification, described earlier. ### Last 2 commits Introduce `BUILD_INFO` generation and include it in the generated `dev` packages. This addresses the main request of #455. <details><summary>`BUILD_INFO` contents when built on my machine:</summary> <p> Build Information for scylla-cpp-driver v1.0.0-145-g541cb277 Platform -------- OS: Ubuntu 25.10 Architecture: x86_64 Kernel: 6.17.0-35-generic glibc: 2.42 Toolchain --------- Rust: rustc 1.96.0 (ac68faa20 2026-05-25) Cargo: cargo 1.96.0 (30a34c682 2026-05-25) CMake: cmake version 3.31.6 CC: cc (Ubuntu 15.2.0-4ubuntu4) 15.2.0 OpenSSL (detected by openssl-sys at build time) ------------------------------------------------ Version: 3.5.0 Include path: /usr/include Disabled (osslconf): OPENSSL_NO_IDEA OPENSSL_NO_SSL3_METHOD Build Configuration ------------------- CMAKE_BUILD_TYPE: Release CMAKE_INSTALL_PREFIX: /usr CASS_BUILD_SHARED: ON CASS_BUILD_STATIC: ON LTO: true Panic strategy: abort Static Library Compatibility Notes ---------------------------------- The static archive (libscylladb_static.a) requires consumers to provide OpenSSL >= 3.0 at link time. The minimum OpenSSL version is determined by the build-time detection performed by the openssl-sys crate. Consumers linking on systems with a different OpenSSL configuration (e.g. different osslconf flags) may encounter undefined symbol errors for conditionally-compiled functions. </p> </details> <details><summary>`BUILD_INFO` contents when built in the CI:</summary> <p> Build Information for scylla-cpp-driver 6eff933 Platform -------- OS: Ubuntu 22.04.5 LTS Architecture: x86_64 Kernel: 6.8.0-1052-azure glibc: 2.35 unknown Toolchain --------- Rust: rustc 1.96.0 (ac68faa20 2026-05-25) Cargo: cargo 1.96.0 (30a34c682 2026-05-25) CMake: cmake version 3.31.6 CC: cc (Ubuntu 11.4.0-1ubuntu1~22.04.3) 11.4.0 OpenSSL (detected by openssl-sys at build time) ------------------------------------------------ Version: 3.0.2 Include path: /usr/include Disabled (osslconf): unknown (openssl-sys build output not found) Build Configuration ------------------- CMAKE_BUILD_TYPE: Release CMAKE_INSTALL_PREFIX: /usr CASS_BUILD_SHARED: ON CASS_BUILD_STATIC: ON LTO: true Panic strategy: abort Static Library Compatibility Notes ---------------------------------- The static archive (libscylladb_static.a) requires consumers to provide OpenSSL >= 3.0 at link time. The minimum OpenSSL version is determined by the build-time detection performed by the openssl-sys crate. Consumers linking on systems with a different OpenSSL configuration (e.g. different osslconf flags) may encounter undefined symbol errors for conditionally-compiled functions. </p> </details>
2 parents e6a498b + 3a9d388 commit dba87e9

6 files changed

Lines changed: 385 additions & 5 deletions

File tree

.github/workflows/build-cpack-packages.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ jobs:
4747
- name: Build and test DEB packages
4848
run: make test-package-deb
4949

50+
- name: Verify static driver links against OpenSSL 3.0 (issue #455)
51+
run: make verify-openssl-3.0-compat
52+
5053
- name: Collect artifacts
5154
if: inputs.save-artifacts
5255
run: make collect-package-artifacts

.github/workflows/build-lint-and-test.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ jobs:
4747
id: build-integration-test-bin
4848
run: make build-integration-test-bin
4949

50+
- name: Verify static driver links against OpenSSL 3.0 (issue #455)
51+
run: make verify-openssl-3.0-compat
52+
5053
- name: Save integration test binary
5154
uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
5255
id: save-integration-test-bin

Makefile

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -193,10 +193,11 @@ endif
193193
FULL_RUSTFLAGS := --cfg scylla_unstable --cfg cpp_integration_testing
194194

195195
CURRENT_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
196-
BUILD_DIR := "${CURRENT_DIR}build"
196+
BUILD_DIR := $(CURRENT_DIR)build
197197
INTEGRATION_TEST_BIN := ${BUILD_DIR}/cassandra-integration-tests
198198
CMAKE_FLAGS ?=
199199
CMAKE_BUILD_TYPE ?= Release
200+
OPENSSL_WIN_VERSION ?= 1.1.1u
200201

201202
ifeq ($(OS_TYPE),macos)
202203
CMAKE_INSTALL_PREFIX ?= /usr/local
@@ -274,6 +275,49 @@ build-integration-test-bin-if-missing:
274275
@cd "${BUILD_DIR}"
275276
cmake -DCASS_BUILD_INTEGRATION_TESTS=ON -DCMAKE_BUILD_TYPE=Release .. && (make -j 4 || make)
276277

278+
# =============================================================================
279+
# OpenSSL 3.0 Compatibility Verification
280+
# =============================================================================
281+
# Regression test for issue #455: ensures the static driver archive can link
282+
# against OpenSSL 3.0 (our minimum supported version). Rather than rebuilding
283+
# from source, this target uses the artifact already produced by the default
284+
# build (which enables both shared and static). If the archive references
285+
# symbols only available in OpenSSL >3.0 (e.g. due to build environment
286+
# contamination), the link fails.
287+
#
288+
# This target is Linux/amd64-only (matches our release artifact platform).
289+
# =============================================================================
290+
291+
OPENSSL_3_0_COMPAT_SYSROOT := /tmp/openssl-3.0-compat-sysroot
292+
OPENSSL_3_0_LIBSSL_DEV_URL := https://launchpad.net/ubuntu/+archive/primary/+files/libssl-dev_3.0.2-0ubuntu1_amd64.deb
293+
OPENSSL_3_0_LIBSSL_DEV_SHA256 := f3671a9f01aa92928db200b3d28f1acb782366882fe318a940649bd02363ceb6
294+
OPENSSL_3_0_LIBSSL_DEV_PATH := /tmp/libssl-dev_3.0.2.deb
295+
296+
verify-openssl-3.0-compat:
297+
@echo "=== Verifying static driver links against OpenSSL 3.0 (issue #455) ==="
298+
rm -rf "$(OPENSSL_3_0_COMPAT_SYSROOT)"
299+
DESTDIR="$(OPENSSL_3_0_COMPAT_SYSROOT)" cmake --install "$(BUILD_DIR)"
300+
curl -fL -o "$(OPENSSL_3_0_LIBSSL_DEV_PATH)" "$(OPENSSL_3_0_LIBSSL_DEV_URL)"
301+
echo "$(OPENSSL_3_0_LIBSSL_DEV_SHA256) $(OPENSSL_3_0_LIBSSL_DEV_PATH)" | sha256sum --check
302+
dpkg-deb -x "$(OPENSSL_3_0_LIBSSL_DEV_PATH)" "$(OPENSSL_3_0_COMPAT_SYSROOT)"
303+
rm -f "$(OPENSSL_3_0_COMPAT_SYSROOT)/usr/lib/x86_64-linux-gnu/libssl.so"
304+
rm -f "$(OPENSSL_3_0_COMPAT_SYSROOT)/usr/lib/x86_64-linux-gnu/libcrypto.so"
305+
PKG_CONFIG_SYSROOT_DIR="$(OPENSSL_3_0_COMPAT_SYSROOT)" \
306+
PKG_CONFIG_PATH="$(OPENSSL_3_0_COMPAT_SYSROOT)/usr/local/lib/x86_64-linux-gnu/pkgconfig:$(OPENSSL_3_0_COMPAT_SYSROOT)/usr/lib/x86_64-linux-gnu/pkgconfig" \
307+
pkg-config --libs --static scylladb_static
308+
cc \
309+
$$(PKG_CONFIG_SYSROOT_DIR="$(OPENSSL_3_0_COMPAT_SYSROOT)" \
310+
PKG_CONFIG_PATH="$(OPENSSL_3_0_COMPAT_SYSROOT)/usr/local/lib/x86_64-linux-gnu/pkgconfig:$(OPENSSL_3_0_COMPAT_SYSROOT)/usr/lib/x86_64-linux-gnu/pkgconfig" \
311+
pkg-config --cflags scylladb_static) \
312+
examples/ssl/ssl.c \
313+
$$(PKG_CONFIG_SYSROOT_DIR="$(OPENSSL_3_0_COMPAT_SYSROOT)" \
314+
PKG_CONFIG_PATH="$(OPENSSL_3_0_COMPAT_SYSROOT)/usr/local/lib/x86_64-linux-gnu/pkgconfig:$(OPENSSL_3_0_COMPAT_SYSROOT)/usr/lib/x86_64-linux-gnu/pkgconfig" \
315+
pkg-config --libs --static scylladb_static) \
316+
-o /tmp/openssl-3.0-compat-link-test
317+
@echo "=== OpenSSL 3.0 compatibility verified ==="
318+
rm -rf "$(OPENSSL_3_0_COMPAT_SYSROOT)" \
319+
"$(OPENSSL_3_0_LIBSSL_DEV_PATH)" /tmp/openssl-3.0-compat-link-test
320+
277321
build-examples:
278322
@echo "Building examples to ${EXAMPLES_DIR}"
279323
@mkdir "${BUILD_DIR}" >/dev/null 2>&1 || true
@@ -345,7 +389,7 @@ endif
345389

346390
.package-configure: .package-build-prepare
347391
ifeq ($(OS_TYPE),windows)
348-
cmake -S . -B build -G "Visual Studio 17 2022" -A x64 -DCMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE) -DOPENSSL_VERSION=1.1.1u $(CMAKE_FLAGS)
392+
cmake -S . -B build -G "Visual Studio 17 2022" -A x64 -DCMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE) -DOPENSSL_VERSION=$(OPENSSL_WIN_VERSION) $(CMAKE_FLAGS)
349393
else
350394
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE) -DCMAKE_INSTALL_PREFIX=$(CMAKE_INSTALL_PREFIX) $(CMAKE_FLAGS)
351395
endif
@@ -559,7 +603,7 @@ test-package-rpm: build-package
559603
fedora:latest \
560604
bash -c ' \
561605
set -euo pipefail; \
562-
dnf -y install make cmake gcc-c++ findutils rpm-build createrepo_c; \
606+
dnf -y install make cmake gcc-c++ findutils rpm-build zlib-devel createrepo_c; \
563607
$(MAKE) -C $(SMOKE_TEST_DIR) verify-driver-dev-rpm; \
564608
$(MAKE) -C $(SMOKE_TEST_DIR) remove-driver-dev-rpm || true; \
565609
$(MAKE) -C $(SMOKE_TEST_DIR) remove-driver-rpm || true; \

ci/generate-build-info.sh

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
#!/usr/bin/env bash
2+
# Generate BUILD_INFO metadata file capturing the build environment.
3+
# Usage: ci/generate-build-info.sh <output-path>
4+
#
5+
# The script degrades gracefully: fields that cannot be determined are
6+
# printed as "unknown". If bash is not available, CMake will skip this
7+
# step without failing the build (see CMakeLists.txt).
8+
9+
set -euo pipefail
10+
11+
OUTPUT="${1:?Usage: $0 <output-path>}"
12+
BUILD_DIR="$(cd "$(dirname "$OUTPUT")" && pwd)"
13+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
14+
SOURCE_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
15+
16+
# --- Helpers ---
17+
18+
cmake_cache_get() {
19+
local key="$1"
20+
local cache="$BUILD_DIR/CMakeCache.txt"
21+
if [ -f "$cache" ]; then
22+
grep "^${key}:" "$cache" 2>/dev/null | cut -d= -f2- || echo "unknown"
23+
else
24+
echo "unknown"
25+
fi
26+
}
27+
28+
# --- Driver version ---
29+
30+
VERSION=$(cd "$SOURCE_DIR" && git describe --tags --always 2>/dev/null || echo "unknown")
31+
32+
# --- Platform ---
33+
34+
ARCH=$(uname -m 2>/dev/null || echo "unknown")
35+
KERNEL=$(uname -r 2>/dev/null || echo "unknown")
36+
37+
case "${OSTYPE:-}" in
38+
linux-gnu*|linux*)
39+
if [ -f /etc/os-release ]; then
40+
OS=$(. /etc/os-release && echo "${PRETTY_NAME:-unknown}")
41+
else
42+
OS="Linux (unknown distro)"
43+
fi
44+
GLIBC=$(ldd --version 2>/dev/null | head -1 | grep -oE '[0-9]+\.[0-9]+$' || echo "unknown")
45+
;;
46+
darwin*)
47+
OS="macOS $(sw_vers -productVersion 2>/dev/null || echo unknown)"
48+
GLIBC="N/A"
49+
;;
50+
msys*|cygwin*|mingw*)
51+
OS="Windows"
52+
GLIBC="N/A"
53+
;;
54+
*)
55+
OS="unknown (${OSTYPE:-not set})"
56+
GLIBC="unknown"
57+
;;
58+
esac
59+
60+
# --- Toolchain ---
61+
62+
RUST_VERSION=$(rustc --version 2>/dev/null || echo "unknown")
63+
CARGO_VERSION=$(cargo --version 2>/dev/null || echo "unknown")
64+
CMAKE_VERSION_STR=$(cmake --version 2>/dev/null | head -1 || echo "unknown")
65+
CC_VERSION=$(${CC:-cc} --version 2>/dev/null | head -1 || echo "unknown")
66+
67+
# --- OpenSSL (from openssl-sys build script output) ---
68+
69+
OPENSSL_SYS_OUTPUT=""
70+
# The output file is at target/<profile>/build/openssl-sys-<hash>/output
71+
# Search within the cargo target directory used by this build.
72+
CARGO_TARGET_DIR=$(cmake_cache_get "CARGO_TARGET_DIR")
73+
if [ "$CARGO_TARGET_DIR" = "unknown" ] || [ ! -d "$CARGO_TARGET_DIR" ]; then
74+
# Fallback: search in the standard location
75+
CARGO_TARGET_DIR="$SOURCE_DIR/scylla-rust-wrapper/target"
76+
fi
77+
if [ -d "$CARGO_TARGET_DIR" ]; then
78+
OPENSSL_SYS_OUTPUT=$(find "$CARGO_TARGET_DIR" -path "*/openssl-sys-*/output" -type f 2>/dev/null | head -1)
79+
fi
80+
81+
if [ -n "$OPENSSL_SYS_OUTPUT" ] && [ -f "$OPENSSL_SYS_OUTPUT" ]; then
82+
OPENSSL_VERSION_HEX=$(grep "^cargo:version_number=" "$OPENSSL_SYS_OUTPUT" | cut -d= -f2 || echo "")
83+
OPENSSL_INCLUDE=$(grep "^cargo:include=" "$OPENSSL_SYS_OUTPUT" | cut -d= -f2 || echo "unknown")
84+
OSSLCONF_FLAGS=$(grep "^cargo:rustc-cfg=osslconf=" "$OPENSSL_SYS_OUTPUT" | sed 's/cargo:rustc-cfg=osslconf="\(.*\)"/\1/' | paste -sd ' ' || echo "none")
85+
86+
# Quoting from openssl docs:
87+
# > A build script can be used to detect the OpenSSL or LibreSSL version at compile time if needed. The `openssl-sys`
88+
# > crate propagates the version via the `DEP_OPENSSL_VERSION_NUMBER` and `DEP_OPENSSL_LIBRESSL_VERSION_NUMBER`
89+
# > environment variables to build scripts. The version format is a hex-encoding of the OpenSSL release version:
90+
# > `0xMNNFFPPS`. For example, version 1.0.2g’s encoding is `0x1_00_02_07_0`.
91+
#
92+
# However, OpenSSL 3.x changed the displaying, while encoding is still the same.
93+
# - In version 1.2.3.c, 3 was Fix and c was Patch.
94+
# - In version 3.2.1, 3 is Patch and Fix is not present (0).
95+
# We're only interested in OpenSSL 3+, so we can assume the version is in the Major.Minor.Patch format.
96+
if [ -n "$OPENSSL_VERSION_HEX" ]; then
97+
dec=$((16#$OPENSSL_VERSION_HEX))
98+
major=$(( (dec >> 28) & 0xF ))
99+
minor=$(( (dec >> 20) & 0xFF ))
100+
patch=$(( (dec >> 4) & 0xFF ))
101+
OPENSSL_VERSION="${major}.${minor}.${patch}"
102+
else
103+
OPENSSL_VERSION="unknown"
104+
fi
105+
else
106+
OPENSSL_VERSION=$(pkg-config --modversion openssl 2>/dev/null || echo "unknown")
107+
OPENSSL_INCLUDE=$(pkg-config --variable=includedir openssl 2>/dev/null || echo "unknown")
108+
OSSLCONF_FLAGS="unknown (openssl-sys build output not found)"
109+
fi
110+
111+
# --- Build configuration (from Cargo.toml) ---
112+
113+
CARGO_TOML="$SOURCE_DIR/scylla-rust-wrapper/Cargo.toml"
114+
if [ -f "$CARGO_TOML" ]; then
115+
LTO=$(grep "^lto" "$CARGO_TOML" | head -1 | sed 's/.*=[ ]*//' | tr -d '"' || echo "unknown")
116+
PANIC=$(grep "^panic" "$CARGO_TOML" | head -1 | sed 's/.*=[ ]*//' | tr -d '"' || echo "unknown")
117+
else
118+
LTO="unknown"
119+
PANIC="unknown"
120+
fi
121+
122+
# --- CMake options ---
123+
124+
CMAKE_BUILD_TYPE=$(cmake_cache_get "CMAKE_BUILD_TYPE")
125+
CMAKE_INSTALL_PREFIX=$(cmake_cache_get "CMAKE_INSTALL_PREFIX")
126+
CASS_BUILD_SHARED=$(cmake_cache_get "CASS_BUILD_SHARED")
127+
CASS_BUILD_STATIC=$(cmake_cache_get "CASS_BUILD_STATIC")
128+
129+
# --- Write output ---
130+
131+
cat > "$OUTPUT" <<EOF
132+
Build Information for scylla-cpp-driver $VERSION
133+
134+
Platform
135+
--------
136+
OS: $OS
137+
Architecture: $ARCH
138+
Kernel: $KERNEL
139+
glibc: $GLIBC
140+
141+
Toolchain
142+
---------
143+
Rust: $RUST_VERSION
144+
Cargo: $CARGO_VERSION
145+
CMake: $CMAKE_VERSION_STR
146+
CC: $CC_VERSION
147+
148+
OpenSSL (detected by openssl-sys at build time)
149+
------------------------------------------------
150+
Version: $OPENSSL_VERSION
151+
Include path: $OPENSSL_INCLUDE
152+
Disabled (osslconf): ${OSSLCONF_FLAGS:-none}
153+
154+
Build Configuration
155+
-------------------
156+
CMAKE_BUILD_TYPE: $CMAKE_BUILD_TYPE
157+
CMAKE_INSTALL_PREFIX: $CMAKE_INSTALL_PREFIX
158+
CASS_BUILD_SHARED: $CASS_BUILD_SHARED
159+
CASS_BUILD_STATIC: $CASS_BUILD_STATIC
160+
LTO: $LTO
161+
Panic strategy: $PANIC
162+
163+
Static Library Compatibility Notes
164+
----------------------------------
165+
The static archive (libscylladb_static.a) requires consumers to
166+
provide OpenSSL >= 3.0 at link time. The minimum OpenSSL version
167+
is determined by the build-time detection performed by the
168+
openssl-sys crate.
169+
170+
Consumers linking on systems with a different OpenSSL configuration
171+
(e.g. different osslconf flags) may encounter undefined symbol errors
172+
for conditionally-compiled functions.
173+
EOF
174+
175+
echo "Generated: $OUTPUT"

0 commit comments

Comments
 (0)