brakeman-min 6.2.2 → 7.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.
@@ -7,6 +7,7 @@ begin
7
7
  require 'brakeman/file_parser'
8
8
  require 'brakeman/parsers/template_parser'
9
9
  require 'brakeman/processors/lib/file_type_detector'
10
+ require 'brakeman/tracker/file_cache'
10
11
  rescue LoadError => e
11
12
  $stderr.puts e.message
12
13
  $stderr.puts "Please install the appropriate dependency."
@@ -31,6 +32,7 @@ class Brakeman::Scanner
31
32
 
32
33
  @processor = processor || Brakeman::Processor.new(@app_tree, options)
33
34
  @show_timing = tracker.options[:debug] || tracker.options[:show_timing]
35
+ @per_file_timing = tracker.options[:debug] && tracker.options[:show_timing]
34
36
  end
35
37
 
36
38
  #Returns the Tracker generated from the scan
@@ -38,6 +40,10 @@ class Brakeman::Scanner
38
40
  @processor.tracked_events
39
41
  end
40
42
 
43
+ def file_cache
44
+ tracker.file_cache
45
+ end
46
+
41
47
  def process_step description
42
48
  Brakeman.notify "#{description}...".ljust(40)
43
49
 
@@ -53,7 +59,7 @@ class Brakeman::Scanner
53
59
  end
54
60
 
55
61
  def process_step_file description
56
- if @show_timing
62
+ if @per_file_timing
57
63
  Brakeman.notify "Processing #{description}"
58
64
 
59
65
  start_t = Time.now
@@ -67,7 +73,7 @@ class Brakeman::Scanner
67
73
  end
68
74
 
69
75
  #Process everything in the Rails application
70
- def process
76
+ def process(ruby_paths: nil, template_paths: nil)
71
77
  process_step 'Processing gems' do
72
78
  process_gems
73
79
  end
@@ -77,14 +83,30 @@ class Brakeman::Scanner
77
83
  process_config
78
84
  end
79
85
 
86
+ # -
87
+ # If ruby_paths or template_paths are set,
88
+ # only parse those files. The rest will be fetched
89
+ # from the file cache.
90
+ #
91
+ # Otherwise, parse everything normally.
92
+ #
93
+ astfiles = nil
94
+ process_step 'Finding files' do
95
+ ruby_paths ||= tracker.app_tree.ruby_file_paths
96
+ template_paths ||= tracker.app_tree.template_paths
97
+ end
98
+
80
99
  process_step 'Parsing files' do
81
- parse_files
100
+ astfiles = parse_files(ruby_paths: ruby_paths, template_paths: template_paths)
82
101
  end
83
102
 
84
103
  process_step 'Detecting file types' do
85
- detect_file_types
104
+ detect_file_types(astfiles)
86
105
  end
87
106
 
107
+ tracker.save_file_cache! if support_rescanning?
108
+ # -
109
+
88
110
  process_step 'Processing initializers' do
89
111
  process_initializers
90
112
  end
@@ -124,44 +146,37 @@ class Brakeman::Scanner
124
146
  tracker
125
147
  end
126
148
 
127
- def parse_files
149
+ def parse_files(ruby_paths:, template_paths:)
128
150
  fp = Brakeman::FileParser.new(tracker.app_tree, tracker.options[:parser_timeout], tracker.options[:parallel_checks], tracker.options[:use_prism])
129
151
 
130
- fp.parse_files tracker.app_tree.ruby_file_paths
152
+ fp.parse_files ruby_paths
131
153
 
132
154
  template_parser = Brakeman::TemplateParser.new(tracker, fp)
133
155
 
134
- fp.read_files(@app_tree.template_paths) do |path, contents|
135
- template_parser.parse_template path, contents
156
+ fp.read_files(template_paths) do |path, contents|
157
+ template_parser.parse_template(path, contents)
136
158
  end
137
159
 
138
160
  # Collect errors raised during parsing
139
161
  tracker.add_errors(fp.errors)
140
162
 
141
- @parsed_files = fp.file_list
163
+ fp.file_list
142
164
  end
143
165
 
144
- def detect_file_types
145
- @file_list = {
146
- controllers: [],
147
- initializers: [],
148
- libs: [],
149
- models: [],
150
- templates: [],
151
- }
152
-
166
+ def detect_file_types(astfiles)
153
167
  detector = Brakeman::FileTypeDetector.new
154
168
 
155
- @parsed_files.each do |file|
169
+ astfiles.each do |file|
156
170
  if file.is_a? Brakeman::TemplateParser::TemplateFile
157
- @file_list[:templates] << file
171
+ file_cache.add_file file, :template
158
172
  else
159
173
  type = detector.detect_type(file)
174
+
160
175
  unless type == :skip
161
- if @file_list[type].nil?
162
- raise type.to_s
176
+ if file_cache.valid_type? type
177
+ file_cache.add_file(file, type)
163
178
  else
164
- @file_list[type] << file
179
+ raise "Unexpected file type: #{type.inspect}"
165
180
  end
166
181
  end
167
182
  end
@@ -216,21 +231,29 @@ class Brakeman::Scanner
216
231
  #Process Gemfile
217
232
  def process_gems
218
233
  gem_files = {}
234
+ gem_file_names = ['Gemfile', 'gems.rb']
235
+ lock_file_names = ['Gemfile.lock', 'gems.locked']
219
236
 
220
- if @app_tree.exists? "Gemfile"
221
- file = @app_tree.file_path("Gemfile")
222
- gem_files[:gemfile] = { :src => parse_ruby_file(file), :file => file }
223
- elsif @app_tree.exists? "gems.rb"
224
- file = @app_tree.file_path("gems.rb")
225
- gem_files[:gemfile] = { :src => parse_ruby_file(file), :file => file }
237
+ if tracker.options[:gemfile]
238
+ name = tracker.options[:gemfile]
239
+ gem_file_names.unshift name
240
+ lock_file_names.unshift "#{name}.lock"
226
241
  end
227
242
 
228
- if @app_tree.exists? "Gemfile.lock"
229
- file = @app_tree.file_path("Gemfile.lock")
230
- gem_files[:gemlock] = { :src => file.read, :file => file }
231
- elsif @app_tree.exists? "gems.locked"
232
- file = @app_tree.file_path("gems.locked")
233
- gem_files[:gemlock] = { :src => file.read, :file => file }
243
+ gem_file_names.each do |name|
244
+ if @app_tree.exists? name
245
+ file = @app_tree.file_path(name)
246
+ gem_files[:gemfile] = { :src => parse_ruby_file(file), :file => file }
247
+ break
248
+ end
249
+ end
250
+
251
+ lock_file_names.each do |name|
252
+ if @app_tree.exists? name
253
+ file = @app_tree.file_path(name)
254
+ gem_files[:gemlock] = { :src => file.read, :file => file }
255
+ break
256
+ end
234
257
  end
235
258
 
236
259
  if @app_tree.gemspec
@@ -268,8 +291,8 @@ class Brakeman::Scanner
268
291
  #
269
292
  #Adds parsed information to tracker.initializers
270
293
  def process_initializers
271
- track_progress @file_list[:initializers] do |init|
272
- process_step_file init[:path] do
294
+ track_progress file_cache.initializers do |path, init|
295
+ process_step_file path do
273
296
  process_initializer init
274
297
  end
275
298
  end
@@ -289,8 +312,10 @@ class Brakeman::Scanner
289
312
  return
290
313
  end
291
314
 
292
- track_progress @file_list[:libs] do |lib|
293
- process_step_file lib.path do
315
+ libs = file_cache.libs.sort_by { |path, _| path }
316
+
317
+ track_progress libs do |path, lib|
318
+ process_step_file path do
294
319
  process_lib lib
295
320
  end
296
321
  end
@@ -322,15 +347,17 @@ class Brakeman::Scanner
322
347
  #
323
348
  #Adds processed controllers to tracker.controllers
324
349
  def process_controllers
325
- track_progress @file_list[:controllers] do |controller|
326
- process_step_file controller.path do
350
+ controllers = file_cache.controllers.sort_by { |path, _| path }
351
+
352
+ track_progress controllers do |path, controller|
353
+ process_step_file path do
327
354
  process_controller controller
328
355
  end
329
356
  end
330
357
  end
331
358
 
332
359
  def process_controller_data_flows
333
- controllers = tracker.controllers.sort_by { |name, _| name.to_s }
360
+ controllers = tracker.controllers.sort_by { |name, _| name }
334
361
 
335
362
  track_progress controllers, "controllers" do |name, controller|
336
363
  process_step_file name do
@@ -356,10 +383,10 @@ class Brakeman::Scanner
356
383
  #
357
384
  #Adds processed views to tracker.views
358
385
  def process_templates
359
- templates = @file_list[:templates].sort_by { |t| t[:path] }
386
+ templates = file_cache.templates.sort_by { |path, _| path }
360
387
 
361
- track_progress templates, "templates" do |template|
362
- process_step_file template[:path] do
388
+ track_progress templates, "templates" do |path, template|
389
+ process_step_file path do
363
390
  process_template template
364
391
  end
365
392
  end
@@ -370,7 +397,7 @@ class Brakeman::Scanner
370
397
  end
371
398
 
372
399
  def process_template_data_flows
373
- templates = tracker.templates.sort_by { |name, _| name.to_s }
400
+ templates = tracker.templates.sort_by { |name, _| name }
374
401
 
375
402
  track_progress templates, "templates" do |name, template|
376
403
  process_step_file name do
@@ -383,15 +410,17 @@ class Brakeman::Scanner
383
410
  #
384
411
  #Adds the processed models to tracker.models
385
412
  def process_models
386
- track_progress @file_list[:models] do |model|
387
- process_step_file model[:path] do
388
- process_model model[:path], model[:ast]
413
+ models = file_cache.models.sort_by { |path, _| path }
414
+
415
+ track_progress models do |path, model|
416
+ process_step_file path do
417
+ process_model model
389
418
  end
390
419
  end
391
420
  end
392
421
 
393
- def process_model path, ast
394
- @processor.process_model(ast, path)
422
+ def process_model astfile
423
+ @processor.process_model(astfile.ast, astfile.path)
395
424
  end
396
425
 
397
426
  def track_progress list, type = "files"
@@ -420,6 +449,10 @@ class Brakeman::Scanner
420
449
  tracker.error(e)
421
450
  nil
422
451
  end
452
+
453
+ def support_rescanning?
454
+ tracker.options[:support_rescanning]
455
+ end
423
456
  end
424
457
 
425
458
  # This is to allow operation without loading the Haml library
@@ -0,0 +1,83 @@
1
+ module Brakeman
2
+ class FileCache
3
+ def initialize(file_list = nil)
4
+ @file_list = file_list || {
5
+ controller: {},
6
+ initializer: {},
7
+ lib: {},
8
+ model: {},
9
+ template: {},
10
+ }
11
+ end
12
+
13
+ def controllers
14
+ @file_list[:controller]
15
+ end
16
+
17
+ def initializers
18
+ @file_list[:initializer]
19
+ end
20
+
21
+ def libs
22
+ @file_list[:lib]
23
+ end
24
+
25
+ def models
26
+ @file_list[:model]
27
+ end
28
+
29
+ def templates
30
+ @file_list[:template]
31
+ end
32
+
33
+ def add_file(astfile, type)
34
+ raise "Unknown type: #{type}" unless valid_type? type
35
+ @file_list[type][astfile.path] = astfile
36
+ end
37
+
38
+ def valid_type?(type)
39
+ @file_list.key? type
40
+ end
41
+
42
+ def cached? path
43
+ @file_list.any? do |name, list|
44
+ list[path]
45
+ end
46
+ end
47
+
48
+ def delete path
49
+ @file_list.each do |name, list|
50
+ list.delete path
51
+ end
52
+ end
53
+
54
+ def diff other
55
+ @file_list.each do |name, list|
56
+ other_list = other.send(:"#{name}s")
57
+
58
+ if list == other_list
59
+ next
60
+ else
61
+ puts "-- #{name} --"
62
+ puts "Old: #{other_list.keys - list.keys}"
63
+ puts "New: #{list.keys - other_list.keys}"
64
+ end
65
+ end
66
+ end
67
+
68
+ def dup
69
+ copy_file_list = @file_list.map do |name, list|
70
+ copy_list = list.map do |path, astfile|
71
+ copy_astfile = astfile.dup
72
+ copy_astfile.ast = copy_astfile.ast.deep_clone
73
+
74
+ [path, copy_astfile]
75
+ end.to_h
76
+
77
+ [name, copy_list]
78
+ end.to_h
79
+
80
+ FileCache.new(copy_file_list)
81
+ end
82
+ end
83
+ end
@@ -12,7 +12,7 @@ class Brakeman::Tracker
12
12
  attr_accessor :controllers, :constants, :templates, :models, :errors,
13
13
  :checks, :initializers, :config, :routes, :processor, :libs,
14
14
  :template_cache, :options, :filter_cache, :start_time, :end_time,
15
- :duration, :ignored_filter, :app_tree
15
+ :duration, :ignored_filter, :app_tree, :file_cache, :pristine_file_cache
16
16
 
17
17
  #Place holder when there should be a model, but it is not
18
18
  #clear what model it will be.
@@ -26,15 +26,22 @@ class Brakeman::Tracker
26
26
  @app_tree = app_tree
27
27
  @processor = processor
28
28
  @options = options
29
+ @file_cache = Brakeman::FileCache.new
30
+ @pristine_file_cache = nil
29
31
 
30
- @config = Brakeman::Config.new(self)
32
+ reset_all
33
+ end
34
+
35
+ def reset_all
31
36
  @templates = {}
32
37
  @controllers = {}
38
+
33
39
  #Initialize models with the unknown model so
34
40
  #we can match models later without knowing precisely what
35
41
  #class they are.
36
42
  @models = {}
37
43
  @models[UNKNOWN_MODEL] = Brakeman::Model.new(UNKNOWN_MODEL, nil, @app_tree.file_path("NOT_REAL.rb"), nil, self)
44
+
38
45
  @method_cache = {}
39
46
  @routes = {}
40
47
  @initializers = {}
@@ -46,11 +53,16 @@ class Brakeman::Tracker
46
53
  @template_cache = Set.new
47
54
  @filter_cache = {}
48
55
  @call_index = nil
56
+ @config = Brakeman::Config.new(self)
49
57
  @start_time = Time.now
50
58
  @end_time = nil
51
59
  @duration = nil
52
60
  end
53
61
 
62
+ def save_file_cache!
63
+ @pristine_file_cache = @file_cache.dup
64
+ end
65
+
54
66
  #Add an error to the list. If no backtrace is given,
55
67
  #the one from the exception will be used.
56
68
  def error exception, backtrace = nil
@@ -301,6 +313,11 @@ class Brakeman::Tracker
301
313
  method_sets << self.controllers
302
314
  end
303
315
 
316
+ if locations.include? :libs
317
+ classes_to_reindex.merge self.libs.keys
318
+ method_sets << self.libs
319
+ end
320
+
304
321
  if locations.include? :initializers
305
322
  self.initializers.each do |file_name, src|
306
323
  @call_index.remove_indexes_by_file file_name
@@ -1,3 +1,3 @@
1
1
  module Brakeman
2
- Version = "6.2.2"
2
+ Version = "7.0.1"
3
3
  end
data/lib/brakeman.rb CHANGED
@@ -84,6 +84,15 @@ module Brakeman
84
84
  options[:report_progress] = false
85
85
  end
86
86
 
87
+ if options[:use_prism]
88
+ begin
89
+ require 'prism'
90
+ notify '[Notice] Using Prism parser'
91
+ rescue LoadError => e
92
+ Brakeman.debug "[Notice] Asked to use Prism, but failed to load: #{e}"
93
+ end
94
+ end
95
+
87
96
  scan options
88
97
  end
89
98
 
@@ -118,6 +127,13 @@ module Brakeman
118
127
  options[:output_formats] = get_output_formats options
119
128
  options[:github_url] = get_github_url options
120
129
 
130
+
131
+ # Use ENV value only if option was not already explicitly set
132
+ # (i.e. prefer commandline option over environment variable).
133
+ if options[:gemfile].nil? and ENV['BUNDLE_GEMFILE']
134
+ options[:gemfile] = ENV['BUNDLE_GEMFILE']
135
+ end
136
+
121
137
  options
122
138
  end
123
139
 
@@ -196,6 +212,7 @@ module Brakeman
196
212
  :pager => true,
197
213
  :parallel_checks => true,
198
214
  :parser_timeout => 10,
215
+ :use_prism => true,
199
216
  :relative_path => false,
200
217
  :report_progress => true,
201
218
  :safe_methods => Set.new,
@@ -464,12 +481,12 @@ module Brakeman
464
481
  def self.rescan tracker, files, options = {}
465
482
  require 'brakeman/rescanner'
466
483
 
467
- tracker.options.merge! options
484
+ options = tracker.options.merge options
468
485
 
469
486
  @quiet = !!tracker.options[:quiet]
470
487
  @debug = !!tracker.options[:debug]
471
488
 
472
- Rescanner.new(tracker.options, tracker.processor, files).recheck
489
+ Rescanner.new(options, tracker.processor, files).recheck
473
490
  end
474
491
 
475
492
  def self.notify message
metadata CHANGED
@@ -1,29 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: brakeman-min
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.2.2
4
+ version: 7.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Justin Collins
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-10-17 00:00:00.000000000 Z
11
+ date: 2025-04-04 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: csv
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - ">="
18
- - !ruby/object:Gem::Version
19
- version: '0'
20
- type: :development
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - ">="
25
- - !ruby/object:Gem::Version
26
- version: '0'
27
13
  - !ruby/object:Gem::Dependency
28
14
  name: minitest
29
15
  requirement: !ruby/object:Gem::Requirement
@@ -66,20 +52,6 @@ dependencies:
66
52
  - - ">="
67
53
  - !ruby/object:Gem::Version
68
54
  version: '0'
69
- - !ruby/object:Gem::Dependency
70
- name: simplecov-html
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - '='
74
- - !ruby/object:Gem::Version
75
- version: 0.10.2
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - '='
81
- - !ruby/object:Gem::Version
82
- version: 0.10.2
83
55
  - !ruby/object:Gem::Dependency
84
56
  name: parallel
85
57
  requirement: !ruby/object:Gem::Requirement
@@ -341,6 +313,7 @@ files:
341
313
  - lib/brakeman/tracker/config.rb
342
314
  - lib/brakeman/tracker/constants.rb
343
315
  - lib/brakeman/tracker/controller.rb
316
+ - lib/brakeman/tracker/file_cache.rb
344
317
  - lib/brakeman/tracker/library.rb
345
318
  - lib/brakeman/tracker/method_info.rb
346
319
  - lib/brakeman/tracker/model.rb