lhc 12.3.0 → 13.4.0.pre.pro1766.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/rubocop.yml +15 -0
  3. data/.github/workflows/test.yml +15 -0
  4. data/.rubocop.yml +344 -19
  5. data/.ruby-version +1 -1
  6. data/Gemfile.activesupport5 +1 -1
  7. data/Gemfile.activesupport6 +1 -1
  8. data/README.md +102 -2
  9. data/Rakefile +3 -3
  10. data/lhc.gemspec +6 -3
  11. data/lib/lhc.rb +70 -59
  12. data/lib/lhc/concerns/lhc/fix_invalid_encoding_concern.rb +1 -0
  13. data/lib/lhc/config.rb +16 -0
  14. data/lib/lhc/endpoint.rb +3 -0
  15. data/lib/lhc/error.rb +7 -3
  16. data/lib/lhc/interceptor.rb +4 -0
  17. data/lib/lhc/interceptors.rb +1 -0
  18. data/lib/lhc/interceptors/auth.rb +10 -5
  19. data/lib/lhc/interceptors/caching.rb +70 -44
  20. data/lib/lhc/interceptors/logging.rb +4 -2
  21. data/lib/lhc/interceptors/monitoring.rb +46 -11
  22. data/lib/lhc/interceptors/retry.rb +2 -0
  23. data/lib/lhc/interceptors/rollbar.rb +3 -2
  24. data/lib/lhc/interceptors/throttle.rb +7 -2
  25. data/lib/lhc/interceptors/zipkin.rb +2 -0
  26. data/lib/lhc/railtie.rb +0 -1
  27. data/lib/lhc/request.rb +37 -4
  28. data/lib/lhc/response.rb +1 -0
  29. data/lib/lhc/response/data.rb +1 -1
  30. data/lib/lhc/rspec.rb +1 -2
  31. data/lib/lhc/scrubber.rb +45 -0
  32. data/lib/lhc/scrubbers/auth_scrubber.rb +32 -0
  33. data/lib/lhc/scrubbers/body_scrubber.rb +30 -0
  34. data/lib/lhc/scrubbers/headers_scrubber.rb +40 -0
  35. data/lib/lhc/scrubbers/params_scrubber.rb +14 -0
  36. data/lib/lhc/version.rb +1 -1
  37. data/spec/config/scrubs_spec.rb +108 -0
  38. data/spec/error/to_s_spec.rb +13 -8
  39. data/spec/formats/multipart_spec.rb +2 -2
  40. data/spec/formats/plain_spec.rb +1 -1
  41. data/spec/interceptors/after_response_spec.rb +1 -1
  42. data/spec/interceptors/caching/main_spec.rb +2 -2
  43. data/spec/interceptors/caching/multilevel_cache_spec.rb +139 -0
  44. data/spec/interceptors/caching/options_spec.rb +0 -11
  45. data/spec/interceptors/define_spec.rb +1 -0
  46. data/spec/interceptors/logging/main_spec.rb +21 -1
  47. data/spec/interceptors/monitoring/caching_spec.rb +66 -0
  48. data/spec/interceptors/response_competition_spec.rb +2 -2
  49. data/spec/interceptors/return_response_spec.rb +2 -2
  50. data/spec/interceptors/rollbar/main_spec.rb +27 -15
  51. data/spec/request/scrubbed_headers_spec.rb +101 -0
  52. data/spec/request/scrubbed_options_spec.rb +185 -0
  53. data/spec/request/scrubbed_params_spec.rb +25 -0
  54. data/spec/response/data_spec.rb +2 -2
  55. data/spec/spec_helper.rb +1 -0
  56. data/spec/support/zipkin_mock.rb +1 -0
  57. metadata +59 -26
  58. data/.rubocop.localch.yml +0 -325
  59. data/Gemfile.activesupport4 +0 -4
  60. data/cider-ci.yml +0 -6
  61. data/cider-ci/bin/bundle +0 -51
  62. data/cider-ci/bin/ruby_install +0 -8
  63. data/cider-ci/bin/ruby_version +0 -25
  64. data/cider-ci/jobs/rspec-activesupport-4.yml +0 -28
  65. data/cider-ci/jobs/rspec-activesupport-5.yml +0 -27
  66. data/cider-ci/jobs/rspec-activesupport-6.yml +0 -28
  67. data/cider-ci/jobs/rubocop.yml +0 -18
  68. data/cider-ci/task_components/bundle.yml +0 -22
  69. data/cider-ci/task_components/rspec.yml +0 -36
  70. data/cider-ci/task_components/rubocop.yml +0 -29
  71. data/cider-ci/task_components/ruby.yml +0 -15
@@ -12,6 +12,7 @@ class LHC::Zipkin < LHC::Interceptor
12
12
 
13
13
  def before_request
14
14
  return if !dependencies? || !tracing?
15
+
15
16
  ZipkinTracer::TraceContainer.with_trace_id(trace_id) do
16
17
  # add headers even if the current trace_id should not be sampled
17
18
  B3_HEADERS.each { |method, header| request.headers[header] = trace_id.send(method).to_s }
@@ -23,6 +24,7 @@ class LHC::Zipkin < LHC::Interceptor
23
24
  def after_response
24
25
  # only sample the current call if we're instructed to do so
25
26
  return unless dependencies? && trace_id.sampled?
27
+
26
28
  end_trace!
27
29
  end
28
30
 
data/lib/lhc/railtie.rb CHANGED
@@ -4,7 +4,6 @@ module LHC
4
4
  class Railtie < Rails::Railtie
5
5
  initializer "lhc.configure_rails_initialization" do
6
6
  LHC::Caching.cache ||= Rails.cache
7
- LHC::Caching.logger ||= Rails.logger
8
7
  end
9
8
  end
10
9
  end
data/lib/lhc/request.rb CHANGED
@@ -12,7 +12,13 @@ class LHC::Request
12
12
 
13
13
  TYPHOEUS_OPTIONS ||= [:params, :method, :body, :headers, :follow_location, :params_encoding]
14
14
 
15
- attr_accessor :response, :options, :raw, :format, :error_handler, :errors_ignored, :source
15
+ attr_accessor :response,
16
+ :options,
17
+ :raw,
18
+ :format,
19
+ :error_handler,
20
+ :errors_ignored,
21
+ :source
16
22
 
17
23
  def initialize(options, self_executing = true)
18
24
  self.errors_ignored = (options.fetch(:ignore, []) || []).to_a.compact
@@ -25,7 +31,11 @@ class LHC::Request
25
31
  interceptors.intercept(:before_raw_request)
26
32
  self.raw = create_request
27
33
  interceptors.intercept(:before_request)
28
- run! if self_executing && !response
34
+ if self_executing && !response
35
+ run!
36
+ elsif response
37
+ on_complete(response)
38
+ end
29
39
  end
30
40
 
31
41
  def url
@@ -52,6 +62,23 @@ class LHC::Request
52
62
  raw.run
53
63
  end
54
64
 
65
+ def scrubbed_params
66
+ LHC::ParamsScrubber.new(params.deep_dup).scrubbed
67
+ end
68
+
69
+ def scrubbed_headers
70
+ LHC::HeadersScrubber.new(headers.deep_dup, options[:auth]).scrubbed
71
+ end
72
+
73
+ def scrubbed_options
74
+ scrubbed_options = options.deep_dup
75
+ scrubbed_options[:params] = LHC::ParamsScrubber.new(scrubbed_options[:params]).scrubbed
76
+ scrubbed_options[:headers] = LHC::HeadersScrubber.new(scrubbed_options[:headers], scrubbed_options[:auth]).scrubbed
77
+ scrubbed_options[:auth] = LHC::AuthScrubber.new(scrubbed_options[:auth]).scrubbed
78
+ scrubbed_options[:body] = LHC::BodyScrubber.new(scrubbed_options[:body]).scrubbed
79
+ scrubbed_options
80
+ end
81
+
55
82
  private
56
83
 
57
84
  attr_accessor :interceptors
@@ -63,6 +90,7 @@ class LHC::Request
63
90
 
64
91
  def optionally_encoded_url(options)
65
92
  return options[:url] unless options.fetch(:url_encoding, true)
93
+
66
94
  encode_url(options[:url])
67
95
  end
68
96
 
@@ -81,13 +109,15 @@ class LHC::Request
81
109
 
82
110
  def translate_body(options)
83
111
  return options if options.fetch(:body, nil).blank?
112
+
84
113
  options[:body] = format.to_body(options[:body])
85
114
  options
86
115
  end
87
116
 
88
117
  def encode_url(url)
89
118
  return url if url.nil?
90
- URI.escape(url)
119
+
120
+ Addressable::URI.escape(url)
91
121
  end
92
122
 
93
123
  def typhoeusize(options)
@@ -96,6 +126,7 @@ class LHC::Request
96
126
  options.delete(:url)
97
127
  options.each do |key, _v|
98
128
  next if TYPHOEUS_OPTIONS.include? key
129
+
99
130
  method = "#{key}="
100
131
  options.delete key unless easy.respond_to?(method)
101
132
  end
@@ -107,6 +138,7 @@ class LHC::Request
107
138
  def use_configured_endpoint!
108
139
  endpoint = LHC.config.endpoints[options[:url]]
109
140
  return unless endpoint
141
+
110
142
  # explicit options override endpoint options
111
143
  new_options = endpoint.options.deep_merge(options)
112
144
  # set new options
@@ -128,13 +160,14 @@ class LHC::Request
128
160
  end
129
161
 
130
162
  def on_complete(response)
131
- self.response = LHC::Response.new(response, self)
163
+ self.response = response.is_a?(LHC::Response) ? response : LHC::Response.new(response, self)
132
164
  interceptors.intercept(:after_response)
133
165
  handle_error(self.response) unless self.response.success?
134
166
  end
135
167
 
136
168
  def handle_error(response)
137
169
  return if ignore_error?
170
+
138
171
  throw_error(response) unless error_handler
139
172
  response.body_replacement = error_handler.call(response)
140
173
  end
data/lib/lhc/response.rb CHANGED
@@ -50,6 +50,7 @@ class LHC::Response
50
50
 
51
51
  def format
52
52
  return LHC::Formats::JSON.new if request.nil?
53
+
53
54
  request.format
54
55
  end
55
56
 
@@ -18,7 +18,7 @@ class LHC::Response::Data
18
18
  end
19
19
  end
20
20
 
21
- def method_missing(method, *args, &block) # rubocop:disable Style/MethodMissingSuper
21
+ def method_missing(method, *args, &block)
22
22
  @base.send(method, *args, &block)
23
23
  end
24
24
 
data/lib/lhc/rspec.rb CHANGED
@@ -3,9 +3,8 @@
3
3
  require 'lhc'
4
4
 
5
5
  RSpec.configure do |config|
6
- LHC::Caching.cache = ActiveSupport::Cache::MemoryStore.new
7
-
8
6
  config.before(:each) do
7
+ LHC::Caching.cache = ActiveSupport::Cache::MemoryStore.new
9
8
  LHC::Caching.cache.clear
10
9
  LHC::Throttle.track = nil
11
10
  end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ class LHC::Scrubber
4
+ attr_accessor :scrubbed
5
+
6
+ SCRUB_DISPLAY = '[FILTERED]'
7
+
8
+ def initialize(data)
9
+ @scrubbed = data.deep_dup
10
+ end
11
+
12
+ private
13
+
14
+ def scrub_auth_elements
15
+ LHC.config.scrubs.dig(:auth)
16
+ end
17
+
18
+ def scrub!
19
+ return if scrub_elements.blank?
20
+ return if scrubbed.blank?
21
+
22
+ LHC::Scrubber.scrub_hash!(scrub_elements, scrubbed) if scrubbed.is_a?(Hash)
23
+ LHC::Scrubber.scrub_array!(scrub_elements, scrubbed) if scrubbed.is_a?(Array)
24
+ end
25
+
26
+ def self.scrub_array!(scrub_elements, scrubbed)
27
+ scrubbed.each do |scrubbed_hash|
28
+ LHC::Scrubber.scrub_hash!(scrub_elements, scrubbed_hash)
29
+ end
30
+ end
31
+
32
+ def self.scrub_hash!(scrub_elements, scrubbed)
33
+ scrub_elements.each do |scrub_element|
34
+ if scrubbed.key?(scrub_element.to_s)
35
+ key = scrub_element.to_s
36
+ elsif scrubbed.key?(scrub_element.to_sym)
37
+ key = scrub_element.to_sym
38
+ end
39
+ next if key.blank?
40
+
41
+ scrubbed[key] = SCRUB_DISPLAY
42
+ end
43
+ scrubbed.values.each { |v| LHC::Scrubber.scrub_hash!(scrub_elements, v) if v.instance_of?(Hash) }
44
+ end
45
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ class LHC::AuthScrubber < LHC::Scrubber
4
+ def initialize(data)
5
+ super(data)
6
+ scrub_auth_options!
7
+ end
8
+
9
+ private
10
+
11
+ def scrub_auth_options!
12
+ return if scrubbed.blank?
13
+ return if scrub_auth_elements.blank?
14
+
15
+ scrub_basic_auth_options! if scrub_auth_elements.include?(:basic)
16
+ scrub_bearer_auth_options! if scrub_auth_elements.include?(:bearer)
17
+ end
18
+
19
+ def scrub_basic_auth_options!
20
+ return if scrubbed[:basic].blank?
21
+
22
+ scrubbed[:basic][:username] = SCRUB_DISPLAY
23
+ scrubbed[:basic][:password] = SCRUB_DISPLAY
24
+ scrubbed[:basic][:base_64_encoded_credentials] = SCRUB_DISPLAY
25
+ end
26
+
27
+ def scrub_bearer_auth_options!
28
+ return if scrubbed[:bearer].blank?
29
+
30
+ scrubbed[:bearer_token] = SCRUB_DISPLAY
31
+ end
32
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ class LHC::BodyScrubber < LHC::Scrubber
4
+ def initialize(data)
5
+ super(data)
6
+ parse!
7
+ scrub!
8
+ end
9
+
10
+ private
11
+
12
+ def scrub_elements
13
+ LHC.config.scrubs[:body]
14
+ end
15
+
16
+ def parse!
17
+ return if scrubbed.nil?
18
+ return if scrubbed.is_a?(Hash)
19
+ return if scrubbed.is_a?(Array)
20
+
21
+ if scrubbed.is_a?(String)
22
+ json = scrubbed
23
+ else
24
+ json = scrubbed.to_json
25
+ end
26
+
27
+ parsed = JSON.parse(json)
28
+ self.scrubbed = parsed if parsed.is_a?(Hash) || parsed.is_a?(Array)
29
+ end
30
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ class LHC::HeadersScrubber < LHC::Scrubber
4
+ def initialize(data, auth_options)
5
+ super(data)
6
+ @auth_options = auth_options
7
+ scrub!
8
+ scrub_auth_headers!
9
+ end
10
+
11
+ private
12
+
13
+ attr_reader :auth_options
14
+
15
+ def scrub_elements
16
+ LHC.config.scrubs[:headers]
17
+ end
18
+
19
+ def scrub_auth_headers!
20
+ return if scrub_auth_elements.blank?
21
+ return if auth_options.blank?
22
+
23
+ scrub_basic_authentication_headers! if scrub_auth_elements.include?(:basic)
24
+ scrub_bearer_authentication_headers! if scrub_auth_elements.include?(:bearer)
25
+ end
26
+
27
+ def scrub_basic_authentication_headers!
28
+ return if auth_options[:basic].blank?
29
+ return if scrubbed['Authorization'].blank?
30
+
31
+ scrubbed['Authorization'] = scrubbed['Authorization'].gsub(auth_options[:basic][:base_64_encoded_credentials], SCRUB_DISPLAY)
32
+ end
33
+
34
+ def scrub_bearer_authentication_headers!
35
+ return if @auth_options[:bearer].blank?
36
+ return if @scrubbed['Authorization'].blank?
37
+
38
+ @scrubbed['Authorization'] = scrubbed['Authorization'].gsub(auth_options[:bearer_token], SCRUB_DISPLAY)
39
+ end
40
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ class LHC::ParamsScrubber < LHC::Scrubber
4
+ def initialize(data)
5
+ super(data)
6
+ scrub!
7
+ end
8
+
9
+ private
10
+
11
+ def scrub_elements
12
+ LHC.config.scrubs[:params]
13
+ end
14
+ end
data/lib/lhc/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module LHC
4
- VERSION ||= '12.3.0'
4
+ VERSION ||= '13.4.0-pro1766.1'
5
5
  end
@@ -0,0 +1,108 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ describe LHC do
6
+ it 'has a default value for scrubs' do
7
+ expect(LHC.config.scrubs[:auth]).to eq [:bearer, :basic]
8
+ expect(LHC.config.scrubs[:params]).to eq []
9
+ expect(LHC.config.scrubs[:headers]).to eq []
10
+ expect(LHC.config.scrubs[:body]).to eq ['password', 'password_confirmation']
11
+ end
12
+
13
+ describe 'auth' do
14
+ context 'when only bearer auth should get scrubbed' do
15
+ before(:each) do
16
+ LHC.configure do |c|
17
+ c.scrubs[:auth] = [:bearer]
18
+ end
19
+ end
20
+
21
+ it 'has only bearer auth in scrubs' do
22
+ expect(LHC.config.scrubs[:auth]).to eq([:bearer])
23
+ expect(LHC.config.scrubs[:params]).to eq []
24
+ expect(LHC.config.scrubs[:headers]).to eq []
25
+ expect(LHC.config.scrubs[:body]).to eq ['password', 'password_confirmation']
26
+ end
27
+ end
28
+ end
29
+
30
+ context 'params' do
31
+ context 'when additional param "api_key" should be scrubbed' do
32
+ before(:each) do
33
+ LHC.configure do |c|
34
+ c.scrubs[:params] << 'api_key'
35
+ end
36
+ end
37
+
38
+ it 'has "api_key" in scrubs' do
39
+ expect(LHC.config.scrubs[:auth]).to eq [:bearer, :basic]
40
+ expect(LHC.config.scrubs[:params]).to eq ['api_key']
41
+ expect(LHC.config.scrubs[:headers]).to eq []
42
+ expect(LHC.config.scrubs[:body]).to eq ['password', 'password_confirmation']
43
+ end
44
+ end
45
+ end
46
+
47
+ context 'headers' do
48
+ context 'when additional header "private_key" should be scrubbed' do
49
+ before(:each) do
50
+ LHC.configure do |c|
51
+ c.scrubs[:headers] << 'private_key'
52
+ end
53
+ end
54
+
55
+ it 'has "private_key" in scrubs' do
56
+ expect(LHC.config.scrubs[:auth]).to eq [:bearer, :basic]
57
+ expect(LHC.config.scrubs[:params]).to eq []
58
+ expect(LHC.config.scrubs[:headers]).to eq ['private_key']
59
+ expect(LHC.config.scrubs[:body]).to eq ['password', 'password_confirmation']
60
+ end
61
+ end
62
+ end
63
+
64
+ context 'body' do
65
+ context 'when only password should get scrubbed' do
66
+ before(:each) do
67
+ LHC.configure do |c|
68
+ c.scrubs[:body] = ['password']
69
+ end
70
+ end
71
+
72
+ it 'has password in scrubs' do
73
+ expect(LHC.config.scrubs[:auth]).to eq [:bearer, :basic]
74
+ expect(LHC.config.scrubs[:params]).to eq []
75
+ expect(LHC.config.scrubs[:headers]).to eq []
76
+ expect(LHC.config.scrubs[:body]).to eq(['password'])
77
+ end
78
+ end
79
+
80
+ context 'when "user_token" should be scrubbed' do
81
+ before(:each) do
82
+ LHC.configure do |c|
83
+ c.scrubs[:body] << 'user_token'
84
+ end
85
+ end
86
+
87
+ it 'has user_token in scrubs' do
88
+ expect(LHC.config.scrubs[:auth]).to eq [:bearer, :basic]
89
+ expect(LHC.config.scrubs[:params]).to eq []
90
+ expect(LHC.config.scrubs[:headers]).to eq []
91
+ expect(LHC.config.scrubs[:body]).to eq(['password', 'password_confirmation', 'user_token'])
92
+ end
93
+ end
94
+ end
95
+
96
+ context 'when nothing should be scrubbed' do
97
+ before(:each) do
98
+ LHC.configure do |c|
99
+ c.scrubs = {}
100
+ end
101
+ end
102
+
103
+ it 'does not have scrubs' do
104
+ expect(LHC.config.scrubs.blank?).to be true
105
+ expect(LHC.config.scrubs[:auth]).to be nil
106
+ end
107
+ end
108
+ end