forest_liana 7.2.0 → 7.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/forest_liana/actions_controller.rb +3 -0
  3. data/app/controllers/forest_liana/associations_controller.rb +4 -0
  4. data/app/controllers/forest_liana/base_controller.rb +1 -0
  5. data/app/controllers/forest_liana/resources_controller.rb +8 -0
  6. data/app/controllers/forest_liana/router.rb +1 -0
  7. data/app/controllers/forest_liana/scopes_controller.rb +1 -0
  8. data/app/controllers/forest_liana/smart_actions_controller.rb +4 -0
  9. data/app/controllers/forest_liana/stats_controller.rb +2 -0
  10. data/app/services/forest_liana/intercom_attributes_getter.rb +1 -0
  11. data/app/services/forest_liana/intercom_conversation_getter.rb +1 -0
  12. data/app/services/forest_liana/intercom_conversations_getter.rb +1 -0
  13. data/app/services/forest_liana/ip_whitelist.rb +1 -0
  14. data/app/services/forest_liana/permissions_checker.rb +8 -1
  15. data/app/services/forest_liana/permissions_getter.rb +1 -0
  16. data/app/services/forest_liana/resources_getter.rb +1 -0
  17. data/app/services/forest_liana/schema_adapter.rb +4 -1
  18. data/app/services/forest_liana/search_query_builder.rb +1 -0
  19. data/app/services/forest_liana/stripe_invoices_getter.rb +1 -0
  20. data/app/services/forest_liana/stripe_payments_getter.rb +1 -0
  21. data/app/services/forest_liana/stripe_sources_getter.rb +1 -0
  22. data/app/services/forest_liana/stripe_subscriptions_getter.rb +1 -0
  23. data/config/initializers/httpclient.rb +11 -0
  24. data/config/initializers/logger.rb +8 -1
  25. data/lib/forest_liana/bootstrapper.rb +3 -1
  26. data/lib/forest_liana/collection.rb +1 -0
  27. data/lib/forest_liana/engine.rb +3 -0
  28. data/lib/forest_liana/schema_file_updater.rb +1 -0
  29. data/lib/forest_liana/version.rb +1 -1
  30. data/lib/forest_liana.rb +2 -0
  31. data/spec/config/initializers/logger_spec.rb +37 -0
  32. data/spec/services/forest_liana/permissions_checker_acl_disabled_spec.rb +28 -0
  33. data/spec/services/forest_liana/permissions_checker_acl_enabled_spec.rb +38 -0
  34. metadata +135 -134
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9661846cededb74e730dcd16808b9a34f13e4094467efad90d069c3eccb89e31
4
- data.tar.gz: 7c7da61924546e78660f9e6674ddc15fb787432793fca4866e53681a0b4d463c
3
+ metadata.gz: adc1d7ec157183e6001f0c62980ae41cac6812a06e4fb8d1d5189609e478c2c6
4
+ data.tar.gz: 21ccd896ff434a672683d6d384aa70e80b531c95189294551c3466a5ead3a5b6
5
5
  SHA512:
6
- metadata.gz: 602f195379f0e5175aaccd55eff08a49da25a6f720a68cca54fce1a40cc46d3b2e878b42fa85512a43b2de94fba9fe9476e01d6a267a572c6a4f2d73e4b182d3
7
- data.tar.gz: 5dac79fb17eaddc9bece92948109934cf043e61a6afb0e697b423419e45c7ffac05b4cb6575650eceb9b3cdcd006c334ab984954e01b37a836047dd0c1f0f493
6
+ metadata.gz: ce716a35923e78b2d00f066aa717e2a4fcd62506fe9073d370cbf30af90b1474a26cf940cd0a2aed1cf959b6c93cfe9314268e4a9ed048042ec3f04b9a227826
7
+ data.tar.gz: 5bb96fed2cc7218d162d4f0ac9df00b6270efa909deaab5ed84289cebe41606b36230423844584b9d65efd7b19588f06f42f90798d6515a05c0a2e2c2755011d
@@ -5,6 +5,7 @@ module ForestLiana
5
5
  begin
6
6
  params[:data][:attributes]
7
7
  rescue => error
8
+ FOREST_REPORTER.report error
8
9
  FOREST_LOGGER.error "Smart Action hook request error: #{error}"
9
10
  {}
10
11
  end
@@ -19,6 +20,7 @@ module ForestLiana
19
20
  begin
20
21
  collection.actions.find {|action| ActiveSupport::Inflector.parameterize(action.name) == params[:action_name]}
21
22
  rescue => error
23
+ FOREST_REPORTER.report error
22
24
  FOREST_LOGGER.error "Smart Action get action retrieval error: #{error}"
23
25
  nil
24
26
  end
@@ -57,6 +59,7 @@ module ForestLiana
57
59
  rescue ForestLiana::Errors::SmartActionInvalidFieldError => invalid_field_error
58
60
  FOREST_LOGGER.warn invalid_field_error.message
59
61
  rescue ForestLiana::Errors::SmartActionInvalidFieldHookError => invalid_hook_error
62
+ FOREST_REPORTER.report invalid_hook_error
60
63
  FOREST_LOGGER.error invalid_hook_error.message
61
64
  return render status: 500, json: { error: invalid_hook_error.message }
62
65
  end
@@ -18,6 +18,7 @@ module ForestLiana
18
18
  format.csv { render_csv(getter, @association.klass) }
19
19
  end
20
20
  rescue => error
21
+ FOREST_REPORTER.report error
21
22
  FOREST_LOGGER.error "Association Index error: #{error}\n#{format_stacktrace(error)}"
22
23
  internal_server_error
23
24
  end
@@ -30,6 +31,7 @@ module ForestLiana
30
31
 
31
32
  render serializer: nil, json: { count: getter.records_count }
32
33
  rescue => error
34
+ FOREST_REPORTER.report error
33
35
  FOREST_LOGGER.error "Association Index Count error: #{error}\n#{format_stacktrace(error)}"
34
36
  internal_server_error
35
37
  end
@@ -47,6 +49,7 @@ module ForestLiana
47
49
  head :no_content
48
50
  end
49
51
  rescue => error
52
+ FOREST_REPORTER.report error
50
53
  FOREST_LOGGER.error "Association Update error: #{error}\n#{format_stacktrace(error)}"
51
54
  internal_server_error
52
55
  end
@@ -59,6 +62,7 @@ module ForestLiana
59
62
 
60
63
  head :no_content
61
64
  rescue => error
65
+ FOREST_REPORTER.report error
62
66
  FOREST_LOGGER.error "Association Associate error: #{error}\n#{format_stacktrace(error)}"
63
67
  internal_server_error
64
68
  end
@@ -30,6 +30,7 @@ module ForestLiana
30
30
  }])
31
31
  render(serializer: nil, json: error_data, status: exception.status)
32
32
  rescue => exception
33
+ FOREST_REPORTER.report exception
33
34
  FOREST_LOGGER.error(exception)
34
35
  FOREST_LOGGER.error(exception.backtrace.join("\n"))
35
36
  render(serializer: nil, json: nil, status: :internal_server_error)
@@ -47,6 +47,7 @@ module ForestLiana
47
47
  }])
48
48
  render(serializer: nil, json: error_data, status: error.status)
49
49
  rescue => error
50
+ FOREST_REPORTER.report error
50
51
  FOREST_LOGGER.error "Records Index error: #{error}\n#{format_stacktrace(error)}"
51
52
  internal_server_error
52
53
  end
@@ -79,6 +80,7 @@ module ForestLiana
79
80
  }])
80
81
  render(serializer: nil, json: error_data, status: error.status)
81
82
  rescue => error
83
+ FOREST_REPORTER.report error
82
84
  FOREST_LOGGER.error "Records Index Count error: #{error}\n#{format_stacktrace(error)}"
83
85
  internal_server_error
84
86
  end
@@ -96,6 +98,7 @@ module ForestLiana
96
98
  rescue ActiveRecord::RecordNotFound
97
99
  render serializer: nil, json: { status: 404 }, status: :not_found
98
100
  rescue => error
101
+ FOREST_REPORTER.report error
99
102
  FOREST_LOGGER.error "Record Show error: #{error}\n#{format_stacktrace(error)}"
100
103
  internal_server_error
101
104
  end
@@ -119,6 +122,7 @@ module ForestLiana
119
122
  creator.record.errors), status: 400
120
123
  end
121
124
  rescue => error
125
+ FOREST_REPORTER.report error
122
126
  FOREST_LOGGER.error "Record Create error: #{error}\n#{format_stacktrace(error)}"
123
127
  internal_server_error
124
128
  end
@@ -142,6 +146,7 @@ module ForestLiana
142
146
  updater.record.errors), status: 400
143
147
  end
144
148
  rescue => error
149
+ FOREST_REPORTER.report error
145
150
  FOREST_LOGGER.error "Record Update error: #{error}\n#{format_stacktrace(error)}"
146
151
  internal_server_error
147
152
  end
@@ -162,6 +167,7 @@ module ForestLiana
162
167
 
163
168
  head :no_content
164
169
  rescue => error
170
+ FOREST_REPORTER.report error
165
171
  FOREST_LOGGER.error "Record Destroy error: #{error}\n#{format_stacktrace(error)}"
166
172
  internal_server_error
167
173
  end
@@ -175,6 +181,7 @@ module ForestLiana
175
181
 
176
182
  head :no_content
177
183
  rescue => error
184
+ FOREST_REPORTER.report error
178
185
  FOREST_LOGGER.error "Records Destroy error: #{error}\n#{format_stacktrace(error)}"
179
186
  internal_server_error
180
187
  end
@@ -190,6 +197,7 @@ module ForestLiana
190
197
  render serializer: nil, json: { status: 404 }, status: :not_found
191
198
  end
192
199
  rescue => error
200
+ FOREST_REPORTER.report error
193
201
  FOREST_LOGGER.error "Find Collection error: #{error}\n#{format_stacktrace(error)}"
194
202
  render serializer: nil, json: { status: 404 }, status: :not_found
195
203
  end
@@ -39,6 +39,7 @@ class ForestLiana::Router
39
39
 
40
40
  controller.action(action.to_sym).call(env)
41
41
  rescue NoMethodError => exception
42
+ FOREST_REPORTER.report exception
42
43
  FOREST_LOGGER.error "Routing error: #{exception}\n#{exception.backtrace.join("\n\t")}"
43
44
  ForestLiana::BaseController.action(:route_not_found).call(env)
44
45
  end
@@ -12,6 +12,7 @@ module ForestLiana
12
12
  ForestLiana::ScopeManager.invalidate_scope_cache(rendering_id)
13
13
  return render serializer: nil, json: { status: 200 }, status: :ok
14
14
  rescue => error
15
+ FOREST_REPORTER.report error
15
16
  FOREST_LOGGER.error "Error during scope cache invalidation: #{error.message}"
16
17
  render serializer: nil, json: {status: 500 }, status: :internal_server_error
17
18
  end
@@ -12,6 +12,7 @@ module ForestLiana
12
12
  begin
13
13
  params[:data][:attributes]
14
14
  rescue => error
15
+ FOREST_REPORTER.report error
15
16
  FOREST_LOGGER.error "Smart Action execution error: #{error}"
16
17
  {}
17
18
  end
@@ -47,6 +48,7 @@ module ForestLiana
47
48
  # target records are out of scope
48
49
  render serializer: nil, json: { error: 'Smart Action: target record not found' }, status: :bad_request
49
50
  rescue => error
51
+ FOREST_REPORTER.report error
50
52
  FOREST_LOGGER.error "Smart Action: #{error}\n#{format_stacktrace(error)}"
51
53
  render serializer: nil, json: { error: 'Smart Action: failed to evaluate permissions' }, status: :internal_server_error
52
54
  end
@@ -70,6 +72,7 @@ module ForestLiana
70
72
  render serializer: nil, json: { status: 400 }, status: :bad_request
71
73
  end
72
74
  rescue => error
75
+ FOREST_REPORTER.report error
73
76
  FOREST_LOGGER.error "Smart Action execution error: #{error}"
74
77
  render serializer: nil, json: { status: 400 }, status: :bad_request
75
78
  end
@@ -85,6 +88,7 @@ module ForestLiana
85
88
  end
86
89
  resource
87
90
  rescue => error
91
+ FOREST_REPORTER.report error
88
92
  FOREST_LOGGER.error "Find Collection error: #{error}\n#{format_stacktrace(error)}"
89
93
  render serializer: nil, json: { status: 404 }, status: :not_found
90
94
  end
@@ -60,6 +60,7 @@ module ForestLiana
60
60
  render json: { errors: [{ status: 422, detail: error.message }] },
61
61
  status: :unprocessable_entity, serializer: nil
62
62
  rescue => error
63
+ FOREST_REPORTER.report error
63
64
  FOREST_LOGGER.error "Live Query error: #{error.message}"
64
65
  render json: { errors: [{ status: 422, detail: error.message }] },
65
66
  status: :unprocessable_entity, serializer: nil
@@ -110,6 +111,7 @@ module ForestLiana
110
111
 
111
112
  return head :forbidden unless checker.is_authorized?
112
113
  rescue => error
114
+ FOREST_REPORTER.report error
113
115
  FOREST_LOGGER.error "Stats execution error: #{error}"
114
116
  render serializer: nil, json: { status: 400 }, status: :bad_request
115
117
  end
@@ -18,6 +18,7 @@ module ForestLiana
18
18
  @record = user
19
19
  rescue Intercom::ResourceNotFound
20
20
  rescue Intercom::UnexpectedError => exception
21
+ FOREST_REPORTER.report exception
21
22
  FOREST_LOGGER.error "Cannot retrieve the Intercom attributes: #{exception.message}"
22
23
  end
23
24
  end
@@ -14,6 +14,7 @@ module ForestLiana
14
14
  rescue Intercom::ResourceNotFound
15
15
  @record = nil
16
16
  rescue Intercom::UnexpectedError => exception
17
+ FOREST_REPORTER.report exception
17
18
  FOREST_LOGGER.error "Cannot retrieve the Intercom conversation: #{exception.message}"
18
19
  @record = nil
19
20
  end
@@ -31,6 +31,7 @@ module ForestLiana
31
31
  rescue Intercom::ResourceNotFound
32
32
  @records = []
33
33
  rescue Intercom::UnexpectedError => exception
34
+ FOREST_REPORTER.report exception
34
35
  FOREST_LOGGER.error "Cannot retrieve the Intercom conversations: #{exception.message}"
35
36
  @records = []
36
37
  end
@@ -21,6 +21,7 @@ module ForestLiana
21
21
  false
22
22
  end
23
23
  rescue => exception
24
+ FOREST_REPORTER.report exception
24
25
  FOREST_LOGGER.error 'Cannot retrieve the IP Whitelist from the Forest server.'
25
26
  FOREST_LOGGER.error 'Which was caused by:'
26
27
  ForestLiana::Errors::ExceptionHelper.recursively_print(exception, margin: ' ', is_error: true)
@@ -159,9 +159,16 @@ module ForestLiana
159
159
 
160
160
  def segment_query_allowed?
161
161
  segments_queries_permissions = get_segments_in_permissions
162
-
162
+ # NOTICE: The segmentQuery should be in the segments_queries_permissions
163
163
  return false unless segments_queries_permissions
164
164
 
165
+ # Handle UNION queries made by the FRONT to display available actions on details view
166
+ unionQueries = @collection_list_parameters[:segmentQuery].split('/*MULTI-SEGMENTS-QUERIES-UNION*/ UNION ');
167
+ if unionQueries.length > 1
168
+ # Are unionQueries all included only in the allowed queries
169
+ return unionQueries.all? { |unionQuery| segments_queries_permissions.select { |query| query.gsub(/;\s*/i, '') === unionQuery }.length > 0 };
170
+ end
171
+
165
172
  # NOTICE: @query_request_info matching an existing segment query
166
173
  return segments_queries_permissions.include? @collection_list_parameters[:segmentQuery]
167
174
  end
@@ -47,6 +47,7 @@ module ForestLiana
47
47
  raise "Forest API returned an #{ForestLiana::Errors::HTTPErrorHelper.format(response)}"
48
48
  end
49
49
  rescue => exception
50
+ FOREST_REPORTER.report exception
50
51
  FOREST_LOGGER.error 'Cannot retrieve the permissions from the Forest server.'
51
52
  FOREST_LOGGER.error 'Which was caused by:'
52
53
  ForestLiana::Errors::ExceptionHelper.recursively_print(exception, margin: ' ', is_error: true)
@@ -179,6 +179,7 @@ module ForestLiana
179
179
  )
180
180
  rescue => error
181
181
  error_message = "Live Query Segment: #{error.message}"
182
+ FOREST_REPORTER.report error
182
183
  FOREST_LOGGER.error(error_message)
183
184
  raise ForestLiana::Errors::LiveQueryError.new(error_message)
184
185
  end
@@ -261,6 +261,7 @@ module ForestLiana
261
261
  FOREST_LOGGER.warn "The association \"#{association.name.to_s}\" " \
262
262
  "does not seem to exist for model \"#{@model.name}\"."
263
263
  rescue => exception
264
+ FOREST_REPORTER.report exception
264
265
  FOREST_LOGGER.error "An error occured trying to add " \
265
266
  "\"#{association.name.to_s}\" association:\n#{exception}"
266
267
  end
@@ -350,10 +351,12 @@ module ForestLiana
350
351
  type = 'Number'
351
352
  when :json, :jsonb, :hstore
352
353
  type = 'Json'
353
- when :string, :text, :citext, :uuid
354
+ when :string, :text, :citext
354
355
  type = 'String'
355
356
  when :time
356
357
  type = 'Time'
358
+ when :uuid
359
+ type = 'Uuid'
357
360
  end
358
361
 
359
362
  is_array = (column.respond_to?(:array) && column.array == true)
@@ -31,6 +31,7 @@ module ForestLiana
31
31
  begin
32
32
  @records = field[:search].call(@records, @search)
33
33
  rescue => exception
34
+ FOREST_REPORTER.report exception
34
35
  FOREST_LOGGER.error "Cannot search properly on Smart Field:\n" \
35
36
  "#{exception}"
36
37
  end
@@ -50,6 +50,7 @@ module ForestLiana
50
50
  d
51
51
  end
52
52
  rescue ::Stripe::InvalidRequestError => error
53
+ FOREST_REPORTER.report error
53
54
  FOREST_LOGGER.error "Stripe error: #{error.message}"
54
55
  @records = []
55
56
  end
@@ -48,6 +48,7 @@ module ForestLiana
48
48
  d
49
49
  end
50
50
  rescue ::Stripe::InvalidRequestError => error
51
+ FOREST_REPORTER.report error
51
52
  FOREST_LOGGER.error "Stripe error: #{error.message}"
52
53
  @records = []
53
54
  end
@@ -46,6 +46,7 @@ module ForestLiana
46
46
  d
47
47
  end
48
48
  rescue ::Stripe::InvalidRequestError => error
49
+ FOREST_REPORTER.report error
49
50
  FOREST_LOGGER.error "Stripe error: #{error.message}"
50
51
  @records = []
51
52
  end
@@ -43,6 +43,7 @@ module ForestLiana
43
43
  d
44
44
  end
45
45
  rescue ::Stripe::InvalidRequestError => error
46
+ FOREST_REPORTER.report error
46
47
  FOREST_LOGGER.error "Stripe error: #{error.message}"
47
48
  @records = []
48
49
  end
@@ -0,0 +1,11 @@
1
+ require 'httpclient'
2
+
3
+ class HTTPClient
4
+ alias original_initialize initialize
5
+
6
+ def initialize(*args, &block)
7
+ original_initialize(*args, &block)
8
+ # NOTICE: Force use of the default system CA certs (instead of the 6 year old bundled ones).
9
+ @session_manager&.ssl_config&.set_default_paths
10
+ end
11
+ end
@@ -18,12 +18,19 @@ module ForestLiana
18
18
  displayed_message = "[#{datetime.to_s(:db)}] Forest 🌳🌳🌳 " \
19
19
  "#{message}\n"
20
20
  "\e[#{logger_colors[severity.to_sym]}m#{displayed_message}\033[0m"
21
- end
21
+ end
22
22
  logger
23
23
  end
24
24
  end
25
25
  end
26
26
  end
27
+
28
+ class Reporter
29
+ def self.report (error)
30
+ ForestLiana.reporter.report error if ForestLiana.reporter
31
+ end
32
+ end
27
33
  end
28
34
 
29
35
  FOREST_LOGGER = ForestLiana::Logger.log
36
+ FOREST_REPORTER = ForestLiana::Reporter
@@ -82,7 +82,8 @@ module ForestLiana
82
82
  @collections_sent = content['collections']
83
83
  @meta_sent = content['meta']
84
84
  generate_action_hooks
85
- rescue JSON::JSONError
85
+ rescue JSON::JSONError => error
86
+ FOREST_REPORTER.report error
86
87
  FOREST_LOGGER.error "The content of .forestadmin-schema.json file is not a correct JSON."
87
88
  FOREST_LOGGER.error "The schema cannot be synchronized with Forest Admin servers."
88
89
  end
@@ -122,6 +123,7 @@ module ForestLiana
122
123
  end
123
124
  end
124
125
  rescue => exception
126
+ FOREST_REPORTER.report exception
125
127
  FOREST_LOGGER.error "Cannot fetch properly model #{model.name}:\n" \
126
128
  "#{exception}"
127
129
  end
@@ -91,6 +91,7 @@ module ForestLiana::Collection
91
91
  begin
92
92
  object.instance_eval(&block)
93
93
  rescue => exception
94
+ FOREST_REPORTER.report exception
94
95
  FOREST_LOGGER.error "Cannot retrieve the " + name.to_s + " value because of an " \
95
96
  "internal error in the getter implementation: " + exception.message
96
97
  nil
@@ -37,6 +37,7 @@ module ForestLiana
37
37
  end
38
38
  nil
39
39
  rescue => exception
40
+ FOREST_REPORTER.report exception
40
41
  exception
41
42
  end
42
43
  end
@@ -51,6 +52,7 @@ module ForestLiana
51
52
  ActiveRecord::Base.connection_pool.with_connection { |connection| connection.active? }
52
53
  rescue => error
53
54
  database_available = false
55
+ FOREST_REPORTER.report error
54
56
  FOREST_LOGGER.error "No Apimap sent to Forest servers, it seems that the database is not accessible:\n#{error}"
55
57
  end
56
58
  database_available
@@ -75,6 +77,7 @@ module ForestLiana
75
77
 
76
78
  config.after_initialize do |app|
77
79
  if error
80
+ FOREST_REPORTER.report error
78
81
  FOREST_LOGGER.error "Impossible to set the whitelisted Forest " \
79
82
  "domains for CORS constraint:\n#{error}"
80
83
  end
@@ -102,6 +102,7 @@ module ForestLiana
102
102
  rescue ForestLiana::Errors::SmartActionInvalidFieldError => invalid_field_error
103
103
  FOREST_LOGGER.warn invalid_field_error.message
104
104
  rescue ForestLiana::Errors::SmartActionInvalidFieldHookError => invalid_hook_error
105
+ FOREST_REPORTER.report invalid_hook_error
105
106
  FOREST_LOGGER.error invalid_hook_error.message
106
107
  end
107
108
  action['fields'] = action['fields'].map { |field| field.slice(*KEYS_ACTION_FIELD) }
@@ -1,3 +1,3 @@
1
1
  module ForestLiana
2
- VERSION = "7.2.0"
2
+ VERSION = "7.4.0"
3
3
  end
data/lib/forest_liana.rb CHANGED
@@ -28,6 +28,7 @@ module ForestLiana
28
28
  mattr_accessor :names_overriden
29
29
  mattr_accessor :meta
30
30
  mattr_accessor :logger
31
+ mattr_accessor :reporter
31
32
  # TODO: Remove once lianas prior to 2.0.0 are not supported anymore.
32
33
  mattr_accessor :names_old_overriden
33
34
 
@@ -40,6 +41,7 @@ module ForestLiana
40
41
  self.names_overriden = {}
41
42
  self.meta = {}
42
43
  self.logger = nil
44
+ self.reporter = nil
43
45
 
44
46
  @config_dir = 'lib/forest_liana/**/*.rb'
45
47
 
@@ -27,4 +27,41 @@ module ForestLiana
27
27
  end
28
28
  end
29
29
  end
30
+
31
+ describe Reporter do
32
+ describe 'self.reporter' do
33
+ describe 'with a reporter provided' do
34
+ it 'should report the error' do
35
+ class SampleReporter
36
+ def report(error)
37
+ end
38
+ end
39
+
40
+ spier = spy('sampleReporter')
41
+
42
+ ForestLiana.reporter = spier
43
+ FOREST_REPORTER.report(Exception.new "sample error")
44
+
45
+ expect(spier).to have_received(:report)
46
+ ForestLiana.reporter = nil
47
+ end
48
+ end
49
+
50
+ describe 'without any reporter provided' do
51
+ it 'should not report the error' do
52
+ class ErrorReporter
53
+ def report(error)
54
+ expect(false).to be_truthy
55
+ end
56
+ end
57
+
58
+ spier = spy('errorReporter')
59
+
60
+ FOREST_REPORTER.report(Exception.new "sample error")
61
+
62
+ expect(spier).not_to have_received(:export)
63
+ end
64
+ end
65
+ end
66
+ end
30
67
  end
@@ -481,6 +481,14 @@ module ForestLiana
481
481
  end
482
482
  end
483
483
 
484
+ context 'when user has no segments and param segmentQuery is there' do
485
+ let(:segmentQuery) { 'SELECT * FROM products;' }
486
+ let(:collection_list_parameters) { { :user_id => "1", :segmentQuery => segmentQuery } }
487
+ it 'should be authorized' do
488
+ expect(subject.is_authorized?).to be false
489
+ end
490
+ end
491
+
484
492
  context 'when segments are defined' do
485
493
  let(:segments_permissions) { ['SELECT * FROM products;', 'SELECT * FROM sellers;'] }
486
494
  let(:collection_list_parameters) { { :user_id => "1", :segmentQuery => segmentQuery } }
@@ -499,6 +507,26 @@ module ForestLiana
499
507
  end
500
508
  end
501
509
 
510
+ context 'when received union segments NOT passing validation' do
511
+ let(:segmentQuery) { 'SELECT * FROM sellers/*MULTI-SEGMENTS-QUERIES-UNION*/ UNION SELECT column_name(s) FROM table1 UNION SELECT column_name(s) FROM table2' }
512
+ it 'should return false' do
513
+ expect(subject.is_authorized?).to be false
514
+ end
515
+ end
516
+
517
+ context 'when received union segments passing validation' do
518
+ let(:segmentQuery) { 'SELECT * FROM sellers/*MULTI-SEGMENTS-QUERIES-UNION*/ UNION SELECT * FROM products' }
519
+ it 'should return true' do
520
+ expect(subject.is_authorized?).to be true
521
+ end
522
+ end
523
+ context 'when received union segments with UNION inside passing validation' do
524
+ let(:segmentQuery) { 'SELECT COUNT(*) AS value FROM products/*MULTI-SEGMENTS-QUERIES-UNION*/ UNION SELECT column_name(s) FROM table1 UNION SELECT column_name(s) FROM table2' }
525
+ let(:segments_permissions) { ['SELECT COUNT(*) AS value FROM products;', 'SELECT column_name(s) FROM table1 UNION SELECT column_name(s) FROM table2;', 'SELECT * FROM products;', 'SELECT * FROM sellers;'] }
526
+ it 'should return true' do
527
+ expect(subject.is_authorized?).to be true
528
+ end
529
+ end
502
530
  end
503
531
 
504
532
  context 'when user has not the required permission' do
@@ -458,6 +458,14 @@ module ForestLiana
458
458
  end
459
459
  end
460
460
 
461
+ context 'when user has no segments queries permissions and param segmentQuery is there' do
462
+ let(:segmentQuery) { 'SELECT * FROM products;' }
463
+ let(:collection_list_parameters) { { :user_id => "1", :segmentQuery => segmentQuery } }
464
+ it 'should be authorized' do
465
+ expect(subject.is_authorized?).to be false
466
+ end
467
+ end
468
+
461
469
  context 'when segments are defined' do
462
470
  let(:default_rendering_id) { 1 }
463
471
  let(:segments_permissions) {
@@ -484,6 +492,36 @@ module ForestLiana
484
492
  expect(subject.is_authorized?).to be false
485
493
  end
486
494
  end
495
+
496
+ context 'when received union segments NOT passing validation' do
497
+ let(:segmentQuery) { 'SELECT * FROM sellers/*MULTI-SEGMENTS-QUERIES-UNION*/ UNION SELECT column_name(s) FROM table1 UNION SELECT column_name(s) FROM table2' }
498
+ it 'should return false' do
499
+ expect(subject.is_authorized?).to be false
500
+ end
501
+ end
502
+
503
+ context 'when received union segments passing validation' do
504
+ let(:segmentQuery) { 'SELECT * FROM sellers/*MULTI-SEGMENTS-QUERIES-UNION*/ UNION SELECT * FROM products' }
505
+ it 'should return true' do
506
+ expect(subject.is_authorized?).to be true
507
+ end
508
+ end
509
+
510
+ context 'when received union segments with UNION inside passing validation' do
511
+ let(:segmentQuery) { 'SELECT COUNT(*) AS value FROM products/*MULTI-SEGMENTS-QUERIES-UNION*/ UNION SELECT column_name(s) FROM table1 UNION SELECT column_name(s) FROM table2' }
512
+ let(:segments_permissions) {
513
+ {
514
+ default_rendering_id => {
515
+ collection_name => {
516
+ 'segments' => ['SELECT COUNT(*) AS value FROM products;', 'SELECT column_name(s) FROM table1 UNION SELECT column_name(s) FROM table2;', 'SELECT * FROM products;', 'SELECT * FROM sellers;']
517
+ }
518
+ }
519
+ }
520
+ }
521
+ it 'should return true' do
522
+ expect(subject.is_authorized?).to be true
523
+ end
524
+ end
487
525
  end
488
526
  end
489
527
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: forest_liana
3
3
  version: !ruby/object:Gem::Version
4
- version: 7.2.0
4
+ version: 7.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sandro Munda
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-09-10 00:00:00.000000000 Z
11
+ date: 2021-11-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -302,6 +302,7 @@ files:
302
302
  - config/initializers/arel-helpers.rb
303
303
  - config/initializers/error-messages.rb
304
304
  - config/initializers/errors.rb
305
+ - config/initializers/httpclient.rb
305
306
  - config/initializers/logger.rb
306
307
  - config/initializers/time_formats.rb
307
308
  - config/routes.rb
@@ -509,171 +510,171 @@ signing_key:
509
510
  specification_version: 4
510
511
  summary: Official Rails Liana for Forest
511
512
  test_files:
512
- - test/services/forest_liana/operator_date_interval_parser_test.rb
513
- - test/services/forest_liana/schema_adapter_test.rb
514
- - test/forest_liana_test.rb
515
- - test/routing/route_test.rb
516
- - test/dummy/bin/rake
517
- - test/dummy/bin/bundle
513
+ - test/test_helper.rb
514
+ - test/dummy/config.ru
518
515
  - test/dummy/bin/setup
516
+ - test/dummy/bin/bundle
517
+ - test/dummy/bin/rake
519
518
  - test/dummy/bin/rails
520
- - test/dummy/config/boot.rb
521
- - test/dummy/config/secrets.yml
522
- - test/dummy/config/routes.rb
523
- - test/dummy/config/environments/test.rb
524
- - test/dummy/config/environments/development.rb
525
- - test/dummy/config/environments/production.rb
526
- - test/dummy/config/locales/en.yml
527
- - test/dummy/config/initializers/inflections.rb
528
- - test/dummy/config/initializers/cookies_serializer.rb
529
- - test/dummy/config/initializers/wrap_parameters.rb
530
- - test/dummy/config/initializers/mime_types.rb
531
- - test/dummy/config/initializers/assets.rb
532
- - test/dummy/config/initializers/session_store.rb
533
- - test/dummy/config/initializers/filter_parameter_logging.rb
534
- - test/dummy/config/initializers/backtrace_silencers.rb
535
- - test/dummy/config/application.rb
536
- - test/dummy/config/database.yml
537
- - test/dummy/config/environment.rb
538
519
  - test/dummy/Rakefile
539
520
  - test/dummy/db/schema.rb
540
- - test/dummy/db/migrate/20150608131430_create_integer_field.rb
541
- - test/dummy/db/migrate/20181111162121_create_references_table.rb
542
- - test/dummy/db/migrate/20160628173505_add_timestamps.rb
543
- - test/dummy/db/migrate/20150608130516_create_date_field.rb
544
- - test/dummy/db/migrate/20150608131610_create_float_field.rb
545
- - test/dummy/db/migrate/20150608132159_create_boolean_field.rb
521
+ - test/dummy/db/migrate/20150612112520_create_has_and_belongs_to_many_field.rb
546
522
  - test/dummy/db/migrate/20150623115554_create_has_many_class_name_field.rb
547
- - test/dummy/db/migrate/20150608131603_create_decimal_field.rb
548
- - test/dummy/db/migrate/20150609114636_create_belongs_to_class_name_field.rb
549
- - test/dummy/db/migrate/20150616150629_create_polymorphic_field.rb
550
- - test/dummy/db/migrate/20170614141921_create_serialize_field.rb
551
- - test/dummy/db/migrate/20150814081918_create_has_many_through_field.rb
552
- - test/dummy/db/migrate/20150608133038_create_belongs_to_field.rb
553
- - test/dummy/db/migrate/20150608133044_create_has_one_field.rb
523
+ - test/dummy/db/migrate/20150608130516_create_date_field.rb
554
524
  - test/dummy/db/migrate/20150608132621_create_string_field.rb
555
525
  - test/dummy/db/migrate/20160627172810_create_owner.rb
526
+ - test/dummy/db/migrate/20170614141921_create_serialize_field.rb
527
+ - test/dummy/db/migrate/20150608131430_create_integer_field.rb
528
+ - test/dummy/db/migrate/20150608133038_create_belongs_to_field.rb
529
+ - test/dummy/db/migrate/20150608131610_create_float_field.rb
530
+ - test/dummy/db/migrate/20160628173505_add_timestamps.rb
556
531
  - test/dummy/db/migrate/20150608150016_create_has_many_field.rb
557
- - test/dummy/db/migrate/20150612112520_create_has_and_belongs_to_many_field.rb
532
+ - test/dummy/db/migrate/20150608131603_create_decimal_field.rb
533
+ - test/dummy/db/migrate/20150616150629_create_polymorphic_field.rb
534
+ - test/dummy/db/migrate/20150609114636_create_belongs_to_class_name_field.rb
535
+ - test/dummy/db/migrate/20181111162121_create_references_table.rb
558
536
  - test/dummy/db/migrate/20160627172951_create_tree.rb
559
- - test/dummy/public/500.html
537
+ - test/dummy/db/migrate/20150608133044_create_has_one_field.rb
538
+ - test/dummy/db/migrate/20150814081918_create_has_many_through_field.rb
539
+ - test/dummy/db/migrate/20150608132159_create_boolean_field.rb
560
540
  - test/dummy/public/422.html
561
- - test/dummy/public/404.html
562
541
  - test/dummy/public/favicon.ico
563
- - test/dummy/config.ru
564
- - test/dummy/app/models/reference.rb
565
- - test/dummy/app/models/belongs_to_field.rb
566
- - test/dummy/app/models/has_many_class_name_field.rb
567
- - test/dummy/app/models/decimal_field.rb
568
- - test/dummy/app/models/owner.rb
569
- - test/dummy/app/models/integer_field.rb
570
- - test/dummy/app/models/boolean_field.rb
542
+ - test/dummy/public/500.html
543
+ - test/dummy/public/404.html
544
+ - test/dummy/README.rdoc
545
+ - test/dummy/config/secrets.yml
546
+ - test/dummy/config/environments/test.rb
547
+ - test/dummy/config/environments/production.rb
548
+ - test/dummy/config/environments/development.rb
549
+ - test/dummy/config/boot.rb
550
+ - test/dummy/config/routes.rb
551
+ - test/dummy/config/locales/en.yml
552
+ - test/dummy/config/application.rb
553
+ - test/dummy/config/database.yml
554
+ - test/dummy/config/environment.rb
555
+ - test/dummy/config/initializers/cookies_serializer.rb
556
+ - test/dummy/config/initializers/wrap_parameters.rb
557
+ - test/dummy/config/initializers/inflections.rb
558
+ - test/dummy/config/initializers/session_store.rb
559
+ - test/dummy/config/initializers/assets.rb
560
+ - test/dummy/config/initializers/backtrace_silencers.rb
561
+ - test/dummy/config/initializers/mime_types.rb
562
+ - test/dummy/config/initializers/filter_parameter_logging.rb
563
+ - test/dummy/app/helpers/application_helper.rb
564
+ - test/dummy/app/views/layouts/application.html.erb
565
+ - test/dummy/app/controllers/application_controller.rb
571
566
  - test/dummy/app/models/date_field.rb
572
- - test/dummy/app/models/serialize_field.rb
573
- - test/dummy/app/models/has_many_field.rb
574
- - test/dummy/app/models/tree.rb
575
567
  - test/dummy/app/models/belongs_to_class_name_field.rb
576
- - test/dummy/app/models/has_and_belongs_to_many_field.rb
577
568
  - test/dummy/app/models/float_field.rb
578
- - test/dummy/app/models/has_one_field.rb
569
+ - test/dummy/app/models/has_many_through_field.rb
570
+ - test/dummy/app/models/decimal_field.rb
571
+ - test/dummy/app/models/serialize_field.rb
572
+ - test/dummy/app/models/has_and_belongs_to_many_field.rb
573
+ - test/dummy/app/models/has_many_field.rb
574
+ - test/dummy/app/models/owner.rb
579
575
  - test/dummy/app/models/polymorphic_field.rb
576
+ - test/dummy/app/models/tree.rb
580
577
  - test/dummy/app/models/string_field.rb
581
- - test/dummy/app/models/has_many_through_field.rb
582
- - test/dummy/app/assets/config/manifest.js
583
- - test/dummy/app/assets/stylesheets/application.css
578
+ - test/dummy/app/models/belongs_to_field.rb
579
+ - test/dummy/app/models/integer_field.rb
580
+ - test/dummy/app/models/has_one_field.rb
581
+ - test/dummy/app/models/boolean_field.rb
582
+ - test/dummy/app/models/has_many_class_name_field.rb
583
+ - test/dummy/app/models/reference.rb
584
584
  - test/dummy/app/assets/javascripts/application.js
585
- - test/dummy/app/controllers/application_controller.rb
586
- - test/dummy/app/views/layouts/application.html.erb
587
- - test/dummy/app/helpers/application_helper.rb
588
- - test/dummy/README.rdoc
589
- - test/fixtures/has_many_through_field.yml
590
- - test/fixtures/has_many_field.yml
591
- - test/fixtures/string_field.yml
585
+ - test/dummy/app/assets/stylesheets/application.css
586
+ - test/dummy/app/assets/config/manifest.js
587
+ - test/routing/route_test.rb
588
+ - test/services/forest_liana/schema_adapter_test.rb
589
+ - test/services/forest_liana/operator_date_interval_parser_test.rb
590
+ - test/fixtures/belongs_to_field.yml
591
+ - test/fixtures/tree.yml
592
592
  - test/fixtures/owner.yml
593
+ - test/fixtures/reference.yml
594
+ - test/fixtures/has_many_through_field.yml
593
595
  - test/fixtures/has_one_field.yml
594
- - test/fixtures/tree.yml
595
596
  - test/fixtures/serialize_field.yml
596
- - test/fixtures/belongs_to_field.yml
597
- - test/fixtures/reference.yml
598
- - test/test_helper.rb
599
- - spec/services/forest_liana/has_many_getter_spec.rb
600
- - spec/services/forest_liana/permissions_formatter_spec.rb
601
- - spec/services/forest_liana/filters_parser_spec.rb
602
- - spec/services/forest_liana/permissions_checker_acl_enabled_spec.rb
603
- - spec/services/forest_liana/value_stat_getter_spec.rb
604
- - spec/services/forest_liana/pie_stat_getter_spec.rb
605
- - spec/services/forest_liana/permissions_checker_acl_disabled_spec.rb
606
- - spec/services/forest_liana/smart_action_field_validator_spec.rb
607
- - spec/services/forest_liana/schema_adapter_spec.rb
608
- - spec/services/forest_liana/permissions_getter_spec.rb
609
- - spec/services/forest_liana/resources_getter_spec.rb
610
- - spec/services/forest_liana/line_stat_getter_spec.rb
611
- - spec/services/forest_liana/apimap_sorter_spec.rb
612
- - spec/services/forest_liana/ip_whitelist_checker_spec.rb
613
- - spec/services/forest_liana/resource_updater_spec.rb
614
- - spec/services/forest_liana/permissions_checker_live_queries_spec.rb
615
- - spec/services/forest_liana/scope_manager_spec.rb
616
- - spec/config/initializers/logger_spec.rb
617
- - spec/requests/resources_spec.rb
597
+ - test/fixtures/string_field.yml
598
+ - test/fixtures/has_many_field.yml
599
+ - test/forest_liana_test.rb
600
+ - spec/helpers/forest_liana/query_helper_spec.rb
601
+ - spec/helpers/forest_liana/schema_helper_spec.rb
618
602
  - spec/requests/stats_spec.rb
619
- - spec/requests/actions_controller_spec.rb
603
+ - spec/requests/resources_spec.rb
620
604
  - spec/requests/authentications_spec.rb
621
- - spec/spec_helper.rb
622
- - spec/lib/forest_liana/schema_file_updater_spec.rb
623
- - spec/lib/forest_liana/bootstrapper_spec.rb
624
- - spec/rails_helper.rb
625
- - spec/dummy/bin/rake
626
- - spec/dummy/bin/bundle
605
+ - spec/requests/actions_controller_spec.rb
606
+ - spec/dummy/config.ru
627
607
  - spec/dummy/bin/setup
608
+ - spec/dummy/bin/bundle
609
+ - spec/dummy/bin/rake
628
610
  - spec/dummy/bin/rails
629
- - spec/dummy/config/boot.rb
611
+ - spec/dummy/lib/forest_liana/collections/user.rb
612
+ - spec/dummy/lib/forest_liana/collections/island.rb
613
+ - spec/dummy/lib/forest_liana/collections/location.rb
614
+ - spec/dummy/Rakefile
615
+ - spec/dummy/db/schema.rb
616
+ - spec/dummy/db/migrate/20190716130830_add_age_to_tree.rb
617
+ - spec/dummy/db/migrate/20190226174951_create_tree.rb
618
+ - spec/dummy/db/migrate/20210526084712_create_products.rb
619
+ - spec/dummy/db/migrate/20190226172951_create_user.rb
620
+ - spec/dummy/db/migrate/20210326110524_create_references.rb
621
+ - spec/dummy/db/migrate/20190226173051_create_isle.rb
622
+ - spec/dummy/db/migrate/20210326140855_create_locations.rb
623
+ - spec/dummy/db/migrate/20190716135241_add_type_to_user.rb
624
+ - spec/dummy/db/migrate/20210511141752_create_owners.rb
625
+ - spec/dummy/README.rdoc
630
626
  - spec/dummy/config/secrets.yml
631
- - spec/dummy/config/routes.rb
632
627
  - spec/dummy/config/environments/test.rb
633
- - spec/dummy/config/environments/development.rb
634
628
  - spec/dummy/config/environments/production.rb
635
- - spec/dummy/config/initializers/inflections.rb
636
- - spec/dummy/config/initializers/forest_liana.rb
629
+ - spec/dummy/config/environments/development.rb
630
+ - spec/dummy/config/boot.rb
631
+ - spec/dummy/config/routes.rb
632
+ - spec/dummy/config/application.rb
633
+ - spec/dummy/config/database.yml
634
+ - spec/dummy/config/environment.rb
637
635
  - spec/dummy/config/initializers/cookies_serializer.rb
638
636
  - spec/dummy/config/initializers/wrap_parameters.rb
639
- - spec/dummy/config/initializers/mime_types.rb
640
- - spec/dummy/config/initializers/assets.rb
637
+ - spec/dummy/config/initializers/inflections.rb
641
638
  - spec/dummy/config/initializers/session_store.rb
642
- - spec/dummy/config/initializers/filter_parameter_logging.rb
639
+ - spec/dummy/config/initializers/forest_liana.rb
640
+ - spec/dummy/config/initializers/assets.rb
643
641
  - spec/dummy/config/initializers/backtrace_silencers.rb
644
- - spec/dummy/config/application.rb
645
- - spec/dummy/config/database.yml
646
- - spec/dummy/config/environment.rb
647
- - spec/dummy/Rakefile
648
- - spec/dummy/db/schema.rb
649
- - spec/dummy/db/migrate/20190716135241_add_type_to_user.rb
650
- - spec/dummy/db/migrate/20210511141752_create_owners.rb
651
- - spec/dummy/db/migrate/20190226172951_create_user.rb
652
- - spec/dummy/db/migrate/20190716130830_add_age_to_tree.rb
653
- - spec/dummy/db/migrate/20210326140855_create_locations.rb
654
- - spec/dummy/db/migrate/20210326110524_create_references.rb
655
- - spec/dummy/db/migrate/20210526084712_create_products.rb
656
- - spec/dummy/db/migrate/20190226173051_create_isle.rb
657
- - spec/dummy/db/migrate/20190226174951_create_tree.rb
658
- - spec/dummy/config.ru
659
- - spec/dummy/lib/forest_liana/collections/location.rb
660
- - spec/dummy/lib/forest_liana/collections/user.rb
661
- - spec/dummy/lib/forest_liana/collections/island.rb
662
- - spec/dummy/app/config/routes.rb
663
- - spec/dummy/app/models/reference.rb
642
+ - spec/dummy/config/initializers/mime_types.rb
643
+ - spec/dummy/config/initializers/filter_parameter_logging.rb
644
+ - spec/dummy/app/helpers/application_helper.rb
645
+ - spec/dummy/app/views/layouts/application.html.erb
646
+ - spec/dummy/app/controllers/forest/islands_controller.rb
647
+ - spec/dummy/app/controllers/application_controller.rb
664
648
  - spec/dummy/app/models/product.rb
665
- - spec/dummy/app/models/location.rb
666
649
  - spec/dummy/app/models/user.rb
667
- - spec/dummy/app/models/island.rb
668
650
  - spec/dummy/app/models/owner.rb
669
651
  - spec/dummy/app/models/tree.rb
670
- - spec/dummy/app/assets/config/manifest.js
671
- - spec/dummy/app/assets/stylesheets/application.css
652
+ - spec/dummy/app/models/island.rb
653
+ - spec/dummy/app/models/location.rb
654
+ - spec/dummy/app/models/reference.rb
672
655
  - spec/dummy/app/assets/javascripts/application.js
673
- - spec/dummy/app/controllers/forest/islands_controller.rb
674
- - spec/dummy/app/controllers/application_controller.rb
675
- - spec/dummy/app/views/layouts/application.html.erb
676
- - spec/dummy/app/helpers/application_helper.rb
677
- - spec/dummy/README.rdoc
678
- - spec/helpers/forest_liana/schema_helper_spec.rb
679
- - spec/helpers/forest_liana/query_helper_spec.rb
656
+ - spec/dummy/app/assets/stylesheets/application.css
657
+ - spec/dummy/app/assets/config/manifest.js
658
+ - spec/dummy/app/config/routes.rb
659
+ - spec/rails_helper.rb
660
+ - spec/services/forest_liana/permissions_getter_spec.rb
661
+ - spec/services/forest_liana/filters_parser_spec.rb
662
+ - spec/services/forest_liana/schema_adapter_spec.rb
663
+ - spec/services/forest_liana/permissions_checker_acl_disabled_spec.rb
664
+ - spec/services/forest_liana/smart_action_field_validator_spec.rb
665
+ - spec/services/forest_liana/apimap_sorter_spec.rb
666
+ - spec/services/forest_liana/permissions_formatter_spec.rb
667
+ - spec/services/forest_liana/line_stat_getter_spec.rb
668
+ - spec/services/forest_liana/pie_stat_getter_spec.rb
669
+ - spec/services/forest_liana/has_many_getter_spec.rb
670
+ - spec/services/forest_liana/permissions_checker_acl_enabled_spec.rb
671
+ - spec/services/forest_liana/ip_whitelist_checker_spec.rb
672
+ - spec/services/forest_liana/resources_getter_spec.rb
673
+ - spec/services/forest_liana/value_stat_getter_spec.rb
674
+ - spec/services/forest_liana/scope_manager_spec.rb
675
+ - spec/services/forest_liana/permissions_checker_live_queries_spec.rb
676
+ - spec/services/forest_liana/resource_updater_spec.rb
677
+ - spec/lib/forest_liana/bootstrapper_spec.rb
678
+ - spec/lib/forest_liana/schema_file_updater_spec.rb
679
+ - spec/spec_helper.rb
680
+ - spec/config/initializers/logger_spec.rb