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,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 8a4e26483ea5692063efa9d08adb90fcbc552243
4
+ data.tar.gz: 1225cf15d13b89501f0d6bf2cdff359f2927bcf6
5
+ SHA512:
6
+ metadata.gz: 0ac7bff7e15664f2beb9aa862c539451f8dab4531346abfca0d1f4fff5f13c7769666440c24e50c792f10aedaeb7bedf7d8b1c41d92cb53a917c812a65abef95
7
+ data.tar.gz: 940407208055587056763facf1b72c5720a5933f35cc01284e0d54e6d84bf54259b279ae2fea15202ee44e8c9a3bc5c3f7c0947bb697a8288cbb68f62fc7b146
@@ -0,0 +1,43 @@
1
+
2
+ ![banalize](images/banalize_small.png)
3
+
4
+ Parser architecture
5
+ ===========
6
+
7
+ Class Parser
8
+ -----------
9
+
10
+ Bash basic parser defines following methods:
11
+
12
+ - {Banalize::Parser#shebang} - first line of the script if it's in `#!` format or nil
13
+ - {Banalize::Parser#comments} - all block comments of the file, excluding shebang line
14
+ - {Banalize::Parser#code} - all non-comments of the script, excluding shebang line
15
+
16
+
17
+ All data returned by parser methods are instances of {Banalize::Numbered} class, i.e. they are lines of code with corresponing line number in the script file.
18
+
19
+ Class Numbered
20
+ ----------------------
21
+
22
+ Class {Banalize::Numbered} provides some helper methods to make searches simpler in the script files:
23
+
24
+ - {Banalize::Numbered#grep}
25
+
26
+ Find and return lines matching regular expresion.
27
+
28
+ - {Banalize::Numbered#has?} Aliased to {Banalize::Numbered#have?}.
29
+
30
+ Search for pattern in all lines, return true or false
31
+
32
+ - {Banalize::Numbered#does\_not\_have?} Alias {Banalize::Numbered#dont_have?}
33
+
34
+ Opposite for the above method. Return true if pattern in not found.
35
+
36
+ - {Banalize::Numbered#search} - attribute accessor. It always contains result of the last grep search.
37
+ - {Banalize::Numbered#lines}
38
+ - {Banalize::Numbered#to_s} (alias: {Banalize::Numbered#inspect})
39
+
40
+ Additional parsers
41
+ ===========
42
+
43
+ Will be added in the future.
@@ -0,0 +1,168 @@
1
+ [![Wizcorp](images/wizcorp-logo.png)](http://wizcorp.jp)
2
+
3
+ **Note** See formatted documentation at http://wizcorp.github.com/Banalize
4
+
5
+ Name
6
+ ===========
7
+
8
+ Banalize - static code analyzer for Bash
9
+
10
+ ![banalize](images/banalize.png)
11
+
12
+ Version {include:file:version.txt}
13
+ -----------
14
+
15
+ Description
16
+ ===========
17
+
18
+ Banalizer is syntax analyzer for bash scripts. It is modelled after ideas of [`Perl::Critic`](http://en.wikipedia.org/wiki/Perl::Critic) static analyzer for Perl. Most of the Banalizer is written in Ruby. Exception is policy files which are language agnostic, and can be written in any language: scripting or compiled.
19
+
20
+ Banalizer consists of main binary file, banalyzer libraries, command line interface (CLI) and policies.
21
+
22
+ Policy is requirement for bash script/file. For example: each script must have 'shebang' as first line.
23
+
24
+ Each policy is implemented as Ruby or other programming/scripting language file able to perform single check on single bash script file. Rest - aggregating checks, reporting, filtering etc - is handled by Banalizer.
25
+
26
+ ### Severity
27
+
28
+ From [`Perl::Critic`](http://perlcritic.tigris.org/) page:
29
+
30
+ > severity is the level of importance you wish to assign to the Policy. All Policy modules are defined with a default severity value ranging from 1 (least severe) to 5 (most severe). However, you may disagree with the default severity and choose to give it a higher or lower severity, based on your own coding philosophy. You can set the severity to an integer from 1 to 5, or use one of the equivalent names:
31
+ >
32
+ > SEVERITY NAME ...is equivalent to... SEVERITY NUMBER
33
+ > ----------------------------------------------------
34
+ > gentle 5
35
+ > stern 4
36
+ > harsh 3
37
+ > cruel 2
38
+ > brutal 1
39
+ >
40
+
41
+ ### Policy style
42
+
43
+ Banalizer's policy style more or less correspond to `Perl::Critic`'s policy theme with exclusion of Perl specific themes. Again quote from `Perl::Critic`:
44
+
45
+
46
+ > THEME DESCRIPTION
47
+ > --------------------------------------------------------------------------
48
+ > core All policies that ship with Perl::Critic
49
+ > pbp Policies that come directly from "Perl Best Practices"
50
+ > bugs Policies that that prevent or reveal bugs
51
+ > maintenance Policies that affect the long-term health of the code
52
+ > cosmetic Policies that only have a superficial effect
53
+ > complexity Policies that specificaly relate to code complexity
54
+ > security Policies that relate to security issues
55
+ > tests Policies that are specific to test scripts
56
+ >
57
+
58
+ See http://perlcritic.tigris.org/#THE%20POLICIES
59
+
60
+ Conventions
61
+ ===========
62
+
63
+ Policies
64
+ -----------
65
+
66
+ - All policies (policy files) installed in `./lib/policies` and users home `~/.banalize/policies` directories.
67
+
68
+ - There are two classes of policies recognized by Banalizer: Ruby and _'other'_
69
+ - Ruby policy files detected by `.rb` extension. Files without `.rb` extension are considered to be 'others'
70
+ - Policy name is detected from
71
+ - file name of 'other' policy
72
+ - first argument for `banalizer` method for Ruby policy
73
+ - all names should be unique, or they will be overwritten
74
+
75
+ ### Attributes
76
+
77
+ All policies have these attributes:
78
+
79
+ - policy (i.e. name)
80
+ - synopsis
81
+ - description
82
+ - severity
83
+ - style
84
+
85
+ Depending on the type of policy some of the attributes are required, some optional or can be set to reasonable default.
86
+
87
+ ### Non-ruby policies (i.e. others)
88
+
89
+ Policy should conform to few rules:
90
+
91
+ 1. it must return information about itself when called with parameter `config`
92
+ - Output of the `config` command is YAML formatted text
93
+ - Command returns attributes names and values of the policy
94
+ - All attributes in case of 'other' policy are optional
95
+
96
+ They are either set to default values if missing, or detected from other meta-data (like, for example, name of a policy is `$(basename file)` of policy file.
97
+ 2. Policy script must be able to perform single (syntax/semantic/format) check on bash script file and:
98
+ - return non-zero status if check fails or 0 if succeeds
99
+ - return (optional) error massages on STDOUT
100
+
101
+ **Note**: Only STDOUT is honored by Banalizer.
102
+
103
+ If your check command, for example, prints to STDERR but not to STDOUT, you'd need to redirect shell streams accordingly.
104
+
105
+ #### Example config section
106
+
107
+ ```yaml
108
+ ---
109
+ name: $(basename $0)
110
+ style:
111
+ - :bug
112
+ - :test
113
+ severity: 5
114
+ description: Runs bash syntax check using 'bash -n' option
115
+ ```
116
+
117
+ ### Ruby policy
118
+
119
+ 1. Ruby policy has two required items:
120
+ - name (_Note_: to avoid clashes with Ruby standard `name` method we use `policy` DSL method)
121
+ - must define method called `run`
122
+ 1. Policy is defined in top-level namespace's method called `banalizer`
123
+ - name is string or Ruby symbol parameter to `banalizer` method
124
+ - additional (optional) attributes are defined as DSL methods calls inside block given to `banalizer` method
125
+ - run method is defined in the same block
126
+ 1. DSL methods names correspond to policy attributes :
127
+ - policy (i.e. policy name)
128
+ - synopsis
129
+ - description
130
+ - style
131
+ - severity
132
+ 1. `run` method :
133
+ - need to return result of a check as something that can be evaluated into true or false
134
+ - optionally can pass along error messages from the check, using `errors.add` DSL method to populate errors object (instance of {Banalize::Errors} class
135
+ 1. Additionally Ruby policies have DSL method `default`. It sets default values for variables, that can be overridden by personal style configuration file ( See {file:CONFIGURATION.md}).
136
+
137
+ #### Examples
138
+
139
+ This is full working example of Ruby DSL policy:
140
+
141
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ruby
142
+ banalizer :shebang_format do
143
+
144
+ synopsis 'Format of shebang should be #!/usr/bin/env bash'
145
+ severity 5
146
+
147
+ def run
148
+ unless shebang.has?(%r{\#!/usr/bin/env\s+bash})
149
+
150
+ errors.add "First line is not in the format #!/usr/bin/env bash", 1
151
+ return false
152
+ end
153
+ end
154
+
155
+ end
156
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
157
+
158
+ If you want to use filename of Ruby policy as its name, do this:
159
+
160
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ruby
161
+ banalizer File.basename(__FILE__, '.rb').to_sym do
162
+
163
+ end
164
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
165
+
166
+
167
+ <!-- LocalWords: banalize
168
+ -->
@@ -0,0 +1,120 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'banalize'
4
+
5
+ include GLI::App
6
+ commands_from "commands"
7
+ version Banalize::VERSION
8
+ config_file Banalize::USER[:config]
9
+ program_desc <<-EOF
10
+
11
+ Banalize is Bash files static code analyzer. It runs each policy
12
+ corresponding to the required level of test severity and policies.
13
+
14
+ Policies are Ruby or other programming languages (Bash, perl)
15
+ executable scripts located in `lib/policies` directories.
16
+
17
+ EOF
18
+
19
+
20
+
21
+ flag [:group, :g], :desc => 'Use only policies included in specified group'
22
+ flag [:severity, :s], :desc => 'Use only policies of specified severity and above'
23
+ flag [:policy, :p], :desc => 'Apply single policy only (by name)'
24
+ flag [:style, :S], :desc => 'Use custom style file instead of default one.',
25
+ :default_value => Banalize::USER[:styles]
26
+
27
+ switch [:color, :c], :desc => "Use colored output"
28
+
29
+ pre do |global,command,options,args|
30
+
31
+ $color = true if global[:color]
32
+
33
+ #
34
+ # Load styles file. Styles override defaults defined in policies.
35
+ #
36
+ $styles = if global[:style] != Banalize::USER[:styles] ||
37
+ File.exist?(File.expand_path(Banalize::USER[:styles]))
38
+ begin
39
+ YAML.load_file global[:style]
40
+ rescue Banalize::BanalizeError => e
41
+ abort "#{e.class} error: Can not load styles file #{e.message}"
42
+ end
43
+
44
+ end
45
+
46
+ search = { }
47
+
48
+ if global[:policy]
49
+ search = global[:policy]
50
+ else
51
+ search.merge!({ :policy => global[:group] }) if global[:group]
52
+ search.merge!({ :severity => global[:severity].to_i }) if global[:severity]
53
+ end
54
+
55
+ $search = search
56
+ $policies = Banalize::Policy.search search
57
+
58
+ # - results of checks
59
+ # - count of failed checks
60
+ # - total count of checks
61
+ $res, $status, $total = { }, 0, 0
62
+ true
63
+ end
64
+
65
+ post do |global,command,options,args|
66
+ #
67
+ # output results of the check
68
+ #
69
+ unless $res.empty?
70
+
71
+ if options[:dots]
72
+ dots = ''
73
+ $res.each do |file,res|
74
+ $total += res.count
75
+ res.each do |k,v|
76
+ dots << (v[:status] ? '.' : "F".color(:red))
77
+ $status += 1 unless v[:status]
78
+ end
79
+ end
80
+ puts dots
81
+
82
+ else
83
+ out = { }
84
+ $res.each do |file,res|
85
+
86
+ failure = res.select { |k,v| !v[:status] }
87
+
88
+ # Ignore all other keys, only bring messages up. If no errors
89
+ # switch is set. only list empty policy names
90
+ failure.map do |k,v|
91
+ failure[k] = options[:errors] ? v[:messages] : nil
92
+ end
93
+
94
+ out[file] = { "Fail" => failure } unless failure.empty?
95
+
96
+ if options[:all]
97
+ out[file] ||= {}
98
+ out[file].merge!({ "Success" => res.keys.select { |k| res[k][:status] } })
99
+ end
100
+
101
+ $total += res.count
102
+ $status += failure.count
103
+ end
104
+
105
+ print ::Banalize.beautify(out)
106
+ end
107
+
108
+ puts "\n#{$res.count} files, #{$total.to_s} checks, #{$status.to_s} failed"
109
+ end
110
+
111
+ $status
112
+ end
113
+
114
+ on_error do |exception|
115
+ exit_now! exception.message unless exception.is_a? GLI::BadCommandLine
116
+ true
117
+ end
118
+
119
+ exit run(ARGV) && $status == 0
120
+
@@ -0,0 +1,64 @@
1
+ $: << File.dirname(__FILE__)
2
+
3
+ require 'gli'
4
+ require 'mash'
5
+ require 'active_support/inflector'
6
+ require 'active_support/core_ext'
7
+
8
+ # Order is not important, load all of them
9
+ Dir.glob("#{File.dirname(__FILE__)}/{core_extensions,helpers}/*.rb").each do |r|
10
+ require r
11
+ end
12
+
13
+ ##
14
+ # This is shamelessly stolen form Rspec::DSL. Inject method `policy`
15
+ # into the top level namespace, so the we can use in policy definition
16
+ # without need to define class inheritance.
17
+ #
18
+ # Registerd policies are listed in `@@policies` array.
19
+ #
20
+ module Banalize
21
+ ROOT = File.dirname(File.dirname(__FILE__))
22
+ VERSION = File.read(ROOT+'/version.txt').chomp.strip
23
+
24
+ # Local user directory with banalize config and policies
25
+
26
+ dot_banalize = "#{Dir.home}/.banalize"
27
+
28
+ USER = {
29
+ dot_banalize: dot_banalize,
30
+ config: "#{dot_banalize}/config", # Default user config file
31
+ styles: "#{dot_banalize}/style", # Default style file
32
+ policies: "#{dot_banalize}/policies"
33
+ }
34
+
35
+ # Truncate long error lines
36
+ TRUNCATE = ENV["BANALIZE_TRUNCATE_LINES"] == 'false' ? nil : 60
37
+
38
+ module DSL
39
+ @@policies = []
40
+ def banalizer my_name, &block
41
+ klass = Banalize::Registry.register(my_name, &block)
42
+ @@policies << klass
43
+ klass
44
+ end
45
+
46
+ def policies
47
+ @@policies
48
+ end
49
+ end
50
+ end
51
+
52
+ include Banalize::DSL
53
+
54
+ require 'banalize/parser/numbered'
55
+ require 'banalize/parser'
56
+ require 'banalize/exception'
57
+ require 'banalize/registry'
58
+
59
+ require 'banalize/errors'
60
+ require 'banalize/policy/severity'
61
+ require 'banalize/policy'
62
+ require 'banalize/files'
63
+ require 'banalize/runner'
64
+
@@ -0,0 +1,43 @@
1
+ module Banalize
2
+ ##
3
+ # Errors class provides stograge of error messages while running policy checks.
4
+ class Errors
5
+
6
+ def initialize klass
7
+ @klass = klass
8
+ @messages = []
9
+ end
10
+
11
+ attr_accessor :messages
12
+
13
+ def add message, line=nil
14
+ @messages << { :message => message, :line => line }
15
+ end
16
+
17
+ ##
18
+ # Retrun true if there are no errors
19
+ def empty?
20
+ @messages.empty?
21
+ end
22
+
23
+ ##
24
+ # Retrun true if there are any errors
25
+ #
26
+ def any?
27
+ ! empty?
28
+ end
29
+
30
+
31
+ ##
32
+ # Convert Array of Hashes of error messages into readable form
33
+ #
34
+ def self.to_s messages=[]
35
+ return '' if messages.empty?
36
+
37
+ messages.map do |err|
38
+ "#{err[:message]}#{err[:line] ? ", on line #{err[:line]}" : ''}"
39
+ end
40
+ end
41
+
42
+ end
43
+ end