forked from rubocop/rubocop-rails
-
Notifications
You must be signed in to change notification settings - Fork 0
/
dangerous_column_names.rb
446 lines (435 loc) · 13 KB
/
dangerous_column_names.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
# frozen_string_literal: true
module RuboCop
module Cop
module Rails
# Avoid dangerous column names.
#
# Some column names are considered dangerous because they would overwrite methods already defined.
#
# @example
# # bad
# add_column :users, :save
#
# # good
# add_column :users, :saved
class DangerousColumnNames < Base # rubocop:disable Metrics/ClassLength
COLUMN_TYPE_METHOD_NAMES = %i[
bigint
binary
blob
boolean
date
datetime
decimal
float
integer
numeric
primary_key
string
text
time
].to_set.freeze
# Generated from `ActiveRecord::AttributeMethods.dangerous_attribute_methods` on activerecord 7.1.3.
# rubocop:disable Metrics/CollectionLiteralLength
DANGEROUS_COLUMN_NAMES = %w[
__callbacks
__id__
_assign_attribute
_assign_attributes
_before_commit_callbacks
_commit_callbacks
_committed_already_called
_create_callbacks
_create_record
_delete_row
_destroy
_destroy_callbacks
_ensure_no_duplicate_errors
_find_callbacks
_find_record
_has_attribute
_initialize_callbacks
_lock_value_for_database
_merge_attributes
_primary_key_constraints_hash
_raise_readonly_record_error
_raise_record_not_destroyed
_raise_record_not_touched_error
_read_attribute
_record_changed
_reflections
_rollback_callbacks
_run_before_commit_callbacks
_run_commit_callbacks
_run_create_callbacks
_run_destroy_callbacks
_run_find_callbacks
_run_initialize_callbacks
_run_rollback_callbacks
_run_save_callbacks
_run_touch_callbacks
_run_update_callbacks
_run_validate_callbacks
_run_validation_callbacks
_save_callbacks
_touch_callbacks
_touch_row
_trigger_destroy_callback
_trigger_update_callback
_update_callbacks
_update_record
_update_row
_validate_callbacks
_validation_callbacks
_validators
_write_attribute
[]
[]=
accessed_fields
add_to_transaction
aggregate_reflections
all_timestamp_attributes_in_model
allow_destroy
apply_scoping
around_save_collection_association
assign_attributes
assign_multiparameter_attributes
assign_nested_attributes_for_collection_association
assign_nested_attributes_for_one_to_one_association
assign_nested_parameter_attributes
assign_to_or_mark_for_destruction
associated_records_to_validate_or_save
association
association_cached
association_foreign_key_changed
association_instance_get
association_instance_set
association_valid
attachment_changes
attachment_reflections
attribute
attribute_aliases
attribute_before_last_save
attribute_before_type_cast
attribute_came_from_user
attribute_change
attribute_change_to_be_saved
attribute_changed
attribute_changed_in_place
attribute_for_database
attribute_for_inspect
attribute_in_database
attribute_method
attribute_method_matchers
attribute_missing
attribute_names
attribute_names_for_partial_inserts
attribute_names_for_partial_updates
attribute_names_for_serialization
attribute_present
attribute_previous_change
attribute_previously_changed
attribute_previously_was
attribute_was
attribute_will_change
attribute=
attributes
attributes_before_type_cast
attributes_for_create
attributes_for_database
attributes_for_update
attributes_in_database
attributes_with_values
attributes=
automatic_scope_inversing
becomes
before_committed
belongs_to_touch_method
broadcast_action
broadcast_action_later
broadcast_action_later_to
broadcast_action_to
broadcast_after_to
broadcast_append
broadcast_append_later
broadcast_append_later_to
broadcast_append_to
broadcast_before_to
broadcast_prepend
broadcast_prepend_later
broadcast_prepend_later_to
broadcast_prepend_to
broadcast_remove
broadcast_remove_to
broadcast_render
broadcast_render_later
broadcast_render_later_to
broadcast_render_to
broadcast_rendering_with_defaults
broadcast_replace
broadcast_replace_later
broadcast_replace_later_to
broadcast_replace_to
broadcast_target_default
broadcast_update
broadcast_update_later
broadcast_update_later_to
broadcast_update_to
build_decrypt_attribute_assignments
build_encrypt_attribute_assignments
cache_key
cache_key_with_version
cache_timestamp_format
cache_version
cache_versioning
call_reject_if
can_use_fast_cache_version
cant_modify_encrypted_attributes_when_frozen
changed
changed_attribute_names_to_save
changed_attributes
changed_for_autosave
changes
changes_applied
changes_to_save
check_record_limit
ciphertext_for
class
clear_attribute_change
clear_attribute_changes
clear_changes_information
clear_timestamp_attributes
clear_transaction_record_state
clone
collection_cache_versioning
column_for_attribute
committed
connection_handler
create_or_update
current_time_from_proper_timezone
custom_inspect_method_defined
custom_validation_context
decrement
decrypt
decrypt_attributes
decrypt_rich_texts
default_connection_handler
default_role
default_scope_override
default_scopes
default_shard
default_validation_context
defined_enums
delete
destroy
destroy_association_async_job
destroy_associations
destroy_row
destroyed
destroyed_by_association
destroyed_by_association=
dup
each_counter_cached_associations
encode_with
encrypt
encrypt_attributes
encrypt_rich_texts
encryptable_rich_texts
encrypted_attribute
encrypted_attributes
encrypted_attributes=
ensure_proper_type
errors
execute_callstack_for_multiparameter_attributes
extract_callstack_for_multiparameter_attributes
find_parameter_position
forget_attribute_assignments
format_for_inspect
freeze
from_json
frozen?
halted_callback_hook
has_attribute
has_changes_to_save
has_defer_touch_attrs
has_destroy_flag
has_encrypted_attributes
has_encrypted_rich_texts
has_transactional_callbacks
hash
id
id_before_type_cast
id_for_database
id_in_database
id_was
id=
include_root_in_json
increment
init_internals
init_with
init_with_attributes
initialize_internals_callback
inspection_filter
invalid
lock
lock_optimistically
locking_enabled
logger
mark_for_destruction
marked_for_destruction
matched_attribute_method
max_updated_column_timestamp
missing_attribute
model_name
mutations_before_last_save
mutations_from_database
nested_attributes_options
nested_records_changed_for_autosave
new_record
no_touching
normalize_reflection_attribute
partial_inserts
partial_updates
perform_validations
persisted
pk_attribute
pluralize_table_names
populate_with_current_scope_attributes
previous_changes
previously_new_record
previously_persisted
primary_key_prefix_type
query_attribute
raise_nested_attributes_record_not_found
raise_validation_error
raw_timestamp_to_cache_version
read_attribute
read_attribute_before_type_cast
read_attribute_for_serialization
read_attribute_for_validation
read_store_attribute
readonly
record_timestamps
record_timestamps=
reject_new_record
reload
remember_transaction_record_state
respond_to_without_attributes
restore_attribute
restore_attributes
restore_transaction_record_state
rolledback
run_callbacks
run_validations
sanitize_for_mass_assignment
sanitize_forbidden_attributes
save
save_belongs_to_association
save_collection_association
save_has_one_association
saved_change_to_attribute
saved_changes
serializable_add_includes
serializable_attributes
serializable_hash
should_record_timestamps
signed_id
signed_id_verifier_secret
skip_time_zone_conversion_for_attributes
slice
store_accessor_for
store_full_class_name
store_full_sti_class
strict_loaded_associations
strict_loading
strict_loading_mode
strict_loading_n_plus_one_only
surreptitiously_touch
table_name_prefix
table_name_suffix
time_zone_aware_attributes
time_zone_aware_types
timestamp_attributes_for_create_in_model
timestamp_attributes_for_update_in_model
to_ary
to_gid
to_gid_param
to_global_id
to_key
to_model
to_partial_path
to_sgid
to_sgid_param
to_signed_global_id
toggle
touch
touch_deferred_attributes
touch_later
transaction
transaction_include_any_action
trigger_transactional_callbacks
type_cast_attribute_value
type_for_attribute
update
update_attribute
update_column
update_columns
valid
validate
validate_collection_association
validate_encryption_allowed
validate_single_association
validates_absence_of
validates_acceptance_of
validates_comparison_of
validates_confirmation_of
validates_exclusion_of
validates_format_of
validates_inclusion_of
validates_length_of
validates_numericality_of
validates_presence_of
validates_size_of
validates_with
validation_context
validation_context=
values_at
verify_readonly_attribute
will_be_destroyed
will_save_change_to_attribute
with_lock
with_transaction_returning_status
write_attribute
write_store_attribute
].freeze
# rubocop:enable Metrics/CollectionLiteralLength
MSG = 'Avoid dangerous column names.'
RESTRICT_ON_SEND = [:add_column, :rename, :rename_column, *COLUMN_TYPE_METHOD_NAMES].freeze
def on_send(node)
column_name_node = column_name_node_from(node)
return false unless column_name_node
return false unless dangerous_column_name_node?(column_name_node)
add_offense(column_name_node)
end
private
def column_name_node_from(node)
case node.method_name
when :add_column, :rename
node.arguments[1]
when :rename_column
node.arguments[2]
when *COLUMN_TYPE_METHOD_NAMES
node.first_argument
end
end
def dangerous_column_name_node?(node)
return false unless node.respond_to?(:value)
dangerous_column_name?(node.value.to_s)
end
def dangerous_column_name?(column_name)
DANGEROUS_COLUMN_NAMES.include?(column_name)
end
end
end
end
end