From 10b0634ca3916f51eff9fc133d6ddf4ec91104cd Mon Sep 17 00:00:00 2001 From: ilyazub Date: Fri, 2 Oct 2026 22:54:17 +0200 Subject: [PATCH] Keep the test CA in memory SSLHelper generates its CA once per process but wrote it to the shared tmp/certs/ca.crt, and OpenSSL only reads ca_file when a context is set up for a handshake. When tests run in several processes at once, as mutant's workers do, the last process to write the file replaces every other process's CA, and their handshakes fail with "certificate verify failed (certificate signature failure)". Trust the CA through an in-memory certificate store instead. The server context no longer sets ca_file, since it does not verify clients. --- test/support/ssl_helper.rb | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/test/support/ssl_helper.rb b/test/support/ssl_helper.rb index 4ba50940..d57091fd 100644 --- a/test/support/ssl_helper.rb +++ b/test/support/ssl_helper.rb @@ -1,11 +1,8 @@ # frozen_string_literal: true require "openssl" -require "pathname" module SSLHelper - CERTS_PATH = Pathname.new File.expand_path("../../tmp/certs", __dir__) - class << self def server_context context = OpenSSL::SSL::SSLContext.new @@ -13,33 +10,35 @@ def server_context context.verify_mode = OpenSSL::SSL::VERIFY_NONE context.key = server_cert_key context.cert = server_cert_cert - context.ca_file = ca_file context end def client_context - # Ensure server cert is generated (triggers CA generation too) - server_cert_cert context = OpenSSL::SSL::SSLContext.new context.options = OpenSSL::SSL::SSLContext::DEFAULT_PARAMS[:options] context.verify_mode = OpenSSL::SSL::VERIFY_PEER context.verify_hostname = true if context.respond_to?(:verify_hostname=) - context.ca_file = ca_file + context.cert_store = cert_store context end def client_params - server_cert_cert { - ca_file: ca_file + cert_store: cert_store } end private + # Each test process generates its own CA, so it is trusted in memory + # rather than through a file that parallel processes would overwrite + def cert_store + OpenSSL::X509::Store.new.tap { |store| store.add_cert(ca_cert) } + end + def ca_key @ca_key ||= OpenSSL::PKey::RSA.new(2048) end @@ -67,15 +66,6 @@ def ca_cert end end - def ca_file - return @ca_file if defined?(@ca_file) - - CERTS_PATH.mkpath - cert_file = CERTS_PATH.join("ca.crt") - cert_file.open("w") { |io| io << ca_cert.to_pem } - @ca_file = cert_file.to_s - end - def server_cert_key @server_cert_key ||= OpenSSL::PKey::RSA.new(2048) end