From ea2e24d844a240649fe147ae89873512f8bdd7c9 Mon Sep 17 00:00:00 2001 From: Matt Perpick Date: Wed, 22 Oct 2025 10:53:38 -0400 Subject: [PATCH] fix ssl crl error see here: https://github.com/ruby/openssl/issues/949 --- .TODO.md | 12 +++++----- Gemfile.lock | 2 ++ braintrust.gemspec | 6 +++++ lib/braintrust.rb | 3 --- lib/braintrust/api/auth.rb | 7 +----- lib/braintrust/internal/experiments.rb | 12 ++-------- lib/braintrust/ssl_config.rb | 31 -------------------------- 7 files changed, 17 insertions(+), 56 deletions(-) delete mode 100644 lib/braintrust/ssl_config.rb diff --git a/.TODO.md b/.TODO.md index 064b7c5b..81d75302 100644 --- a/.TODO.md +++ b/.TODO.md @@ -6,12 +6,12 @@ ### High Priority -- [ ] **SSL Certificate Verification on macOS**: Currently using `OpenSSL::SSL::VERIFY_NONE` workaround ⚠️ - - **SECURITY ISSUE**: Disables SSL certificate verification - - Affects: lib/braintrust/api/auth.rb, lib/braintrust/trace.rb - - Issue: `certificate verify failed (unable to get certificate CRL)` - - Need to investigate proper SSL certificate handling or system cert store configuration - - Must be fixed before production use +- [x] **SSL Certificate Verification on macOS**: ✅ FIXED (2025-10-22) + - **Solution**: Added `openssl` gem v3.3.1+ as runtime dependency + - Fixed in Ruby/OpenSSL maintainers' release (see https://github.com/ruby/openssl/issues/949) + - Removed all `VERIFY_NONE` workarounds and ssl_config.rb + - Now uses proper SSL verification with VERIFY_PEER + - Tests passing, SSL connections verified working ### Medium Priority diff --git a/Gemfile.lock b/Gemfile.lock index 185a06de..63100b0f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -2,6 +2,7 @@ PATH remote: . specs: braintrust (0.0.1) + openssl (~> 3.3.1) opentelemetry-exporter-otlp (~> 0.28) opentelemetry-sdk (~> 1.0) @@ -29,6 +30,7 @@ GEM minitest (5.26.0) openai (0.34.1) connection_pool + openssl (3.3.1) opentelemetry-api (1.7.0) opentelemetry-common (0.23.0) opentelemetry-api (~> 1.0) diff --git a/braintrust.gemspec b/braintrust.gemspec index 2a92d8bf..0ee6b2f4 100644 --- a/braintrust.gemspec +++ b/braintrust.gemspec @@ -33,6 +33,12 @@ Gem::Specification.new do |spec| spec.add_runtime_dependency "opentelemetry-sdk", "~> 1.0" spec.add_runtime_dependency "opentelemetry-exporter-otlp", "~> 0.28" + # OpenSSL 3.3.1+ fixes macOS CRL (Certificate Revocation List) verification issues + # that occur with OpenSSL 3.6 + Ruby (certificate verify failed: unable to get certificate CRL). + # See: https://github.com/ruby/openssl/issues/949 + # This dependency may be removable in future Ruby versions once the fix is widely available. + spec.add_runtime_dependency "openssl", "~> 3.3.1" + # Development dependencies spec.add_development_dependency "minitest", "~> 5.0" spec.add_development_dependency "rake", "~> 13.0" diff --git a/lib/braintrust.rb b/lib/braintrust.rb index c5895a5d..b85d0bdb 100644 --- a/lib/braintrust.rb +++ b/lib/braintrust.rb @@ -1,8 +1,5 @@ # frozen_string_literal: true -# Load SSL config first to configure OpenSSL defaults before any connections -require_relative "braintrust/ssl_config" - require_relative "braintrust/version" require_relative "braintrust/config" require_relative "braintrust/state" diff --git a/lib/braintrust/api/auth.rb b/lib/braintrust/api/auth.rb index 4131f9a8..3e5ea84a 100644 --- a/lib/braintrust/api/auth.rb +++ b/lib/braintrust/api/auth.rb @@ -33,12 +33,7 @@ def self.login(api_key:, app_url:, org_name: nil) request["Authorization"] = "Bearer #{api_key}" http = Net::HTTP.new(uri.hostname, uri.port) - if uri.scheme == "https" - http.use_ssl = true - # TODO: This should be VERIFY_PEER but macOS has CRL issues - # Need to update system certs or configure ca_file properly - http.verify_mode = OpenSSL::SSL::VERIFY_NONE - end + http.use_ssl = true if uri.scheme == "https" response = http.start do |http_session| http_session.request(request) diff --git a/lib/braintrust/internal/experiments.rb b/lib/braintrust/internal/experiments.rb index 0f6b354b..a5a64a1d 100644 --- a/lib/braintrust/internal/experiments.rb +++ b/lib/braintrust/internal/experiments.rb @@ -58,11 +58,7 @@ def self.register_project(name, state) request.body = JSON.dump({name: name}) http = Net::HTTP.new(uri.hostname, uri.port) - if uri.scheme == "https" - http.use_ssl = true - # TODO: This should be VERIFY_PEER but macOS has CRL issues - http.verify_mode = OpenSSL::SSL::VERIFY_NONE - end + http.use_ssl = true if uri.scheme == "https" response = http.start do |http_session| http_session.request(request) @@ -110,11 +106,7 @@ def self.register_experiment(name, project_id, state, tags: nil, metadata: nil, request.body = JSON.dump(payload) http = Net::HTTP.new(uri.hostname, uri.port) - if uri.scheme == "https" - http.use_ssl = true - # TODO: This should be VERIFY_PEER but macOS has CRL issues - http.verify_mode = OpenSSL::SSL::VERIFY_NONE - end + http.use_ssl = true if uri.scheme == "https" response = http.start do |http_session| http_session.request(request) diff --git a/lib/braintrust/ssl_config.rb b/lib/braintrust/ssl_config.rb deleted file mode 100644 index 52c9f27d..00000000 --- a/lib/braintrust/ssl_config.rb +++ /dev/null @@ -1,31 +0,0 @@ -# frozen_string_literal: true - -require "openssl" - -module Braintrust - # SSL configuration helpers for macOS CRL issues - # - # This module configures OpenSSL to bypass Certificate Revocation List (CRL) errors - # which commonly occur on macOS due to system certificate configuration issues. - # All other SSL verification checks remain active for security. - module SSLConfig - # Configure global SSL defaults to ignore CRL errors - # This affects all Ruby SSL connections system-wide - def self.configure_defaults! - # Set up a verify callback that ignores CRL errors but keeps other checks - OpenSSL::SSL::SSLContext::DEFAULT_PARAMS[:verify_mode] = OpenSSL::SSL::VERIFY_PEER - OpenSSL::SSL::SSLContext::DEFAULT_PARAMS[:verify_callback] = proc do |preverify_ok, store_context| - if store_context.error == OpenSSL::X509::V_ERR_UNABLE_TO_GET_CRL - # Ignore CRL errors (common on macOS) - true - else - # Keep all other SSL verification - preverify_ok - end - end - end - end -end - -# Auto-configure SSL defaults when this module is loaded -Braintrust::SSLConfig.configure_defaults!