nasl-pedant 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. data/Rakefile +38 -0
  2. data/bin/pedant +1 -1
  3. data/lib/pedant.rb +3 -1
  4. data/lib/pedant/check.rb +20 -12
  5. data/lib/pedant/checks/conditional_or_loop_is_empty.rb +1 -1
  6. data/lib/pedant/checks/contains_ip_address_literals.rb +1 -1
  7. data/lib/pedant/checks/contains_no_carriage_returns.rb +1 -1
  8. data/lib/pedant/checks/contains_no_tabs.rb +1 -1
  9. data/lib/pedant/checks/contains_registration_section.rb +10 -4
  10. data/lib/pedant/checks/contains_unreachable_code.rb +2 -2
  11. data/lib/pedant/checks/ends_with_newline.rb +1 -1
  12. data/lib/pedant/checks/{files_parse_without_error.rb → files_parse_without_errors.rb} +1 -1
  13. data/lib/pedant/checks/local_variable_unused.rb +51 -0
  14. data/lib/pedant/checks/parse_test_code.rb +1 -1
  15. data/lib/pedant/checks/plugin_type_not_specified.rb +4 -3
  16. data/lib/pedant/checks/script_category.rb +111 -0
  17. data/lib/pedant/checks/script_family_not_specified.rb +53 -16
  18. data/lib/pedant/checks/script_id.rb +115 -0
  19. data/lib/pedant/checks/script_name.rb +133 -0
  20. data/lib/pedant/checks/script_summary.rb +142 -0
  21. data/lib/pedant/cli.rb +41 -31
  22. data/lib/pedant/command.rb +16 -29
  23. data/lib/pedant/commands/check.rb +105 -6
  24. data/lib/pedant/commands/test.rb +24 -2
  25. data/lib/pedant/knowledge_base.rb +1 -1
  26. data/lib/pedant/test.rb +5 -5
  27. data/lib/pedant/version.rb +1 -1
  28. data/pedant.gemspec +33 -6
  29. data/test/test_helper.rb +26 -0
  30. data/test/unit/checks/test_conditional_or_loop_is_empty.rb +1 -1
  31. data/test/unit/checks/test_contains_ip_address_literals.rb +1 -1
  32. data/test/unit/checks/test_contains_no_carriage_returns.rb +1 -1
  33. data/test/unit/checks/test_contains_no_tabs.rb +1 -1
  34. data/test/unit/checks/test_contains_registration_section.rb +17 -1
  35. data/test/unit/checks/test_contains_unreachable_code.rb +11 -1
  36. data/test/unit/checks/test_ends_with_newline.rb +1 -1
  37. data/test/unit/checks/test_plugin_type_not_specified.rb +9 -1
  38. data/test/unit/checks/test_script_family_not_specified.rb +54 -13
  39. metadata +30 -20
@@ -0,0 +1,115 @@
1
+ ################################################################################
2
+ # Copyright (c) 2012, Mak Kolybabi
3
+ # All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # 1. Redistributions of source code must retain the above copyright notice, this
9
+ # list of conditions and the following disclaimer.
10
+ #
11
+ # 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ # this list of conditions and the following disclaimer in the documentation
13
+ # and/or other materials provided with the distribution.
14
+ #
15
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19
+ # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22
+ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23
+ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
+ ################################################################################
26
+
27
+ module Pedant
28
+ class CheckScriptId < Check
29
+ def self.requires
30
+ super + [:main, :trees]
31
+ end
32
+
33
+ def run
34
+ # This check only applies to plugins.
35
+ return skip unless @kb[:main].extname == '.nasl'
36
+
37
+ si_nodes = []
38
+ tree = @kb[:trees][@kb[:main]]
39
+
40
+ tree.all(:Call).each do |node|
41
+ next unless node.name.ident.name == 'script_id'
42
+ next unless node.name.indexes == []
43
+ si_nodes << node
44
+ end
45
+
46
+ if si_nodes.length == 0
47
+ report(:error, "Plugin does not call script_id() in the description.")
48
+ return fail
49
+ elsif si_nodes.length > 1
50
+ report(:error, "Plugin specifies multiple script IDs:")
51
+ si_nodes.each { |call| report(:error, call.context()) }
52
+ return fail
53
+ end
54
+
55
+ si_node = si_nodes.first
56
+
57
+ if si_node.args.empty?
58
+ report(:error, "script_id() was called with no arguments:\n#{si_node.context()}")
59
+ return fail
60
+ end
61
+
62
+ if si_node.args.length > 1
63
+ report(:error, "script_id() was called with too many arguments:\n#{si_node.context()}")
64
+ return fail
65
+ end
66
+
67
+ # Pull out argument
68
+ type = si_node.args.first.type
69
+ arg = si_node.args.first.expr
70
+
71
+ if type != :anonymous
72
+ report(
73
+ :error,
74
+ "script_id() was called using a named parameter. It requires using one positional parameter.\n" +
75
+ arg.context(si_node)
76
+ )
77
+ return fail
78
+ end
79
+
80
+ unless arg.is_a? Nasl::Integer
81
+ report(
82
+ :error,
83
+ "script_id() was called with the wrong type of argument.\n" +
84
+ "An integer literal between 10001 and 999999 inclusive is required:\n" +
85
+ arg.context(si_node)
86
+ )
87
+ return fail
88
+ end
89
+
90
+ # Ensure that the script id is valid.
91
+ if arg.value < 10001 or arg.value > 999999
92
+ report(
93
+ :error,
94
+ "script_id() was called with an invalid argument.\n" +
95
+ "An integer literal between 10001 and 999999 inclusive is required:\n" +
96
+ arg.context(si_node)
97
+ )
98
+ return fail
99
+ end
100
+
101
+ # Ensure that the script id is valid.
102
+ if arg.value >= 900001 and arg.value <= 999999
103
+ report(
104
+ :warn,
105
+ "Uses a script id reserved for custom plugins / plugins in development.\n" +
106
+ arg.context(si_node)
107
+ )
108
+ return warn
109
+ end
110
+
111
+ report(:info, "Plugin has script id #{arg.value}:\n#{arg.context(si_node)}")
112
+ pass
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,133 @@
1
+ ################################################################################
2
+ # Copyright (c) 2012, Mak Kolybabi
3
+ # All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # 1. Redistributions of source code must retain the above copyright notice, this
9
+ # list of conditions and the following disclaimer.
10
+ #
11
+ # 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ # this list of conditions and the following disclaimer in the documentation
13
+ # and/or other materials provided with the distribution.
14
+ #
15
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19
+ # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22
+ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23
+ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
+ ################################################################################
26
+
27
+ module Pedant
28
+ class CheckScriptName < Check
29
+ def self.requires
30
+ super + [:main, :trees]
31
+ end
32
+
33
+ def run
34
+ # This check only applies to plugins.
35
+ return skip unless @kb[:main].extname == '.nasl'
36
+
37
+ sn_nodes = []
38
+ tree = @kb[:trees][@kb[:main]]
39
+
40
+ tree.all(:Call).each do |node|
41
+ next unless node.name.ident.name == 'script_name'
42
+ next unless node.name.indexes == []
43
+ sn_nodes << node
44
+ end
45
+
46
+ if sn_nodes.length == 0
47
+ report(:error, "Plugin does not call script_name() in the description.")
48
+ return fail
49
+ elsif sn_nodes.length > 1
50
+ report(:error, "Plugin calls script_name() multiple times:")
51
+ sn_nodes.each { |call| report(:error, call.context()) }
52
+ return fail
53
+ end
54
+
55
+ sn_node = sn_nodes.first
56
+
57
+ if sn_node.args.empty?
58
+ report(:error, "script_name() was called with no arguments:\n#{sn_node.context()}")
59
+ return fail
60
+ end
61
+
62
+ if sn_node.args.length > 1
63
+ report(:error, "script_name() was called with too many arguments:\n#{sn_node.context()}")
64
+ return fail
65
+ end
66
+
67
+ # Pull out argument
68
+ type = sn_node.args.first.type
69
+ param = sn_node.args.first.name
70
+ arg = sn_node.args.first.expr
71
+
72
+ if type == :anonymous
73
+ report(
74
+ :error,
75
+ "script_name() was called using a positional parameter.\n" +
76
+ "It requires using an argument to the 'english' named parameter.\n" +
77
+ arg.context(sn_node)
78
+ )
79
+ return fail
80
+ end
81
+
82
+ if param.name != "english"
83
+ report(
84
+ :error,
85
+ "script_name() was called using an invalid named parameter.\n" +
86
+ "The 'english' named parameter must be used.\n" +
87
+ param.context(sn_node)
88
+ )
89
+ return fail
90
+ end
91
+
92
+ unless arg.is_a? Nasl::String
93
+ report(
94
+ :error,
95
+ "script_name() was called with the wrong type of argument. A string is required.\n" +
96
+ arg.context(sn_node)
97
+ )
98
+ return fail
99
+ end
100
+
101
+ if arg.text.length == 0
102
+ report(
103
+ :error,
104
+ "script_name() was called with an empty string.\n" +
105
+ arg.context(sn_node)
106
+ )
107
+ return fail
108
+ end
109
+
110
+ if arg.text.slice(0) == " " && arg.text.slice(-1) == " "
111
+ ws_error = "Script name has leading and trailing whitespace:\n"
112
+ elsif arg.text.slice(0) == " "
113
+ ws_error = "Script name has leading whitespace:\n"
114
+ elsif arg.text.slice(-1) == " "
115
+ ws_error = "Script name has trailing whitespace:\n"
116
+ else
117
+ ws_error = nil
118
+ end
119
+
120
+ unless ws_error.nil?
121
+ report(
122
+ :error,
123
+ ws_error +
124
+ arg.context(sn_node)
125
+ )
126
+ return fail
127
+ end
128
+
129
+ report(:info, "Plugin has a script name of '#{arg.text}':\n#{arg.context(sn_node)}")
130
+ pass
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,142 @@
1
+ ################################################################################
2
+ # Copyright (c) 2012, Mak Kolybabi
3
+ # All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # 1. Redistributions of source code must retain the above copyright notice, this
9
+ # list of conditions and the following disclaimer.
10
+ #
11
+ # 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ # this list of conditions and the following disclaimer in the documentation
13
+ # and/or other materials provided with the distribution.
14
+ #
15
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19
+ # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22
+ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23
+ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
+ ################################################################################
26
+
27
+ module Pedant
28
+ class CheckScriptSummary < Check
29
+ def self.requires
30
+ super + [:main, :trees]
31
+ end
32
+
33
+ def run
34
+ # This check only applies to plugins.
35
+ return skip unless @kb[:main].extname == '.nasl'
36
+
37
+ ss_nodes = []
38
+ tree = @kb[:trees][@kb[:main]]
39
+
40
+ tree.all(:Call).each do |node|
41
+ next unless node.name.ident.name == 'script_summary'
42
+ next unless node.name.indexes == []
43
+ ss_nodes << node
44
+ end
45
+
46
+ if ss_nodes.length == 0
47
+ report(:error, "Plugin does not call script_summary() in the description.")
48
+ return fail
49
+ elsif ss_nodes.length > 1
50
+ report(:error, "Plugin calls script_summary() multiple times:")
51
+ ss_nodes.each { |call| report(:error, call.context()) }
52
+ return fail
53
+ end
54
+
55
+ ss_node = ss_nodes.first
56
+
57
+ if ss_node.args.empty?
58
+ report(:error, "script_summary() was called with no arguments:\n#{ss_node.context()}")
59
+ return fail
60
+ end
61
+
62
+ if ss_node.args.length > 1
63
+ report(:error, "script_summary() was called with too many arguments:\n#{ss_node.context()}")
64
+ return fail
65
+ end
66
+
67
+ # Pull out argument
68
+ type = ss_node.args.first.type
69
+ param = ss_node.args.first.name
70
+ arg = ss_node.args.first.expr
71
+
72
+ if type == :anonymous
73
+ report(
74
+ :error,
75
+ "script_summary() was called using a positional parameter.\n" +
76
+ "It requires using an argument to the 'english' named parameter.\n" +
77
+ arg.context(ss_node)
78
+ )
79
+ return fail
80
+ end
81
+
82
+ if param.name != "english"
83
+ report(
84
+ :error,
85
+ "script_summary() was called using an invalid named parameter.\n" +
86
+ "The 'english' named parameter must be used.\n" +
87
+ param.context(ss_node)
88
+ )
89
+ return fail
90
+ end
91
+
92
+ unless arg.is_a? Nasl::String
93
+ report(
94
+ :error,
95
+ "script_summary() was called with the wrong type of argument. A string is required.\n" +
96
+ arg.context(ss_node)
97
+ )
98
+ return fail
99
+ end
100
+
101
+ if arg.text.length == 0
102
+ report(
103
+ :error,
104
+ "script_summary() was called with an empty string.\n" +
105
+ arg.context(ss_node)
106
+ )
107
+ return fail
108
+ end
109
+
110
+ if arg.text.slice(0) == " " && arg.text.slice(-1) == " "
111
+ ws_error = "Script summary has leading and trailing whitespace:\n"
112
+ elsif arg.text.slice(0) == " "
113
+ ws_error = "Script summary has leading whitespace:\n"
114
+ elsif arg.text.slice(-1) == " "
115
+ ws_error = "Script summary has trailing whitespace:\n"
116
+ else
117
+ ws_error = nil
118
+ end
119
+
120
+ unless ws_error.nil?
121
+ report(
122
+ :error,
123
+ ws_error +
124
+ arg.context(ss_node)
125
+ )
126
+ return fail
127
+ end
128
+
129
+ if arg.text.include? "\n"
130
+ report(
131
+ :error,
132
+ "Script summary includes newline characters:\n" +
133
+ arg.context(ss_node)
134
+ )
135
+ return fail
136
+ end
137
+
138
+ report(:info, "Plugin has a script summary of '#{arg.text}':\n#{arg.context(ss_node)}")
139
+ pass
140
+ end
141
+ end
142
+ end
data/lib/pedant/cli.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  ################################################################################
2
- # Copyright (c) 2011, Mak Kolybabi
2
+ # Copyright (c) 2011-2014, Tenable Network Security
3
3
  # All rights reserved.
4
4
  #
5
5
  # Redistribution and use in source and binary forms, with or without
@@ -28,53 +28,63 @@ require 'optparse'
28
28
 
29
29
  module Pedant
30
30
  class Cli
31
+ @@optparse = nil
32
+
31
33
  def self.run
32
- cfg = {}
34
+ options = {
35
+ input_mode: :filesystem,
36
+ output_mode: :terminal,
37
+ verbosity: 0
38
+ }
33
39
 
34
40
  Command.initialize!
35
41
 
36
- optparse = OptionParser.new do |opts|
37
- opts.banner = "Usage: pedant [options] [command [args]]"
42
+ @@optparse = OptionParser.new do |opts|
43
+ opts.banner = "Usage: pedant [global-options] [command [command-options] [args]]"
44
+
45
+ opts.separator ""
46
+ opts.separator "Global settings:"
38
47
 
39
- cfg[:verbose] = 0
40
- opts.on('-v', '--verbose', 'Output more information') do
41
- cfg[:verbose] += 1
48
+ opts.on('-v', '--verbose', 'Output more information, use multiple time to increase verbosity.') do
49
+ options[:verbosity] += 1
42
50
  end
43
- end
44
51
 
45
- optparse.parse!
52
+ opts.separator ""
53
+ opts.separator "Common operations:"
46
54
 
47
- # Sanity check the command line arguments.
48
- if ARGV.empty?
49
- puts "No command was specified."
50
- puts
51
- usage
52
- exit 1
55
+ opts.on('-h', '--help', 'Display this help screen.') do
56
+ puts opts
57
+ exit 1
58
+ end
59
+
60
+ opts.on('-l', '--list', 'Display the list of available commands.') do
61
+ puts Command.list
62
+ exit 1
63
+ end
64
+
65
+ opts.on('-V', '--version', 'Display the version of Pedant.') do
66
+ puts "#{Pedant::VERSION}"
67
+ exit
68
+ end
53
69
  end
54
70
 
71
+ @@optparse.order!
72
+
73
+ # Sanity check the command.
74
+ usage("No command was specified.") if ARGV.empty?
55
75
  cmd = ARGV.shift
56
76
  cls = Command.find(cmd)
57
- if cls.nil? then
58
- puts "Command '#{cmd}' not supported."
59
- puts
60
- usage
61
- exit 1
62
- end
77
+ usage("Command '#{cmd}' not supported.") if cls.nil?
63
78
 
64
79
  # Run the command.
65
- cls.run(cfg, ARGV)
80
+ cls.run(options, ARGV)
66
81
  end
67
82
 
68
- def self.usage
69
- puts "pedant [flags] [command] [filename ...]"
70
- puts
71
- puts "Flags:"
72
- puts " -v Display more verbose (warning) messages. "
73
- puts " -vv Display more verbose (informational) messages. "
83
+ def self.usage(msg)
84
+ puts Rainbow(msg).color(:red)
74
85
  puts
75
- puts "Commands:"
76
- puts " check Runs all included checks against the specified plugin(s)."
77
- puts " test Runs the specified unit tests, all are selected by default."
86
+ puts @@optparse
87
+ exit 1
78
88
  end
79
89
  end
80
90
  end