banalize 0.0.1

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.
@@ -0,0 +1,101 @@
1
+ module Banalize
2
+
3
+ ##
4
+ # Run policy check and return result of it.
5
+ #
6
+ # @param [String] bash Bash file for analisys
7
+ #
8
+ # @param [String, Hash] search Name of a policy to check against or
9
+ # hash having :severity and/or :policy keys
10
+ #
11
+ # @see Policy.search
12
+ #
13
+ # @return [Array of Hashes] each element of array is { :name => result }
14
+ #
15
+ def self.run bash, search
16
+
17
+ run_list = Policy.search search
18
+
19
+ if run_list.empty?
20
+ raise Banalize::Runner::Error, "No policy satisfying criteria: #{search.inspect}"
21
+ end
22
+
23
+ res = { }
24
+ run_list.each do |policy|
25
+ res[policy[:policy]] = Banalize::Runner.new(bash, policy).result
26
+ end
27
+ res
28
+ end
29
+
30
+ ##
31
+ # Executing policy checks against bash file(s). Class instance is
32
+ # single bach file to check and single policy. Result of the check
33
+ # is returned in `@result` instance variable (and attr_accessor).
34
+ #
35
+ # Instance attributes
36
+ # ----------------------
37
+ # - `@bash` - PATH to bash file
38
+ #
39
+ # - `@policy` - [Hash] Policy configuration hash, key :klass contains
40
+ # name of the class for Ruby policy. If Hash does not have
41
+ # :klass key, it's not a Ruby, execute it as shell policy.
42
+ #
43
+ # - `@result` - Currenty returns only Boolean (true - check OK/false
44
+ # check fail). This can change later.
45
+ class Runner
46
+
47
+ ##
48
+ # Create new instance of policy check runner and execute
49
+ # it. Result of the check is returned in @result attribute.
50
+ #
51
+ # @param [String] bash
52
+ # @param [Hash] policy Policy configuration hash.
53
+ #
54
+ # @see Runner
55
+ #
56
+ def initialize bash,policy
57
+ @bash, @policy, @result = bash, policy, nil
58
+
59
+ if @policy.has_key? :klass
60
+ ruby
61
+ else
62
+ shell
63
+ end
64
+ end
65
+
66
+ attr_accessor :policy, :bash, :result
67
+
68
+ ##
69
+ # Execute ruby check
70
+ #
71
+ def ruby
72
+ object = policy[:klass].constantize.new(bash)
73
+ res = object.run
74
+ @result = {
75
+ :status => res ? true : false,
76
+ :messages => Errors.to_s(object.errors.messages)
77
+ }
78
+ end
79
+
80
+ ##
81
+ # Execute shell check
82
+ #
83
+ def shell
84
+ err = %x{ #{policy[:path]} #{bash} }
85
+ @result = {
86
+ :status => ($?.exitstatus == 0),
87
+ :messages => err
88
+ }
89
+ end
90
+
91
+ # systemu is very slow
92
+ # def shell_
93
+ # stat, out, err = systemu "#{policy[:path]} #{bash} "
94
+ # @result = {
95
+ # :status => ($?.exitstatus == 0),
96
+ # :messages => err
97
+ # }
98
+ # end
99
+
100
+ end
101
+ end
@@ -0,0 +1,58 @@
1
+ desc 'Give a description of terms used here'
2
+ arg_name 'Describe arguments to analyze here'
3
+ command [:describe,:desc] do |c|
4
+
5
+
6
+ c.desc 'Print help for the specified policy'
7
+ c.command [:policy, :pol, :p] do |p|
8
+ p.desc 'Policy name'
9
+ p.arg_name 'policy_name'
10
+
11
+ p.action do |global_options, options, args|
12
+ raise "Need a policy name to see description" if args.empty?
13
+ p = args.first.to_sym
14
+ print "\n#{p}: #{Banalize::Policy.synopsis(p)}\n\n"
15
+ print Banalize::Policy.description(p) + "\n\n"
16
+ end
17
+
18
+ end
19
+
20
+
21
+ ##
22
+ # Policies
23
+ #
24
+ c.desc 'List and describe available policy groups'
25
+ c.command [:styles, :style] do |p|
26
+ p.action do
27
+ puts <<-EOP
28
+ Theme Description
29
+ ----- -----------
30
+ core All policies
31
+ bugs Policies that that prevent or reveal bugs
32
+ maintenance Policies that affect the long-term health of the code
33
+ cosmetic Policies that only have a superficial effect
34
+ complexity Policies that specifically relate to code complexity
35
+ security Policies that relate to security issues
36
+ tests Policies that are specific to test programs
37
+
38
+ EOP
39
+ end
40
+ end
41
+
42
+
43
+
44
+ ##
45
+ # Severity
46
+ #
47
+ c.desc 'Print out names of severity levels and their numeric value'
48
+ c.command [:severity, :sev] do |a|
49
+ a.action do
50
+ puts "Name Value"
51
+ puts "------ ------"
52
+ print Banalize::Policy::Severity.to_s
53
+
54
+ puts "\n\nDefault severity: " << Banalize::Policy::Severity.default.to_s
55
+ end
56
+ end
57
+
58
+ end
@@ -0,0 +1,39 @@
1
+ desc 'Banalize file(s) from single or multiple directories. Can use wildcards and mix files/directories.'
2
+
3
+ arg_name 'dir', :multiple
4
+ command [:directory, :dir] do |c|
5
+
6
+ c.desc "Show all results, by default only failures shown (only for long format)"
7
+ c.switch [:a,:all]
8
+
9
+ c.desc "Short dotted output format"
10
+ c.switch [:s, :short, :dots]
11
+
12
+ c.desc "Recursive scan directories for files"
13
+ c.switch [:recursive, :recur, :r]
14
+
15
+ c.switch [:allow_files, :f], :desc => "Allow use of file paths together with directory paths"
16
+
17
+ c.desc "Wildcard for file lists"
18
+ c.default_value "*"
19
+ c.flag [:wildcard, :w]
20
+
21
+ c.desc "With 'no-' do not show errors, only name of failed check"
22
+ c.default_value true
23
+ c.switch [:errors, :err, :e]
24
+
25
+ c.action do |global, options, args|
26
+ files = []
27
+ args.each { |dir|
28
+ dir = File.expand_path dir
29
+ if options[:allow_files] && File.file?(dir)
30
+ files << dir
31
+ else
32
+ files += Dir.glob("#{dir}/#{ options[:r] ? '**/' : ''}#{options[:wildcard]}").select { |x| File.file? x}
33
+ end
34
+ }
35
+ files.each { |file| $res[file] = Banalize.run(file, $search) }
36
+ end
37
+ end
38
+
39
+
@@ -0,0 +1,22 @@
1
+ desc 'Run banalize on a single file or multiple files'
2
+
3
+ arg_name 'filename', :multiple
4
+ command [:file, :fl] do |c|
5
+
6
+ c.desc "Show all results, by default only failures shown (only for long format)"
7
+ c.switch [:a,:all]
8
+
9
+ c.desc "Short dotted output format"
10
+ c.switch [:s, :short, :dots]
11
+
12
+ c.desc "With 'no-' do not show errors, only name of failed check"
13
+ c.default_value true
14
+ c.switch [:errors, :err, :e]
15
+
16
+
17
+ c.action do |global, options, args|
18
+ args.each { |file| $res[file] = Banalize.run(file, $search) }
19
+ end
20
+ end
21
+
22
+
@@ -0,0 +1,25 @@
1
+ desc 'List available policies'
2
+
3
+ command [:list, :ls] do |c|
4
+
5
+ c.desc 'Only names of policies without description'
6
+ c.switch [:short, :s]
7
+ c.default_value true
8
+
9
+ c.action do |global, options, args|
10
+
11
+
12
+ printf "\n%40s %s\n\n", "Policy name".color(:bold), "Synopsis, style, severity".color(:bold)
13
+
14
+ $policies.each do |x|
15
+ if options[:short]
16
+ printf "%40s : %s, %s\n", x[:policy].to_s.color(:yellow), x[:style], x[:severity]
17
+ else
18
+ printf "%40s : %s [%s, %s]\n", x[:policy].to_s.color(:yellow), x[:synopsis], x[:style], x[:severity]
19
+ end
20
+ end
21
+ require 'pp'
22
+ # pp $policies
23
+ # pp Banalize::Files.policies
24
+ end
25
+ end
@@ -0,0 +1,15 @@
1
+ ##
2
+ # Extend class String with color codes
3
+ class String
4
+ def color type
5
+ return self unless $color
6
+ color_code = case type
7
+ when :bold then 1
8
+ when :white, :file then 37
9
+ when :error, :red then 31
10
+ when :green then 32
11
+ when :policy, :yellow then 33
12
+ end
13
+ "\e[#{color_code}m#{self}\e[0m"
14
+ end
15
+ end
@@ -0,0 +1,43 @@
1
+ module Banalize
2
+ ##
3
+ # Make ouput text indented and apply colors to it if this is required
4
+ #
5
+ # @param [Hash] hash check result hash
6
+ # @param [String] indent Default indent 4 spaces for each level
7
+ #
8
+ def self.beautify hash, indent=' '
9
+ out = ''
10
+ l1 = "\n"+indent
11
+ l2 = "\n" << indent*2
12
+ l3 = "\n" << indent*2 << "## "
13
+
14
+ hash.each do |file,results|
15
+ out << "\n\n#{file.color(:file)}"
16
+
17
+ results.each do |f_or_s, checks|
18
+
19
+
20
+ out << l1 << f_or_s << l1 << '-'*10
21
+
22
+ checks.each do |policy, string|
23
+ out << l1 << policy.to_s.color(f_or_s == 'Fail' ? :red : :yellow)
24
+ if string
25
+ lines = case string
26
+ when String
27
+ string.split("\n")
28
+ when Array
29
+ string
30
+ end
31
+ lines.each do |line|
32
+ line.gsub!(/(line \d+:)(.*)/, '\1' +"#{l3} "+ '\2' )
33
+ out << l3 << line
34
+ end
35
+
36
+ end
37
+ end
38
+ end
39
+
40
+ end
41
+ out
42
+ end
43
+ end
@@ -0,0 +1,34 @@
1
+ banalizer File.basename(__FILE__, '.rb').to_sym do
2
+
3
+ synopsis 'All lines must be indented consistenly'
4
+ severity :harsh
5
+ style :cosmetic
6
+
7
+ description <<EOF
8
+
9
+ When indenting the code all leading line indents should use the same
10
+ character: either all spaces or all tabs, but not mixed.
11
+
12
+ EOF
13
+
14
+
15
+ def run
16
+ ret = true
17
+
18
+ has_tabs = code.has?(/^\s*\t/)
19
+ tab_lines = code.lines
20
+
21
+ has_spcs = code.has?(/^\s* /)
22
+ spc_lines = code.lines
23
+
24
+ if has_tabs && has_spcs
25
+ errors.add "Code indented inconsistently: TABS and SPACES mixed"
26
+ errors.add " TAB indented: #{tab_lines}"
27
+ errors.add " SPC indented: #{spc_lines}"
28
+
29
+ end
30
+
31
+ return errors.empty?
32
+ end
33
+
34
+ end
@@ -0,0 +1,53 @@
1
+ banalizer :explicitly_define_path_variable do
2
+
3
+ style :security
4
+ severity :gentle
5
+
6
+ description <<-EOF
7
+
8
+ PATH varaible should be defined explicitly in the script. It should *only* list absolute path names and does not have $PATH variable.
9
+
10
+ Quote from http://hub.opensolaris.org/bin/view/Community+Group+on/shellstyle#HPathnames
11
+
12
+ It is always a good idea to be careful about $PATH settings and
13
+ pathnames when writing shell scripts. This allows them to function
14
+ correctly even when the user invoking your script has some strange
15
+ $PATH set in their environment.
16
+
17
+ There are two acceptable ways to do this:
18
+
19
+ (1) make *all* command references in your script use explicit pathnames:
20
+
21
+ /usr/bin/chown root bar
22
+ /usr/bin/chgrp sys bar
23
+ or (2) explicitly reset $PATH in your script:
24
+
25
+ PATH=/usr/bin; export PATH
26
+
27
+ chown root bar
28
+ chgrp sys bar
29
+
30
+ DO NOT use a mixture of (1) and (2) in the same script. Pick one method and use it consistently.
31
+
32
+
33
+ EOF
34
+
35
+
36
+
37
+ parser :bash
38
+
39
+ def run
40
+ if code.dont_have?(/^\s*PATH=/)
41
+ errors.add "PATH variable is not defined in the script"
42
+ end
43
+
44
+ if code.has?(/PATH=.*\$\{?PATH\}?/)
45
+ errors.add "PATH variable defined by extending existing $PATH variable at: #{code.lines}"
46
+ errors.add " #{code.search.inspect}"
47
+ errors.add code
48
+ end
49
+
50
+ return errors.empty?
51
+ end
52
+
53
+ end
@@ -0,0 +1,46 @@
1
+ banalizer :exit_on_error do
2
+
3
+ synopsis 'Script should be run with -e option or `set -o errexit`'
4
+
5
+ description <<EOF
6
+ Using this option forces bash script to exit on first error.
7
+
8
+ man bash:
9
+
10
+ -e Exit immediately if a simple command (see SHELL GRAMMAR above)
11
+ exits with a non-zero status. The shell does not exit if the
12
+ command that fails is part of the command list immediately
13
+ following a while or until keyword, part of the test in an if
14
+ statement, part of a && or || list, or if the command's return
15
+ value is being inverted via !. A trap on ERR, if set, is exe-
16
+ cuted before the shell exits.
17
+
18
+
19
+ `set -o errexit` is the same as `set -e`.
20
+
21
+ EOF
22
+
23
+ severity :gentle
24
+
25
+ def run
26
+ ret = true
27
+ #
28
+ # Prohibit using set +e option
29
+ #
30
+ errors.add "Setting +e option in shebang: #{shebang}" if (shebang.has? /\+e/)
31
+
32
+ if code.has? /set\s+\+e/
33
+ errors.add "Use of +e to unset -e option. Lines: #{code.lines}"
34
+ end
35
+
36
+
37
+ if ( code.dont_have?(/set\s+-e/) ||
38
+ code.dont_have?(/set\s+-o\s+errexit/)
39
+ ) &&
40
+ shebang.dont_have?(/\s-e/)
41
+ errors.add "Can not find option -e or -o errexit anywhere in the script"
42
+ end
43
+ return errors.empty?
44
+ end
45
+
46
+ end