rubocop-flexport 0.4.0 → 0.5.0
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.
- checksums.yaml +4 -4
- data/config/default.yml +1 -0
- data/lib/rubocop/cop/flexport/engine_api_boundary.rb +82 -29
- data/lib/rubocop/cop/flexport/global_model_access_from_engine.rb +3 -0
- data/lib/rubocop/cop/flexport_cops.rb +1 -0
- data/lib/rubocop/cop/mixin/engine_node_context.rb +26 -0
- data/lib/rubocop/flexport/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e7bfc3b432b328659f2ac2dd842e48c05028482c7538fcd2f03a33dbbee4b561
|
4
|
+
data.tar.gz: b9fade3c98f628825b648b184fba3c6317c94476f2c4de1791bdf2aab7e7b372
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3a7687a4bf47c4f476006a00c7852d5c008daeb88693949b2ff182e28f46c6344fba487ed6e86cda52fc454a7cc5266ae33b47b98829494c96c8e902746c8faa
|
7
|
+
data.tar.gz: 01561c084ee90550946391998f5a28bf0959a2758ece148762714ccb28bb6db2300c8829c13776544a969fab377b136b47b864a8fab76d50461f0d4af9d821f3
|
data/config/default.yml
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# rubocop:disable Metrics/ClassLength
|
3
4
|
module RuboCop
|
4
5
|
module Cop
|
5
6
|
module Flexport
|
@@ -80,6 +81,36 @@ module RuboCop
|
|
80
81
|
# end
|
81
82
|
# ```
|
82
83
|
#
|
84
|
+
# # "StronglyProtectedEngines" parameter
|
85
|
+
#
|
86
|
+
# The Engine API is not actually a network API surface. Method invocations
|
87
|
+
# may happen synchronously and assume they are part of the same
|
88
|
+
# transaction. So if your engine is using modules whitelisted by
|
89
|
+
# other engines, then you cannot extract your engine code into a
|
90
|
+
# separate network-isolated service (even though within a big Rails
|
91
|
+
# monolith using engines the cross-engine method call might have been
|
92
|
+
# acceptable).
|
93
|
+
#
|
94
|
+
# The "StronglyProtectedEngines" parameter helps in the case you want to
|
95
|
+
# extract your engine completely. If your engine is listed as a strongly
|
96
|
+
# protected engine, then the following additional restricts apply:
|
97
|
+
#
|
98
|
+
# (1) Any use of your engine's code by code outside your engine is
|
99
|
+
# considered a violation, regardless of *your* _legacy_dependents.rb,
|
100
|
+
# _whitelist.rb, or engine API module. (no inbound access)
|
101
|
+
# (2) Any use of other engines' code within your engine is considered
|
102
|
+
# a violation, regardless of *their* _legacy_dependents.rb,
|
103
|
+
# _whitelist.rb, or engine API module. (no outbound access)
|
104
|
+
#
|
105
|
+
# (Note: "EngineSpecificOverrides" parameter still has effect.)
|
106
|
+
#
|
107
|
+
# # "EngineSpecificOverrides" parameter
|
108
|
+
#
|
109
|
+
# This parameter allows defining bi-lateral private "APIs" between
|
110
|
+
# engines. See example in global_model_access_from_engine_spec.rb.
|
111
|
+
# This may be useful if you plan to extract several engines into the
|
112
|
+
# same network-isolated service.
|
113
|
+
#
|
83
114
|
# @example
|
84
115
|
#
|
85
116
|
# # bad
|
@@ -109,25 +140,27 @@ module RuboCop
|
|
109
140
|
#
|
110
141
|
class EngineApiBoundary < Cop
|
111
142
|
include EngineApi
|
143
|
+
include EngineNodeContext
|
112
144
|
|
113
145
|
MSG = 'Direct access of %<engine>s engine. ' \
|
114
146
|
'Only access engine via %<engine>s::Api.'
|
115
147
|
|
148
|
+
STRONGLY_PROTECTED_MSG = 'All direct access of ' \
|
149
|
+
'%<engine>s engine disallowed because ' \
|
150
|
+
'it is in StronglyProtectedEngines list.'
|
151
|
+
|
152
|
+
STRONGLY_PROTECTED_CURRENT_MSG = 'Direct ' \
|
153
|
+
'access of other engines is disallowed in this file because ' \
|
154
|
+
'it\'s in the %<engine>s engine, which ' \
|
155
|
+
'is in the StronglyProtectedEngines list.'
|
156
|
+
|
116
157
|
def_node_matcher :rails_association_hash_args, <<-PATTERN
|
117
158
|
(send _ {:belongs_to :has_one :has_many} sym $hash)
|
118
159
|
PATTERN
|
119
160
|
|
120
161
|
def on_const(node)
|
121
|
-
# Sometimes modules/class are declared with the same name as an
|
122
|
-
# engine. For example, you might have:
|
123
|
-
#
|
124
|
-
# /engines/foo
|
125
|
-
# /app/graph/types/foo
|
126
|
-
#
|
127
|
-
# We ignore instead of yielding false positive for the module
|
128
|
-
# declaration in the latter.
|
129
162
|
return if in_module_or_class_declaration?(node)
|
130
|
-
#
|
163
|
+
# There might be value objects that are named
|
131
164
|
# the same as engines like:
|
132
165
|
#
|
133
166
|
# Warehouse.new
|
@@ -139,7 +172,7 @@ module RuboCop
|
|
139
172
|
return unless engine
|
140
173
|
return if valid_engine_access?(node, engine)
|
141
174
|
|
142
|
-
add_offense(node, message:
|
175
|
+
add_offense(node, message: message(node, engine))
|
143
176
|
end
|
144
177
|
|
145
178
|
def on_send(node)
|
@@ -151,7 +184,7 @@ module RuboCop
|
|
151
184
|
next if engine.nil?
|
152
185
|
next if valid_engine_access?(node, engine)
|
153
186
|
|
154
|
-
add_offense(class_name_node, message:
|
187
|
+
add_offense(class_name_node, message: message(node, engine))
|
155
188
|
end
|
156
189
|
end
|
157
190
|
|
@@ -161,6 +194,16 @@ module RuboCop
|
|
161
194
|
|
162
195
|
private
|
163
196
|
|
197
|
+
def message(_node, engine)
|
198
|
+
if strongly_protected_engine?(engine)
|
199
|
+
format(STRONGLY_PROTECTED_MSG, engine: engine)
|
200
|
+
elsif strongly_protected_engine?(current_engine)
|
201
|
+
format(STRONGLY_PROTECTED_CURRENT_MSG, engine: current_engine)
|
202
|
+
else
|
203
|
+
format(MSG, engine: engine)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
164
207
|
def extract_engine(node)
|
165
208
|
return nil unless protected_engines.include?(node.const_name)
|
166
209
|
|
@@ -192,27 +235,25 @@ module RuboCop
|
|
192
235
|
names.map { |n| ActiveSupport::Inflector.camelize(n) }
|
193
236
|
end
|
194
237
|
|
195
|
-
def in_module_or_class_declaration?(node)
|
196
|
-
depth = 0
|
197
|
-
max_depth = 10
|
198
|
-
while node.const_type? && depth < max_depth
|
199
|
-
node = node.parent
|
200
|
-
depth += 1
|
201
|
-
end
|
202
|
-
node.module_type? || node.class_type?
|
203
|
-
end
|
204
|
-
|
205
238
|
def sending_method_to_namespace_itself?(node)
|
206
239
|
node.parent.send_type?
|
207
240
|
end
|
208
241
|
|
209
242
|
def valid_engine_access?(node, engine)
|
243
|
+
return true if in_engine_file?(engine)
|
244
|
+
return true if engine_specific_override?(node)
|
245
|
+
|
246
|
+
return false if strongly_protected_engine?(current_engine)
|
247
|
+
return false if strongly_protected_engine?(engine)
|
248
|
+
|
249
|
+
valid_engine_api_access?(node, engine)
|
250
|
+
end
|
251
|
+
|
252
|
+
def valid_engine_api_access?(node, engine)
|
210
253
|
(
|
211
|
-
in_engine_file?(engine) ||
|
212
254
|
in_legacy_dependent_file?(engine) ||
|
213
255
|
through_api?(node) ||
|
214
|
-
whitelisted?(node, engine)
|
215
|
-
engine_specific_override?(node)
|
256
|
+
whitelisted?(node, engine)
|
216
257
|
)
|
217
258
|
end
|
218
259
|
|
@@ -302,19 +343,31 @@ module RuboCop
|
|
302
343
|
|
303
344
|
raw_overrides.each do |raw_override|
|
304
345
|
engine = ActiveSupport::Inflector.camelize(raw_override['Engine'])
|
305
|
-
overrides_by_engine[engine] = raw_override['
|
346
|
+
overrides_by_engine[engine] = raw_override['AllowedModules']
|
306
347
|
end
|
307
348
|
overrides_by_engine
|
308
349
|
end
|
309
350
|
|
310
351
|
def engine_specific_override?(node)
|
311
|
-
|
312
|
-
|
313
|
-
return false unless
|
352
|
+
module_name = node.parent.source
|
353
|
+
module_names_allowed_by_override = overrides_by_engine[current_engine]
|
354
|
+
return false unless module_names_allowed_by_override
|
355
|
+
|
356
|
+
module_names_allowed_by_override.include?(module_name)
|
357
|
+
end
|
358
|
+
|
359
|
+
def strongly_protected_engines
|
360
|
+
@strongly_protected_engines ||= begin
|
361
|
+
strongly_protected = cop_config['StronglyProtectedEngines'] || []
|
362
|
+
camelize_all(strongly_protected)
|
363
|
+
end
|
364
|
+
end
|
314
365
|
|
315
|
-
|
366
|
+
def strongly_protected_engine?(engine)
|
367
|
+
strongly_protected_engines.include?(engine)
|
316
368
|
end
|
317
369
|
end
|
318
370
|
end
|
319
371
|
end
|
320
372
|
end
|
373
|
+
# rubocop:enable Metrics/ClassLength
|
@@ -46,6 +46,8 @@ module RuboCop
|
|
46
46
|
# end
|
47
47
|
#
|
48
48
|
class GlobalModelAccessFromEngine < Cop
|
49
|
+
include EngineNodeContext
|
50
|
+
|
49
51
|
MSG = 'Direct access of global model `%<model>s` ' \
|
50
52
|
'from within Rails Engine.'
|
51
53
|
|
@@ -58,6 +60,7 @@ module RuboCop
|
|
58
60
|
return unless global_model_const?(node)
|
59
61
|
# The cop allows access to e.g. MyGlobalModel::MY_CONST.
|
60
62
|
return if child_of_const?(node)
|
63
|
+
return if in_module_or_class_declaration?(node)
|
61
64
|
|
62
65
|
add_offense(node, message: message(node.source))
|
63
66
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
# Helpers for determining the context of a node for engine violations.
|
6
|
+
module EngineNodeContext
|
7
|
+
# Sometimes modules/class are declared with the same name as an
|
8
|
+
# engine or global model. For example, you might have both:
|
9
|
+
#
|
10
|
+
# /engines/foo
|
11
|
+
# /app/graph/types/foo
|
12
|
+
#
|
13
|
+
# We ignore instead of yielding false positive for the module
|
14
|
+
# declaration in the latter.
|
15
|
+
def in_module_or_class_declaration?(node)
|
16
|
+
depth = 0
|
17
|
+
max_depth = 10
|
18
|
+
while node.const_type? && depth < max_depth
|
19
|
+
node = node.parent
|
20
|
+
depth += 1
|
21
|
+
end
|
22
|
+
node.module_type? || node.class_type?
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rubocop-flexport
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Flexport Engineering
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-01-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -56,6 +56,7 @@ files:
|
|
56
56
|
- lib/rubocop/cop/flexport/new_global_model.rb
|
57
57
|
- lib/rubocop/cop/flexport_cops.rb
|
58
58
|
- lib/rubocop/cop/mixin/engine_api.rb
|
59
|
+
- lib/rubocop/cop/mixin/engine_node_context.rb
|
59
60
|
- lib/rubocop/flexport.rb
|
60
61
|
- lib/rubocop/flexport/inject.rb
|
61
62
|
- lib/rubocop/flexport/version.rb
|