class Sqreen::EndpointTesting

Constants

CONTROL_ERROR_KIND
Endpoint
FALLBACK_ENDPOINT_URL
GLOBAL_TIMEOUT
INGESTION_ERROR_KIND
MAIN_CONTROL_HOST
MAIN_INJECTION_HOST

Public Class Methods

no_test_endpoints(config_url, config_ingestion_url) click to toggle source

reproduces behaviour before endpoint testing was introduced

# File lib/sqreen/endpoint_testing.rb, line 45
def no_test_endpoints(config_url, config_ingestion_url)
  endpoints = ChosenEndpoints.new

  endpoints.control = Endpoint.new(
    config_url || "https://#{MAIN_CONTROL_HOST}/", cert_store
  )
  endpoints.ingestion = Endpoint.new(
    config_ingestion_url || "https://#{MAIN_INJECTION_HOST}/", nil
  )

  endpoints
end
test_endpoints(proxy_url, config_url, config_ingestion_url) click to toggle source
# File lib/sqreen/endpoint_testing.rb, line 58
def test_endpoints(proxy_url, config_url, config_ingestion_url)
  proxy_params = create_proxy_params(proxy_url)

  # execute the tests in separate threads and wait for them
  thread_control = Thread.new do
    thread_main(config_url, proxy_params, MAIN_CONTROL_HOST)
  end
  thread_injection = Thread.new do
    thread_main(config_ingestion_url, proxy_params, MAIN_INJECTION_HOST)
  end

  wait_for_threads(thread_control, thread_injection)

  # build and return result
  fallback = Endpoint.new(FALLBACK_ENDPOINT_URL, cert_store)
  endpoints = ChosenEndpoints.new
  endpoints.control = thread_control[:endpoint] || fallback
  endpoints.ingestion = thread_injection[:endpoint] || fallback

  if thread_control[:endpoint_error]
    msg = AgentMessage.new(CONTROL_ERROR_KIND, thread_control[:endpoint_error])
    endpoints.add_message msg
  end
  if thread_injection[:endpoint_error]
    msg = AgentMessage.new(INGESTION_ERROR_KIND, thread_injection[:endpoint_error])
    endpoints.add_message msg
  end

  endpoints
end

Private Class Methods

cert_store() click to toggle source
# File lib/sqreen/endpoint_testing.rb, line 178
def cert_store
  @cert_store ||= begin
    cert_file = File.join(File.dirname(__FILE__), 'ca.crt')
    cert_store = OpenSSL::X509::Store.new
    cert_store.add_file cert_file

    cert_store
  end
end
create_proxy_params(proxy_url) click to toggle source
# File lib/sqreen/endpoint_testing.rb, line 103
def create_proxy_params(proxy_url)
  return [] unless proxy_url

  proxy = URI.parse(proxy_url)

  return [] unless proxy.scheme == 'http'

  [proxy.host, proxy.port, proxy.user, proxy.password]
end
do_test(proxy_params, server_name, custom_store) click to toggle source

@param [Array] proxy_params @param [String] server_name @param [Boolean] custom_store

# File lib/sqreen/endpoint_testing.rb, line 123
def do_test(proxy_params, server_name, custom_store)
  http = Net::HTTP.new(server_name, 443, *proxy_params)
  http.use_ssl = true
  http.verify_mode = OpenSSL::SSL::VERIFY_NONE if ENV['SQREEN_SSL_NO_VERIFY']
  http.verify_callback = lambda do |preverify_ok, ctx|
    unless preverify_ok
      logger.warn do
        "Certificate validation failure for certificate issued to " \
        "#{ctx.chain[0].subject}: #{ctx.error_string}"
      end
    end

    preverify_ok
  end

  http.open_timeout = 13
  http.ssl_timeout = 7
  http.read_timeout = 7
  http.close_on_empty_response = true

  http.cert_store = cert_store if custom_store

  resp = http.get('/ping')

  logger.info do
    "Got response from #{server_name}'s ping endpoint. " \
    "Status code is #{resp.code} (custom CA store: #{custom_store})"
  end

  unless resp.code == '200'
    raise "Response code for /ping is #{resp.code}, not 200"
  end

  Endpoint.new("https://#{server_name}/", http.cert_store)
rescue StandardError => e
  logger.info do
    "Error in request to #{server_name} " \
    "(custom store: #{custom_store}): #{e.message}"
  end

  raise "Error in request to #{server_name}: #{e.message}"
end
test_with_store_variants(proxy_params, server_name) click to toggle source
# File lib/sqreen/endpoint_testing.rb, line 113
def test_with_store_variants(proxy_params, server_name)
  # first without custom store
  do_test(proxy_params, server_name, false)
rescue StandardError => _e
  do_test(proxy_params, server_name, true)
end
thread_main(configured_url, proxy_params, host) click to toggle source
# File lib/sqreen/endpoint_testing.rb, line 91
def thread_main(configured_url, proxy_params, host)
  res = if configured_url
          Endpoint.new(configured_url, nil)
        else
          EndpointTesting.send(:test_with_store_variants, proxy_params, host)
        end

  Thread.current[:endpoint] = res
rescue StandardError => e
  Thread.current[:endpoint_error] = e.message
end
wait_for_threads(thread_control, thread_injection) click to toggle source
# File lib/sqreen/endpoint_testing.rb, line 166
def wait_for_threads(thread_control, thread_injection)
  deadline = Time.now + GLOBAL_TIMEOUT
  [thread_control, thread_injection].each do |thread|
    rem = deadline - Time.now
    rem = 0.1 if rem < 0.1
    next if thread.join(rem)
    logger.debug { "Timeout for thread #{thread}" }
    thread.kill
    thread[:endpoint_error] = "Timeout doing endpoint testing"
  end
end