brakeman-lib 3.3.5 → 3.4.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: aec96cc1da2d6480b8522d8b63a6ceac114256fc
4
- data.tar.gz: 59525f78b3554856223bf33b70d00be2cabce334
3
+ metadata.gz: e27ccfd7420f1e8272480ef9ca0de23fee00b540
4
+ data.tar.gz: 09ed85e36994255d6634bbcb7c8ca59e8790541b
5
5
  SHA512:
6
- metadata.gz: e68fb294389dcd669ae82dd91fa6b2949d3f19df3f9043dc5d5409c11865910dc64fed571e79d51134815c577445debccffdd0ca9c27b6fdcb830e37cfcb6342
7
- data.tar.gz: c325feff4fcfe7c23c20cc71ec10d25ac492e17a678c670128be845a227389f6db282198e08adbd97ed614a575e7fb80974c978370e18620f18e53e885ae8f2f
6
+ metadata.gz: 117943f4633a23ef3a34286fdcb7f445594c2bee527a6dea48e1a9b77bdff5b0e24aa563d22703e8caf34c4094ee17cdf6a83492ad9f247bcd00473984c0588c
7
+ data.tar.gz: c194c2535ff1db2743fcf66893d6d0dce2d5ff89ba7fc3a358c8a15564ea6de61bd0365f595051ab36eb6c6af987680fda94eba89aaca06d5d1085a584f31708
data/CHANGES CHANGED
@@ -1,3 +1,12 @@
1
+ # 3.4.0
2
+
3
+ * Add new `plain` report format
4
+ * Add option to prune ignore file with `-I`
5
+ * Improved Slim template support
6
+ * Show obsolete ignore entries in reports (Jonathan Cheatham)
7
+ * Support creating reports in non-existent paths
8
+ * Add `--no-exit-warn`
9
+
1
10
  # 3.3.5
2
11
 
3
12
  * Fix bug in reports when using --debug option
data/lib/brakeman.rb CHANGED
@@ -145,7 +145,8 @@ module Brakeman
145
145
  :parallel_checks => true,
146
146
  :relative_path => false,
147
147
  :report_progress => true,
148
- :html_style => "#{File.expand_path(File.dirname(__FILE__))}/brakeman/format/style.css"
148
+ :html_style => "#{File.expand_path(File.dirname(__FILE__))}/brakeman/format/style.css",
149
+ :output_color => true
149
150
  }
150
151
  end
151
152
 
@@ -186,6 +187,8 @@ module Brakeman
186
187
  [:to_markdown]
187
188
  when :cc, :to_cc, :codeclimate, :to_codeclimate
188
189
  [:to_codeclimate]
190
+ when :plain ,:to_plain
191
+ [:to_plain]
189
192
  else
190
193
  [:to_s]
191
194
  end
@@ -209,6 +212,8 @@ module Brakeman
209
212
  :to_markdown
210
213
  when /(\.cc|\.codeclimate)$/i
211
214
  :to_codeclimate
215
+ when /\.plain$/i
216
+ :to_plain
212
217
  else
213
218
  :to_s
214
219
  end
@@ -362,7 +367,15 @@ module Brakeman
362
367
  end
363
368
 
364
369
  def self.write_report_to_files tracker, output_files
370
+ require 'fileutils'
371
+ tracker.options[:output_color] = false
372
+
365
373
  output_files.each_with_index do |output_file, idx|
374
+ dir = File.dirname(output_file)
375
+ unless Dir.exist? dir
376
+ FileUtils.mkdir_p(dir)
377
+ end
378
+
366
379
  File.open output_file, "w" do |f|
367
380
  f.write tracker.report.format(tracker.options[:output_formats][idx])
368
381
  end
@@ -372,6 +385,10 @@ module Brakeman
372
385
  private_class_method :write_report_to_files
373
386
 
374
387
  def self.write_report_to_formats tracker, output_formats
388
+ unless $stdout.tty?
389
+ tracker.options[:output_color] = false
390
+ end
391
+
375
392
  output_formats.each do |output_format|
376
393
  puts tracker.report.format(output_format)
377
394
  end
@@ -39,8 +39,8 @@ module Brakeman::Options
39
39
  options[:quiet] = quiet
40
40
  end
41
41
 
42
- opts.on( "-z", "--exit-on-warn", "Exit code is non-zero if warnings found") do
43
- options[:exit_on_warn] = true
42
+ opts.on( "-z", "--[no-]exit-on-warn", "Exit code is non-zero if warnings found") do |exit_on_warn|
43
+ options[:exit_on_warn] = exit_on_warn
44
44
  end
45
45
 
46
46
  opts.on "-3", "--rails3", "Force Rails 3 mode" do
@@ -172,12 +172,12 @@ module Brakeman::Options
172
172
 
173
173
  opts.on "-f",
174
174
  "--format TYPE",
175
- [:pdf, :text, :html, :csv, :tabs, :json, :markdown, :codeclimate, :cc],
175
+ [:pdf, :text, :html, :csv, :tabs, :json, :markdown, :codeclimate, :cc, :plain],
176
176
  "Specify output formats. Default is text" do |type|
177
177
 
178
178
  type = "s" if type == :text
179
179
  options[:output_format] = ("to_" << type.to_s).to_sym
180
- end
180
+ end
181
181
 
182
182
  opts.on "--css-file CSSFile", "Specify CSS to use for HTML output" do |file|
183
183
  options[:html_style] = File.expand_path file
@@ -199,6 +199,10 @@ module Brakeman::Options
199
199
  options[:highlight_user_input] = highlight
200
200
  end
201
201
 
202
+ opts.on "--[no-]color", "Use ANSI colors in report (Default)" do |color|
203
+ options[:output_color] = color
204
+ end
205
+
202
206
  opts.on "-m", "--routes", "Report controller information" do
203
207
  options[:report_routes] = true
204
208
  end
@@ -9,7 +9,9 @@ class Brakeman::OutputProcessor < Ruby2Ruby
9
9
  include Brakeman::Util
10
10
 
11
11
  #Copies +exp+ and then formats it.
12
- def format exp
12
+ def format exp, user_input = nil, &block
13
+ @user_input = user_input
14
+ @user_input_block = block
13
15
  process(exp.deep_clone) || "[Format Error]"
14
16
  end
15
17
 
@@ -17,7 +19,11 @@ class Brakeman::OutputProcessor < Ruby2Ruby
17
19
 
18
20
  def process exp
19
21
  begin
20
- super exp if sexp? exp and not exp.empty?
22
+ if @user_input and @user_input == exp
23
+ @user_input_block.call(exp, super(exp))
24
+ else
25
+ super exp if sexp? exp and not exp.empty?
26
+ end
21
27
  rescue => e
22
28
  Brakeman.debug "While formatting #{exp}: #{e}\n#{e.backtrace.join("\n")}"
23
29
  end
@@ -7,6 +7,7 @@ class Brakeman::SlimTemplateProcessor < Brakeman::TemplateProcessor
7
7
  SAFE_BUFFER = s(:call, s(:colon2, s(:const, :ActiveSupport), :SafeBuffer), :new)
8
8
  OUTPUT_BUFFER = s(:ivar, :@output_buffer)
9
9
  TEMPLE_UTILS = s(:colon2, s(:colon3, :Temple), :Utils)
10
+ ATTR_MERGE = s(:call, s(:call, s(:array), :reject, s(:block_pass, s(:lit, :empty?))), :join, s(:str, " "))
10
11
 
11
12
  def process_call exp
12
13
  target = exp.target
@@ -16,7 +17,7 @@ class Brakeman::SlimTemplateProcessor < Brakeman::TemplateProcessor
16
17
  arg = normalize_output(exp.first_arg)
17
18
 
18
19
  if is_escaped? arg
19
- add_escaped_output arg
20
+ add_escaped_output arg.first_arg
20
21
  elsif string? arg
21
22
  ignore
22
23
  elsif render? arg
@@ -25,11 +26,15 @@ class Brakeman::SlimTemplateProcessor < Brakeman::TemplateProcessor
25
26
  process_inside_interp arg
26
27
  elsif node_type? arg, :ignore
27
28
  ignore
29
+ elsif internal_variable? arg
30
+ ignore
31
+ elsif arg == ATTR_MERGE
32
+ ignore
28
33
  else
29
34
  add_output arg
30
35
  end
31
36
  elsif is_escaped? exp
32
- add_escaped_output exp.first_arg
37
+ add_escaped_output arg
33
38
  elsif target == nil and method == :render
34
39
  exp.arglist = process exp.arglist
35
40
  make_render_in_view exp
@@ -73,12 +78,25 @@ class Brakeman::SlimTemplateProcessor < Brakeman::TemplateProcessor
73
78
  end
74
79
  end
75
80
 
81
+ def add_escaped_output exp
82
+ exp = normalize_output(exp)
83
+
84
+ return exp if string? exp or internal_variable? exp
85
+
86
+ super exp
87
+ end
88
+
76
89
  def is_escaped? exp
77
90
  call? exp and
78
91
  exp.target == TEMPLE_UTILS and
79
92
  (exp.method == :escape_html or exp.method == :escape_html_safe)
80
93
  end
81
94
 
95
+ def internal_variable? exp
96
+ node_type? exp, :lvar and
97
+ exp.value =~ /^_(temple_|slim_)/
98
+ end
99
+
82
100
  def render? exp
83
101
  call? exp and
84
102
  exp.target.nil? and
@@ -6,7 +6,7 @@ require 'brakeman/report/report_base'
6
6
  class Brakeman::Report
7
7
  attr_reader :tracker
8
8
 
9
- VALID_FORMATS = [:to_html, :to_pdf, :to_csv, :to_json, :to_tabs, :to_hash, :to_s, :to_markdown, :to_codeclimate]
9
+ VALID_FORMATS = [:to_html, :to_pdf, :to_csv, :to_json, :to_tabs, :to_hash, :to_s, :to_markdown, :to_codeclimate, :to_plain]
10
10
 
11
11
  def initialize app_tree, tracker
12
12
  @app_tree = app_tree
@@ -34,6 +34,8 @@ class Brakeman::Report
34
34
  Brakeman::Report::Hash
35
35
  when :to_markdown
36
36
  return self.to_markdown
37
+ when :to_plain
38
+ return self.to_plain
37
39
  when :to_s
38
40
  return self.to_s
39
41
  when :to_pdf
@@ -72,6 +74,11 @@ class Brakeman::Report
72
74
  generate Brakeman::Report::Markdown
73
75
  end
74
76
 
77
+ def to_plain
78
+ require_report 'text'
79
+ generate Brakeman::Report::Text
80
+ end
81
+
75
82
  def generate reporter
76
83
  reporter.new(@app_tree, @tracker).generate_report
77
84
  end
@@ -11,6 +11,7 @@ module Brakeman
11
11
  @new_warnings = new_warnings
12
12
  @already_ignored = []
13
13
  @ignored_fingerprints = Set.new
14
+ @used_fingerprints = Set.new
14
15
  @notes = {}
15
16
  @shown_warnings = @ignored_warnings = nil
16
17
  @changed = false
@@ -43,6 +44,7 @@ module Brakeman
43
44
 
44
45
  # Determine if warning should be ignored
45
46
  def ignored? warning
47
+ @used_fingerprints << warning.fingerprint
46
48
  @ignored_fingerprints.include? warning.fingerprint
47
49
  end
48
50
 
@@ -75,6 +77,22 @@ module Brakeman
75
77
  nil
76
78
  end
77
79
 
80
+ # The set of unused ignore entries
81
+ def obsolete_fingerprints
82
+ (@ignored_fingerprints - @used_fingerprints).to_a
83
+ end
84
+
85
+ def prune_obsolete
86
+ obsolete = obsolete_fingerprints.to_set
87
+ @ignored_fingerprints -= obsolete
88
+
89
+ @already_ignored.reject! do |w|
90
+ if obsolete.include? w[:fingerprint]
91
+ @changed = true
92
+ end
93
+ end
94
+ end
95
+
78
96
  # Read configuration to file
79
97
  def read_from_file file = @file
80
98
  if File.exist? file
@@ -19,6 +19,7 @@ module Brakeman
19
19
  @ignore_config.filter_ignored
20
20
 
21
21
  unless @quit
22
+ penultimate_menu
22
23
  final_menu
23
24
  end
24
25
 
@@ -65,6 +66,10 @@ module Brakeman
65
66
  process_warnings
66
67
  end
67
68
 
69
+ m.choice "Prune obsolete ignored warnings" do
70
+ prune_obsolete
71
+ end
72
+
68
73
  m.choice "Skip - use current ignore configuration" do
69
74
  @quit = true
70
75
  @ignore_config.filter_ignored
@@ -103,6 +108,36 @@ q - Quit, do not update ignored warnings
103
108
  end
104
109
  end
105
110
 
111
+ def penultimate_menu
112
+ obsolete = @ignore_config.obsolete_fingerprints
113
+ return unless obsolete.any?
114
+
115
+ if obsolete.length > 1
116
+ plural = 's'
117
+ verb = 'are'
118
+ else
119
+ plural = ''
120
+ verb = 'is'
121
+ end
122
+
123
+ say "\n#{obsolete.length} fingerprint#{plural} #{verb} unused:", :green
124
+ obsolete.each do |obs|
125
+ say obs
126
+ end
127
+
128
+ if yes_or_no "\nRemove fingerprint#{plural}?"
129
+ @ignore_config.prune_obsolete
130
+ end
131
+ end
132
+
133
+ def prune_obsolete
134
+ @ignore_config.filter_ignored
135
+ obsolete = @ignore_config.obsolete_fingerprints
136
+ @ignore_config.prune_obsolete
137
+
138
+ say "Removed #{obsolete.length} obsolete fingerprint#{'s' if obsolete.length > 1} from ignore config.", :yellow
139
+ end
140
+
106
141
  def final_menu
107
142
  summarize_changes
108
143
 
@@ -79,6 +79,11 @@ class Brakeman::Report::Base
79
79
  render_array('error_overview', ['Error', 'Location'], values, {:tracker => tracker})
80
80
  end
81
81
 
82
+ def generate_obsolete
83
+ values = tracker.unused_fingerprints.collect{|fingerprint| [fingerprint] }
84
+ render_array('obsolete_ignore_entries', ['fingerprint'], values, {:tracker => tracker})
85
+ end
86
+
82
87
  def generate_warnings
83
88
  render_warnings generic_warnings,
84
89
  :warning,
@@ -2,6 +2,8 @@ class Brakeman::Report::JSON < Brakeman::Report::Base
2
2
  def generate_report
3
3
  errors = tracker.errors.map{|e| { :error => e[:error], :location => e[:backtrace][0] }}
4
4
 
5
+ obsolete = tracker.unused_fingerprints
6
+
5
7
  warnings = convert_to_hashes all_warnings
6
8
 
7
9
  ignored = convert_to_hashes ignored_warnings
@@ -26,7 +28,8 @@ class Brakeman::Report::JSON < Brakeman::Report::Base
26
28
  :scan_info => scan_info,
27
29
  :warnings => warnings,
28
30
  :ignored_warnings => ignored,
29
- :errors => errors
31
+ :errors => errors,
32
+ :obsolete => obsolete
30
33
  }
31
34
 
32
35
  JSON.pretty_generate report_info
@@ -25,6 +25,7 @@ class Brakeman::Report::Table < Brakeman::Report::Base
25
25
  truncate_table(generate_templates.to_s) << "\n"
26
26
  end
27
27
 
28
+ output_table("+Obsolete Ignore Entries+", generate_obsolete, out)
28
29
  output_table("+Errors+", generate_errors, out)
29
30
  output_table("+SECURITY WARNINGS+", generate_warnings, out)
30
31
  output_table("Controller Warnings:", generate_controller_warnings, out)
@@ -0,0 +1,193 @@
1
+ Brakeman.load_brakeman_dependency 'highline'
2
+
3
+ class Brakeman::Report::Text < Brakeman::Report::Base
4
+ def generate_report
5
+ HighLine.use_color = !!tracker.options[:output_color]
6
+ @output_string = "\n"
7
+
8
+ add_chunk generate_header
9
+ add_chunk generate_overview
10
+ add_chunk generate_warning_overview
11
+ return @output_string if tracker.options[:summary_only]
12
+
13
+ add_chunk generate_controllers if tracker.options[:debug] or tracker.options[:report_routes]
14
+ add_chunk generate_templates if tracker.options[:debug]
15
+ add_chunk generate_obsolete
16
+ add_chunk generate_errors
17
+ add_chunk generate_warnings
18
+ end
19
+
20
+ def add_chunk chunk, out = @output_string
21
+ if chunk and not chunk.empty?
22
+ if chunk.is_a? Array
23
+ chunk = chunk.join("\n")
24
+ end
25
+
26
+ out << chunk << "\n\n"
27
+ end
28
+ end
29
+
30
+ def generate_header
31
+ [
32
+ header("Brakeman Report"),
33
+ label("Application Path", tracker.app_path),
34
+ label("Rails Version", rails_version),
35
+ label("Brakeman Version", Brakeman::Version),
36
+ label("Scan Date", tracker.start_time),
37
+ label("Duration", "#{tracker.duration} seconds"),
38
+ label("Checks Run", checks.checks_run.sort.join(", "))
39
+ ]
40
+ end
41
+
42
+ def generate_overview
43
+ overview = [
44
+ header("Overview"),
45
+ label('Controllers', tracker.controllers.length),
46
+ label('Models', tracker.models.length - 1),
47
+ label('Templates', number_of_templates(@tracker)),
48
+ label('Errors', tracker.errors.length),
49
+ label('Security Warnings', all_warnings.length)
50
+ ]
51
+
52
+ unless ignored_warnings.empty?
53
+ overview << label('Ignored Warnings', ignored_warnings.length)
54
+ end
55
+
56
+ overview
57
+ end
58
+
59
+ def generate_warning_overview
60
+ warning_types = warnings_summary
61
+ warning_types.delete :high_confidence
62
+
63
+ warning_types.sort_by { |t, c| t }.map do |type, count|
64
+ label(type, count)
65
+ end.unshift(header('Warning Types'))
66
+ end
67
+
68
+ def generate_warnings
69
+ if tracker.filtered_warnings.empty?
70
+ HighLine.color("No warnings found", :bold, :green)
71
+ else
72
+ warnings = tracker.filtered_warnings.sort_by do |w|
73
+ [w.confidence, w.warning_type, w.fingerprint]
74
+ end.map do |w|
75
+ output_warning w
76
+ end
77
+
78
+ double_space "Warnings", warnings
79
+ end
80
+ end
81
+
82
+ def generate_errors
83
+ return if tracker.errors.empty?
84
+ full_trace = tracker.options[:debug]
85
+
86
+ errors = tracker.errors.map do |e|
87
+ trace = if full_trace
88
+ e[:backtrace].join("\n")
89
+ else
90
+ e[:backtrace][0]
91
+ end
92
+
93
+ [
94
+ label("Error", e[:error]),
95
+ label("Location", trace)
96
+ ]
97
+ end
98
+
99
+ double_space "Errors", errors
100
+ end
101
+
102
+ def generate_obsolete
103
+ return if tracker.unused_fingerprints.empty?
104
+
105
+ [header("Obsolete Ignore Entries")] + tracker.unused_fingerprints
106
+ end
107
+
108
+ def generate_templates
109
+ out_processor = Brakeman::OutputProcessor.new
110
+
111
+ template_rows = {}
112
+ tracker.templates.each do |name, template|
113
+ template.each_output do |out|
114
+ out = out_processor.format out
115
+ template_rows[name] ||= []
116
+ template_rows[name] << out.gsub("\n", ";").gsub(/\s+/, " ")
117
+ end
118
+ end
119
+
120
+ double_space "Template Output", template_rows.sort_by { |name, value| name.to_s }.map { |template|
121
+ [HighLine.new.color(template.first.to_s << "\n", :cyan)] + template[1]
122
+ }.compact
123
+ end
124
+
125
+ def output_warning w
126
+ out = [
127
+ label('Confidence', confidence(w.confidence)),
128
+ label('Category', w.warning_type.to_s),
129
+ label('Message', w.message)
130
+ ]
131
+
132
+ if w.code
133
+ out << label('Code', format_code(w))
134
+ end
135
+
136
+ out << label('File', warning_file(w))
137
+
138
+ if w.line
139
+ out << label('Line', w.line)
140
+ end
141
+
142
+ out
143
+ end
144
+
145
+ def double_space title, values
146
+ values = values.map { |v| v.join("\n") }.join("\n\n")
147
+ [header(title), values]
148
+ end
149
+
150
+ def format_code w
151
+ if @highlight_user_input and w.user_input
152
+ w.format_with_user_input do |exp, text|
153
+ HighLine.new.color(text, :yellow)
154
+ end
155
+ else
156
+ w.format_code
157
+ end
158
+ end
159
+
160
+ def confidence c
161
+ case c
162
+ when 0
163
+ HighLine.new.color("High", :red)
164
+ when 1
165
+ HighLine.new.color("Medium", :yellow)
166
+ when 2
167
+ HighLine.new.color("Weak", :none)
168
+ end
169
+ end
170
+
171
+ def label l, value, color = :green
172
+ "#{HighLine.new.color(l, color)}: #{value}"
173
+ end
174
+
175
+ def header text
176
+ HighLine.new.color("== #{text} ==\n", :bold, :magenta)
177
+ end
178
+
179
+ # ONLY used for generate_controllers to avoid duplication
180
+ def render_array name, cols, values, locals
181
+ controllers = values.map do |name, parent, includes, routes|
182
+ [
183
+ label("Controller", name),
184
+ label("Parent", parent),
185
+ label("Includes", includes),
186
+ label("Routes", routes)
187
+ ]
188
+ end
189
+
190
+ double_space "Controller Overview", controllers
191
+ end
192
+ end
193
+
@@ -185,6 +185,11 @@ class Brakeman::Tracker
185
185
  end
186
186
  end
187
187
 
188
+ def unused_fingerprints
189
+ return [] unless self.ignored_filter
190
+ self.ignored_filter.obsolete_fingerprints
191
+ end
192
+
188
193
  def add_constant name, value, context = nil
189
194
  @constants.add name, value, context unless @options[:disable_constant_tracking]
190
195
  end
@@ -1,3 +1,3 @@
1
1
  module Brakeman
2
- Version = "3.3.5"
2
+ Version = "3.4.0"
3
3
  end
@@ -134,6 +134,16 @@ class Brakeman::Warning
134
134
  format_ruby self.user_input, strip
135
135
  end
136
136
 
137
+ def format_with_user_input strip = true, &block
138
+ if self.user_input
139
+ formatted = Brakeman::OutputProcessor.new.format(code, self.user_input, &block)
140
+ formatted.gsub!(/(\t|\r|\n)+/, " ") if strip
141
+ formatted
142
+ else
143
+ format_code
144
+ end
145
+ end
146
+
137
147
  #Return formatted warning message
138
148
  def format_message
139
149
  return @format_message if @format_message
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: brakeman-lib
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.3.5
4
+ version: 3.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Justin Collins
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain:
11
11
  - brakeman-public_cert.pem
12
- date: 2016-08-12 00:00:00.000000000 Z
12
+ date: 2016-09-07 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: minitest
@@ -309,6 +309,7 @@ files:
309
309
  - lib/brakeman/report/report_markdown.rb
310
310
  - lib/brakeman/report/report_table.rb
311
311
  - lib/brakeman/report/report_tabs.rb
312
+ - lib/brakeman/report/report_text.rb
312
313
  - lib/brakeman/report/templates/controller_overview.html.erb
313
314
  - lib/brakeman/report/templates/controller_warnings.html.erb
314
315
  - lib/brakeman/report/templates/error_overview.html.erb