Skip to content

Commit 4d4668f

Browse files
committed
feat: Add OpenSSL packaging validation script and tests; enhance production readiness checks
1 parent 727bd26 commit 4d4668f

7 files changed

Lines changed: 170 additions & 14 deletions

File tree

README.md

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -457,18 +457,19 @@ scripts/check_release_readiness.sh
457457
REQUIRE_PRODUCTION_READY=1 scripts/check_release_readiness.sh
458458
```
459459

460-
The default gate checks package shape, forbidden runtime dependencies,
461-
unit/integration opt-in tests, benchmark smoke, and the compressed release
462-
binary size proxy. The strict gate additionally requires
460+
The default gate checks package shape, forbidden runtime dependencies, local
461+
OpenSSL package/module/link validation, unit/integration opt-in tests,
462+
benchmark smoke, and the compressed release binary size proxy. The strict gate additionally requires
463463
`LiveKitNative.productionReadiness.status == .productionReady`, no blockers,
464464
tests, benchmarks, the size gate, Apple platform builds, and configured LiveKit
465465
integration variables so a production tag cannot pass with any release gate
466466
disabled.
467467
That strict gate intentionally fails today because LiveKit E2E secure RTP/RTCP
468468
verification, CI-gated TURN-only hardening, real-device video display validation,
469-
standards-compliant live SCTP, Apple-platform OpenSSL packaging validation,
470-
real-device audio route/interruption recovery, full live congestion/adaptive-quality
471-
policy, and end-to-end LiveKit tests are still open.
469+
standards-compliant live SCTP, Apple-platform OpenSSL redistribution/signing
470+
validation beyond the local package gate, real-device audio route/interruption
471+
validation, full live congestion/adaptive-quality policy, and end-to-end
472+
LiveKit tests are still open.
472473

473474
Opt-in LiveKit integration tests are disabled unless a local or cloud LiveKit
474475
server is explicitly configured:

Sources/LiveKitNative/Core/ProductionReadiness.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public extension LiveKitNative {
2828
static let productionReadiness = LiveKitNativeProductionReadiness(
2929
status: .developerPreview,
3030
blockers: [
31-
"ICEAgent nomination, local ICE trickle signaling, server ICE server configuration application, STUN UDP server-reflexive candidate gathering, bound local ICE UDP host candidate gathering and socket reuse for STUN checks and media datagrams, default Room socket-backed subscriber/publisher media-data startup configuration, OpenSSL-backed WebRTC DTLS-SRTP use_srtp handshake/exporter wiring, DTLS-SRTP packet protection, RFC 5764 DTLS/SRTP datagram demux, shared persistent DTLS application-data plus SRTP session binding, SDP DTLS role/fingerprint extraction, handshaker-backed media-session binding with result role/profile validation, injected Room publisher/subscriber media startup, injected selected-pair ICE consent freshness loop with transport closure on expiry, injected publisher transport teardown, Room publisher RTP/RTCP and subscriber RTCP bridges through injected secure media transport, publisher and subscriber RTCP receive-handler loops, deterministic NACK/PLI RTCP feedback policy primitives, bounded subscriber feedback planning from H.264/VP8 RTP loss signals, Room subscriber feedback dispatch through injected subscriber RTCP transport, bounded RTP jitter-buffer primitives, stateful Opus/H.264 publisher RTP packetizer bridges, native camera/microphone publisher capture pipelines, Room publisher RTP sender registry lifecycle coverage, subscriber RTP jitter-buffer/feedback dispatch, and default Room TURN relay allocation/permission maintenance execution exist, but production readiness still needs LiveKit server E2E secure RTP/RTCP integration, Apple-platform OpenSSL packaging validation, and the remaining media pipeline gates.",
31+
"ICEAgent nomination, local ICE trickle signaling, server ICE server configuration application, STUN UDP server-reflexive candidate gathering, bound local ICE UDP host candidate gathering and socket reuse for STUN checks and media datagrams, default Room socket-backed subscriber/publisher media-data startup configuration, OpenSSL-backed WebRTC DTLS-SRTP use_srtp handshake/exporter wiring, DTLS-SRTP packet protection, RFC 5764 DTLS/SRTP datagram demux, shared persistent DTLS application-data plus SRTP session binding, SDP DTLS role/fingerprint extraction, handshaker-backed media-session binding with result role/profile validation, injected Room publisher/subscriber media startup, injected selected-pair ICE consent freshness loop with transport closure on expiry, injected publisher transport teardown, Room publisher RTP/RTCP and subscriber RTCP bridges through injected secure media transport, publisher and subscriber RTCP receive-handler loops, deterministic NACK/PLI RTCP feedback policy primitives, bounded subscriber feedback planning from H.264/VP8 RTP loss signals, Room subscriber feedback dispatch through injected subscriber RTCP transport, bounded RTP jitter-buffer primitives, stateful Opus/H.264 publisher RTP packetizer bridges, native camera/microphone publisher capture pipelines, Room publisher RTP sender registry lifecycle coverage, subscriber RTP jitter-buffer/feedback dispatch, default Room TURN relay allocation/permission maintenance execution, and local OpenSSL package/module/link validation exist, but production readiness still needs LiveKit server E2E secure RTP/RTCP integration, Apple-platform OpenSSL redistribution/signing validation, and the remaining media pipeline gates.",
3232
"Fresh join, resume reconnect, disconnect, and failed signal-loop boundaries regenerate local ICE credentials, clear stale peer negotiation state, parse TURN UDP/TCP/TLS endpoint configuration, order TURN relay fallback candidates as UDP, TCP, then TLS, select supported TURN relay session configurations from parsed ICE server endpoints with credentials, exercise TURN Allocate, Refresh, CreatePermission, and ChannelBind request/authentication/response-validation primitives with one-shot stale nonce retry, cover TURN ChannelData framing, provide deterministic allocation/permission maintenance scheduling and execution, plan relayed ICE candidates from TURN bindings, compose and execute bounded TURN relay session setup plans over UDP datagram and TCP/TLS stream transports, expose ChannelData relay transports over abstract media datagram transports, allocate default UDP TURN relay candidates through the bound Room ICE socket, use ChannelData relay bindings for relayed ICE checks and media datagrams, bind default Room TURN relay maintenance loops to selected relay pairs with transport closure on expired refresh failure, provide relay-only ICE candidate policy plus an opt-in LiveKit TURN-only validation harness, provide deterministic ICE consent freshness planning plus an injected Room startup loop, run ICEAgent connectivity checks through paced scheduling with queued triggered-check priority plus role-conflict role switching and pair-priority recompute, and rebuild reconnect SyncState SDP/trickle state with fresh local ICE credentials, but CI-gated TURN-only validation and live media recovery are not complete.",
3333
"Publisher camera capture can encode H.264 through VideoToolbox with bounded frame backpressure/drop control and publisher microphone capture can encode Opus through AudioToolbox before RTP/SRTP send, while subscriber RTP can pass through jitter buffering, H.264/Opus packet assembly, NACK/PLI feedback, opt-in Opus decode-to-audio-playout scheduling, opt-in H.264 VideoToolbox decode-to-pixel-buffer scheduling, application-provided subscriber video renderer handoff, UIKit/AppKit VideoView sample-buffer rendering, opt-in iOS voice-chat audio-session lifecycle configuration, and deterministic audio interruption/route recovery with Room observer-loop reactivation; real-device video display validation, LiveKit E2E media validation, real-device route/interruption audio validation, and production runtime pacing remain incomplete.",
3434
"Production H.264 now uses real VideoToolbox encode output for publish smoke coverage, opt-in VideoToolbox decode output for subscribe smoke coverage, and UIKit/AppKit VideoView rendering for decoded frames, but production readiness still requires real-device display validation, hardware acceleration verification where the OS exposes that signal, and explicit fallback behavior instead of relying on a pure Swift codec implementation.",
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import XCTest
2+
3+
final class OpenSSLPackagingTests: XCTestCase {
4+
func testPackageDeclaresOpenSSLSystemLibraryAndWrapperTargets() throws {
5+
let package = try String(contentsOf: repositoryRoot.appendingPathComponent("Package.swift"))
6+
7+
XCTAssertTrue(package.contains(".systemLibrary("))
8+
XCTAssertTrue(package.contains("name: \"COpenSSL\""))
9+
XCTAssertTrue(package.contains("pkgConfig: \"openssl\""))
10+
XCTAssertTrue(package.contains(".brew([\"openssl@3\"])"))
11+
XCTAssertTrue(package.contains("name: \"CLiveKitNativeOpenSSL\""))
12+
XCTAssertTrue(package.contains("\"COpenSSL\""))
13+
XCTAssertTrue(package.contains("\"CLiveKitNativeOpenSSL\""))
14+
}
15+
16+
func testOpenSSLModuleMapExportsRequiredHeadersAndLibraries() throws {
17+
let moduleMap = try String(
18+
contentsOf: repositoryRoot.appendingPathComponent("Sources/COpenSSL/module.modulemap")
19+
)
20+
21+
for header in ["ssl.h", "srtp.h", "err.h", "x509.h", "pem.h"] {
22+
XCTAssertTrue(moduleMap.contains("header \"openssl/\(header)\""))
23+
}
24+
XCTAssertTrue(moduleMap.contains("link \"ssl\""))
25+
XCTAssertTrue(moduleMap.contains("link \"crypto\""))
26+
XCTAssertTrue(moduleMap.contains("export *"))
27+
}
28+
29+
func testOpenSSLWrapperHeaderExposesDTLSUseSRTPSurface() throws {
30+
let header = try String(
31+
contentsOf: repositoryRoot.appendingPathComponent(
32+
"Sources/CLiveKitNativeOpenSSL/include/CLiveKitNativeOpenSSL.h"
33+
)
34+
)
35+
36+
for symbol in [
37+
"lkn_dtls_identity_create",
38+
"lkn_dtls_session_create",
39+
"lkn_dtls_session_do_handshake",
40+
"lkn_dtls_session_export_keying_material",
41+
"lkn_dtls_session_selected_srtp_profile",
42+
"lkn_dtls_last_error_string",
43+
] {
44+
XCTAssertTrue(header.contains(symbol))
45+
}
46+
}
47+
48+
private var repositoryRoot: URL {
49+
URL(fileURLWithPath: #filePath)
50+
.deletingLastPathComponent()
51+
.deletingLastPathComponent()
52+
.deletingLastPathComponent()
53+
}
54+
}

Tests/LiveKitNativeTests/ProductionReadinessTests.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ final class ProductionReadinessTests: XCTestCase {
1414
XCTAssertTrue(readiness.blockers.contains { $0.contains("outbound DATA TSN acknowledgement tracking") })
1515
XCTAssertTrue(readiness.blockers.contains { $0.contains("SACK gap-triggered retransmission") })
1616
XCTAssertTrue(readiness.blockers.contains { $0.contains("deterministic cwnd/rwnd send gating") })
17+
XCTAssertTrue(readiness.blockers.contains { $0.contains("local OpenSSL package/module/link validation") })
18+
XCTAssertTrue(readiness.blockers.contains { $0.contains("Apple-platform OpenSSL redistribution/signing validation") })
1719
XCTAssertTrue(readiness.blockers.contains { $0.contains("full standards-compliant SCTP association state") })
1820
XCTAssertFalse(readiness.blockers.contains { $0.contains("promotion of live DataPacket coverage") })
1921
}

docs/STATUS.md

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ Production readiness is intentionally represented in code through
1212
`LiveKitNative.productionReadiness` and `LiveKitNative.assertProductionReady()`.
1313
The current status is `developerPreview`, with explicit blockers for LiveKit
1414
server E2E secure RTP/RTCP verification, TURN/ICE hardening,
15-
default live media send/receive completion, Apple-platform OpenSSL packaging,
15+
default live media send/receive completion, Apple-platform OpenSSL
16+
redistribution/signing validation beyond the local package gate,
1617
VideoToolbox-backed production H.264
1718
encode/decode with hardware path verification and fallback policy,
1819
standards-compliant DTLS-backed SCTP, media
@@ -993,8 +994,9 @@ The following checks passed after the latest implementation pass:
993994
- LiveKit server E2E verification for the OpenSSL-backed DTLS 1.2
994995
WebRTC `use_srtp` extension negotiation and exporter now wired into the
995996
default live Room path.
996-
- Apple-platform OpenSSL packaging/signing validation for iOS and macOS release
997-
builds.
997+
- Local OpenSSL package/module/link validation now runs in the release readiness
998+
gate; Apple-platform OpenSSL redistribution/signing validation for iOS and
999+
macOS release builds remains open.
9981000
- LiveKit E2E verification for default live RTP/RTCP media send/receive on top
9991001
of the handshaker-backed secure media session binder.
10001002
- Production hardening for the default camera/audio capture and encode loops,
@@ -1094,8 +1096,8 @@ The following checks passed after the latest implementation pass:
10941096

10951097
1. Continue `1.0.0` hardening by extending the new live OpenSSL-backed
10961098
DTLS-SRTP default Room startup coverage into full RTP/RTCP media
1097-
send/receive validation, then validate the OpenSSL packaging story for iOS
1098-
release builds.
1099+
send/receive validation, then validate the OpenSSL redistribution/signing
1100+
story for iOS release builds.
10991101
2. Replace the current DTLS data-channel packet envelope and deterministic
11001102
fragment/retry primitive with a standards-compliant SCTP association,
11011103
validate it through the default shared media/data Room path, and add
@@ -1126,8 +1128,8 @@ The following checks passed after the latest implementation pass:
11261128
blockers.
11271129
10. Keep full VP8 pixel reconstruction, publisher transceiver negotiation,
11281130
LiveKit E2E secure RTP/RTCP verification, real-device media timing, and
1129-
Apple-platform OpenSSL packaging validation as the hardening path before a
1130-
usable end-to-end release.
1131+
Apple-platform OpenSSL redistribution/signing validation as the hardening
1132+
path before a usable end-to-end release.
11311133

11321134
## Practical Release Status
11331135

scripts/check_openssl_packaging.sh

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
5+
cd "$repo_root"
6+
7+
fail() {
8+
echo "OpenSSL packaging validation failed: $*"
9+
exit 1
10+
}
11+
12+
require_file() {
13+
local path="$1"
14+
[[ -f "$path" ]] || fail "missing $path"
15+
}
16+
17+
require_text() {
18+
local path="$1"
19+
local text="$2"
20+
grep -Fq "$text" "$path" || fail "expected '$text' in $path"
21+
}
22+
23+
package_file="Package.swift"
24+
modulemap_file="Sources/COpenSSL/module.modulemap"
25+
wrapper_header="Sources/CLiveKitNativeOpenSSL/include/CLiveKitNativeOpenSSL.h"
26+
wrapper_source="Sources/CLiveKitNativeOpenSSL/CLiveKitNativeOpenSSL.c"
27+
28+
require_file "$package_file"
29+
require_file "$modulemap_file"
30+
require_file "$wrapper_header"
31+
require_file "$wrapper_source"
32+
33+
require_text "$package_file" '.systemLibrary('
34+
require_text "$package_file" 'name: "COpenSSL"'
35+
require_text "$package_file" 'pkgConfig: "openssl"'
36+
require_text "$package_file" '.brew(["openssl@3"])'
37+
require_text "$package_file" 'name: "CLiveKitNativeOpenSSL"'
38+
require_text "$package_file" '"COpenSSL"'
39+
require_text "$package_file" '"CLiveKitNativeOpenSSL"'
40+
41+
for header in ssl.h srtp.h err.h x509.h pem.h; do
42+
require_text "$modulemap_file" "header \"openssl/$header\""
43+
done
44+
require_text "$modulemap_file" 'link "ssl"'
45+
require_text "$modulemap_file" 'link "crypto"'
46+
47+
for symbol in \
48+
lkn_dtls_identity_create \
49+
lkn_dtls_session_create \
50+
lkn_dtls_session_do_handshake \
51+
lkn_dtls_session_export_keying_material \
52+
lkn_dtls_session_selected_srtp_profile \
53+
lkn_dtls_last_error_string
54+
do
55+
require_text "$wrapper_header" "$symbol"
56+
done
57+
58+
command -v pkg-config >/dev/null 2>&1 || fail "pkg-config is required for the COpenSSL system library"
59+
pkg-config --exists openssl || fail "pkg-config cannot resolve openssl"
60+
61+
openssl_version="$(pkg-config --modversion openssl)"
62+
openssl_major="${openssl_version%%.*}"
63+
case "$openssl_major" in
64+
''|*[!0-9]*)
65+
fail "could not parse OpenSSL version '$openssl_version'"
66+
;;
67+
esac
68+
if (( openssl_major < 3 )); then
69+
fail "OpenSSL 3.x is required, found $openssl_version"
70+
fi
71+
72+
openssl_include_dir="$(pkg-config --variable=includedir openssl)"
73+
openssl_lib_dir="$(pkg-config --variable=libdir openssl)"
74+
75+
for header in ssl.h srtp.h err.h x509.h pem.h; do
76+
require_file "$openssl_include_dir/openssl/$header"
77+
done
78+
79+
shopt -s nullglob
80+
ssl_libraries=("$openssl_lib_dir"/libssl.*)
81+
crypto_libraries=("$openssl_lib_dir"/libcrypto.*)
82+
shopt -u nullglob
83+
(( ${#ssl_libraries[@]} > 0 )) || fail "missing libssl in $openssl_lib_dir"
84+
(( ${#crypto_libraries[@]} > 0 )) || fail "missing libcrypto in $openssl_lib_dir"
85+
86+
compiler="${CC:-cc}"
87+
command -v "$compiler" >/dev/null 2>&1 || fail "C compiler '$compiler' is required"
88+
openssl_cflags="$(pkg-config --cflags openssl)"
89+
90+
# Intentionally let pkg-config split flags the same way the C compiler expects them.
91+
# shellcheck disable=SC2086
92+
"$compiler" -fsyntax-only -I"$repo_root/Sources/CLiveKitNativeOpenSSL/include" $openssl_cflags "$wrapper_source"
93+
94+
echo "OpenSSL packaging validation passed for OpenSSL $openssl_version."

scripts/check_release_readiness.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ fi
4747

4848
echo "Package shape passed."
4949

50+
echo "==> Checking OpenSSL packaging"
51+
scripts/check_openssl_packaging.sh
52+
5053
echo "==> Checking production readiness marker"
5154
readiness_file="Sources/LiveKitNative/Core/ProductionReadiness.swift"
5255
if [[ "$require_production_ready" == "1" ]]; then

0 commit comments

Comments
 (0)