CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/lib/rubocop/cop/lint/module_enforce_notes.rb
Views: 1904
1
# frozen_string_literal: true
2
3
module RuboCop
4
module Cop
5
module Lint
6
class ModuleEnforceNotes < Base
7
8
NO_NOTES_MSG = 'Module is missing the Notes section which must include Stability, Reliability and SideEffects] - https://docs.metasploit.com/docs/development/developing-modules/module-metadata/definition-of-module-reliability-side-effects-and-stability.html'
9
MISSING_KEY_MSG = 'Module is missing %s from the Notes section - https://docs.metasploit.com/docs/development/developing-modules/module-metadata/definition-of-module-reliability-side-effects-and-stability.html'
10
REQUIRED_KEYS = %w[Stability Reliability SideEffects]
11
12
def_node_matcher :find_update_info_node, <<~PATTERN
13
(def :initialize _args (begin (super $(send nil? {:update_info :merge_info} (lvar :info) (hash ...))) ...))
14
PATTERN
15
16
def_node_matcher :find_nested_update_info_node, <<~PATTERN
17
(def :initialize _args (super $(send nil? {:update_info :merge_info} (lvar :info) (hash ...)) ...))
18
PATTERN
19
20
def on_def(node)
21
update_info_node = find_update_info_node(node) || find_nested_update_info_node(node)
22
return if update_info_node.nil?
23
24
hash = update_info_node.arguments.find { |argument| hash_arg?(argument) }
25
notes_present = false
26
last_key = nil
27
notes = nil
28
hash.each_pair do |key, value|
29
if key.value == 'Notes'
30
notes_present = true
31
notes = value
32
end
33
last_key = key
34
end
35
36
if notes_present
37
check_for_required_keys(notes)
38
else
39
add_offense(last_key || hash, message: NO_NOTES_MSG)
40
end
41
end
42
43
private
44
45
def check_for_required_keys(notes)
46
last_key = nil
47
keys_present = []
48
notes.each_pair do |key, _value|
49
if REQUIRED_KEYS.include? key.value
50
keys_present << key.value
51
end
52
last_key = key
53
end
54
55
missing_keys = REQUIRED_KEYS - keys_present
56
unless missing_keys.empty?
57
if missing_keys.length == 1
58
msg = missing_keys[0]
59
else
60
msg = missing_keys[0...-1].join(', ') + ' and ' + missing_keys[-1]
61
end
62
add_offense(last_key || notes, message: MISSING_KEY_MSG % msg)
63
end
64
end
65
66
def hash_arg?(node)
67
node.type == :hash
68
end
69
end
70
end
71
end
72
end
73
74