Files
sure/app/models/concerns/ssl_configurable.rb
BitToby ba6e286b41 feat: add SSL_CA_FILE and SSL_VERIFY environment variables to support… (#894)
* feat: add SSL_CA_FILE and SSL_VERIFY environment variables to support self-signed certificates in self-hosted environments

* fix: NoMethodError by defining SSL helper methods before configure block executes

* refactor: Refactor SessionsController to use shared SslConfigurable module and simplify SSL initializer redundant checks

* refactor: improve SSL configuration robustness and error detection accuracy

* fix:HTTParty SSL options, add file validation guards, prevent Tempfile GC, and redact URLs in error logs

* fix:  Fix SSL concern indentation and stub Simplefin POST correctly in tests

* fix: normalize ssl_verify to always return boolean instead of nil

* fix: solve failing SimpleFin test

* refactor:  trim unused error-handling code from SslConfigurable, replace Tempfile with fixed-path CA bundle, fix namespace pollution in initializers, and add unit tests for core SSL configuration and Langfuse CRL callback.

* fix: added require ileutils in the initializer and require ostruct in the test file.

* fix: solve autoload conflict that broke provider loading, validate all certs in PEM bundles, and add missing requires.
2026-02-06 18:04:03 +01:00

127 lines
3.6 KiB
Ruby

# frozen_string_literal: true
# Provides centralized SSL configuration for HTTP clients.
#
# This module enables support for self-signed certificates in self-hosted
# environments by reading configuration from Rails.configuration.x.ssl.
#
# Features:
# - Custom CA certificate support for self-signed certificates
# - Optional SSL verification bypass (for development/testing only)
# - Debug logging for troubleshooting SSL issues
#
# Usage (extend for class methods — the only supported pattern):
# class MyHttpClient
# extend SslConfigurable
#
# def self.make_request
# Faraday.new(url, ssl: faraday_ssl_options) { |f| ... }
# end
# end
#
# Environment Variables (configured in config/initializers/00_ssl.rb):
# SSL_CA_FILE - Path to custom CA certificate file (PEM format)
# SSL_VERIFY - Set to "false" to disable SSL verification
# SSL_DEBUG - Set to "true" to enable verbose SSL logging
module SslConfigurable
# Returns SSL options hash for Faraday connections
#
# @return [Hash] SSL options for Faraday
# @example
# Faraday.new(url, ssl: faraday_ssl_options) do |f|
# f.request :json
# f.response :raise_error
# end
def faraday_ssl_options
options = {}
options[:verify] = ssl_verify?
if ssl_ca_file.present?
options[:ca_file] = ssl_ca_file
log_ssl_debug("Faraday SSL: Using custom CA file: #{ssl_ca_file}")
end
log_ssl_debug("Faraday SSL: Verification disabled") unless ssl_verify?
log_ssl_debug("Faraday SSL options: #{options.inspect}") if options.present?
options
end
# Returns SSL options hash for HTTParty requests
#
# @return [Hash] SSL options for HTTParty
# @example
# class MyProvider
# include HTTParty
# extend SslConfigurable
# default_options.merge!(httparty_ssl_options)
# end
def httparty_ssl_options
options = { verify: ssl_verify? }
if ssl_ca_file.present?
options[:ssl_ca_file] = ssl_ca_file
log_ssl_debug("HTTParty SSL: Using custom CA file: #{ssl_ca_file}")
end
log_ssl_debug("HTTParty SSL: Verification disabled") unless ssl_verify?
options
end
# Returns SSL verify mode for Net::HTTP
#
# @return [Integer] OpenSSL verify mode constant (VERIFY_PEER or VERIFY_NONE)
# @example
# http = Net::HTTP.new(uri.host, uri.port)
# http.use_ssl = true
# http.verify_mode = net_http_verify_mode
# http.ca_file = ssl_ca_file if ssl_ca_file.present?
def net_http_verify_mode
mode = ssl_verify? ? OpenSSL::SSL::VERIFY_PEER : OpenSSL::SSL::VERIFY_NONE
log_ssl_debug("Net::HTTP verify mode: #{mode == OpenSSL::SSL::VERIFY_PEER ? 'VERIFY_PEER' : 'VERIFY_NONE'}")
mode
end
# Returns CA file path if configured
#
# @return [String, nil] Path to CA file or nil if not configured
def ssl_ca_file
ssl_configuration.ca_file
end
# Returns whether SSL verification is enabled
# nil or true both mean verification is enabled; only explicit false disables it
#
# @return [Boolean] true if SSL verification is enabled
def ssl_verify?
ssl_configuration.verify != false
end
# Returns whether SSL debug logging is enabled
#
# @return [Boolean] true if debug logging is enabled
def ssl_debug?
ssl_configuration.debug == true
end
private
# Returns the SSL configuration from Rails
#
# @return [ActiveSupport::OrderedOptions] SSL configuration
def ssl_configuration
Rails.configuration.x.ssl
end
# Logs a debug message if SSL debug mode is enabled
#
# @param message [String] Message to log
def log_ssl_debug(message)
return unless ssl_debug?
Rails.logger.debug("[SSL Debug] #{message}")
end
end