brakeman-lib 7.1.0 → 7.1.2

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
  SHA256:
3
- metadata.gz: c2279f2b84d3be0e168b6b16e59855f5507c0514df39c4fb4b63d76721b7e87d
4
- data.tar.gz: 37751126761102664819b8779940ecbc2097caec46176f4fc8d3b0f740585579
3
+ metadata.gz: 7ea221a705906bc411f454313acfcdf88cca8b45c9fbfc31fa4f3ccf29b0e2f5
4
+ data.tar.gz: 3aa55c53e8da987ae87ada8a3b82a763a38a9926a37c62aa1ab097878abb86b6
5
5
  SHA512:
6
- metadata.gz: 2c8a2bf6f2f3c2ee11419def7e7e91a4942cf337504db7a6e54c66f7b6a645cef31ac86de9580f78bdfe0ca66d08387d4125d36f106ac63354423e3973917deb
7
- data.tar.gz: b77e61957f321cdbdf33a41b057779c5b5f60a41512d538737a8aa0e57e6c6fc13cf9213cc710995ff55de04a57c1640492108529fda616553c6fb7ba5cd81d7
6
+ metadata.gz: 0ff5ade2e856bcb0e0c94ac76e8ab730b794e44cd8ab887d0c0687c562da8eb9ebd9429a0178c93cc0239a81f0d9621d05db2189b1ae9e28580a4d811888e7f3
7
+ data.tar.gz: 708dfa80c235e15e1c9c448064ba7e072846e72f7f5aa8a838dd63fb81e727ee809824629626d35199dd034219e4f606e24dbe05651ef1f3dc923dfb604e86e9
data/CHANGES.md CHANGED
@@ -1,3 +1,24 @@
1
+ # 7.1.2 - 2025-12-25
2
+
3
+ * Update `ruby_parser` to remove version restriction (Chedli Bourguiba)
4
+ * Raise minimum required Ruby to 3.2.0
5
+ * Use Minitest 6.0
6
+ * Reduce SQL injection false positives from `count` calls
7
+ * Ignore more Haml attribute builder methods
8
+
9
+ # 7.1.1 - 2025-11-03
10
+
11
+ * Fix false positive when calling `with_content` on ViewComponents (Peer Allan)
12
+ * Word wrap text output in pager
13
+ * Consider Tempfile.create.path as safe input (Ali Ismayilov)
14
+ * Exclude directories before searching for files
15
+ * Check each side of `or` SQL arguments
16
+ * Ignore attribute builder in Haml 6
17
+ * Add `FilePath#to_path` for Ruby 3.5 compatibility (S-H-GAMELINKS)
18
+ * Fix SQL injection check for calculate method (Rohan Sharma)
19
+ * Fix missing `td` in HTML report (John Hawthorn)
20
+ * Check for unsafe SQL when two arguments are passed to AR methods (Patrick Brinich-Langlois)
21
+
1
22
  # 7.1.0 - 2025-07-18
2
23
 
3
24
  * Add EOL dates for Rails 8.0 and Ruby 3.4
@@ -7,7 +28,7 @@
7
28
  * Improve ignored warnings layout in HTML report (Sebastien Savater)
8
29
  * Update JUnit report for CircleCI (Philippe Bernery)
9
30
  * Only load escape functionality from cgi library (Earlopain)
10
- * Add `--ensure-no-obsolete-config-entries` option (viralpraxis)
31
+ * Add `--ensure-no-obsolete-ignore-entries` option (viralpraxis)
11
32
 
12
33
  # 7.0.2 - 2025-04-04
13
34
 
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  [![Brakeman Logo](http://brakemanscanner.org/images/logo_medium.png)](http://brakemanscanner.org/)
2
2
 
3
3
  [![Build Status](https://circleci.com/gh/presidentbeef/brakeman.svg?style=svg)](https://circleci.com/gh/presidentbeef/brakeman)
4
- [![Test Coverage](https://api.codeclimate.com/v1/badges/1b08a5c74695cb0d11ec/test_coverage)](https://codeclimate.com/github/presidentbeef/brakeman/test_coverage)
4
+ [![Code Coverage](https://qlty.sh/gh/presidentbeef/projects/brakeman/coverage.svg)](https://qlty.sh/gh/presidentbeef/projects/brakeman)
5
5
 
6
6
  # Brakeman
7
7
 
@@ -65,7 +65,7 @@ Outside of Rails root (note that the output file is relative to path/to/rails/ap
65
65
 
66
66
  Brakeman should work with any version of Rails from 2.3.x to 8.x.
67
67
 
68
- Brakeman can analyze code written with Ruby 2.0 syntax and newer, but requires at least Ruby 3.0.0 to run.
68
+ Brakeman can analyze code written with Ruby 2.0 syntax and newer, but requires at least Ruby 3.2.0 to run.
69
69
 
70
70
  # Basic Options
71
71
 
@@ -75,7 +75,7 @@ To specify an output file for the results:
75
75
 
76
76
  brakeman -o output_file
77
77
 
78
- The output format is determined by the file extension or by using the `-f` option. Current options are: `text`, `html`, `tabs`, `json`, `junit`, `markdown`, `csv`, `codeclimate`, and `sonar`.
78
+ The output format is determined by the file extension or by using the `-f` option. Current options are: `text`, `html`, `tabs`, `json`, `junit`, `markdown`, `csv`, `codeclimate`, `github` and `sonar`.
79
79
 
80
80
  Multiple output files can be specified:
81
81
 
@@ -33,6 +33,7 @@ module Brakeman
33
33
  # * "path1/" - Matches any path that contains "path1" in the project directory.
34
34
  # * "/path1/ - Matches any path that is rooted at "path1" in the project directory.
35
35
  #
36
+ # TODO: This is wacky and I don't like it.
36
37
  def self.regex_for_paths(paths)
37
38
  path_regexes = paths.map do |f|
38
39
  # If path ends in a file separator then we assume it is a path rather
@@ -192,7 +193,12 @@ module Brakeman
192
193
  files = patterns.flat_map { |pattern| Dir.glob(pattern) }
193
194
  files.uniq.lazy
194
195
  else
195
- pattern = "#{root_search_pattern}#{directory}/**/#{name}#{extensions}"
196
+ if directory == '.'
197
+ pattern = File.join(top_directories_pattern, '**', "#{name}#{extensions}")
198
+ else
199
+ pattern = "#{root_search_pattern}#{directory}/**/#{name}#{extensions}"
200
+ end
201
+
196
202
  Dir.glob(pattern).lazy
197
203
  end
198
204
  end
@@ -257,18 +263,47 @@ module Brakeman
257
263
  end
258
264
 
259
265
  def match_path files, path
266
+ # TODO: Converting to Pathnames and Strings seems like a lot
267
+ # of converting that could perhaps all be handled in Brakeman::FilePath
268
+ # instead?
260
269
  absolute_path = Pathname.new(path)
270
+
261
271
  # relative root never has a leading separator. But, we use a leading
262
272
  # separator in a @skip_files entry to imply that a directory is
263
273
  # "absolute" with respect to the project directory.
264
- project_relative_path = File.join(
265
- File::SEPARATOR,
266
- absolute_path.relative_path_from(@project_root_path).to_s
267
- )
274
+ #
275
+ # Also directories need a trailing separator.
276
+ project_relative_path = if File.directory?(path)
277
+ File.join(
278
+ File::SEPARATOR,
279
+ absolute_path.relative_path_from(@project_root_path).to_s,
280
+ File::SEPARATOR
281
+ )
282
+ else
283
+ File.join(
284
+ File::SEPARATOR,
285
+ absolute_path.relative_path_from(@project_root_path).to_s
286
+ )
287
+ end
268
288
 
269
289
  files.match(project_relative_path)
270
290
  end
271
291
 
292
+ def top_directories_pattern
293
+ top_dirs = convert_to_file_paths(Dir.glob(File.join(root_search_pattern, '*/')))
294
+ top_dirs.reject! { |d| File.symlink?(d) or !File.directory?(d) }
295
+ top_dirs = reject_global_excludes(top_dirs)
296
+ top_dirs = reject_skipped_files(top_dirs)
297
+
298
+ if top_dirs.empty?
299
+ # Fall back to searching everything, otherwise the empty pattern
300
+ # will start searching from the global root
301
+ root_search_pattern
302
+ else
303
+ "{#{top_dirs.join(',')}}"
304
+ end
305
+ end
306
+
272
307
  def root_search_pattern
273
308
  return @root_search_pattern if @root_search_pattern
274
309
  @root_search_pattern = search_pattern(@root)
@@ -151,10 +151,13 @@ class Brakeman::BaseCheck < Brakeman::SexpProcessor
151
151
  method[-1] == "?"
152
152
  end
153
153
 
154
- TEMP_FILE_PATH = s(:call, s(:call, s(:const, :Tempfile), :new), :path).freeze
154
+ TEMP_FILE_PATH = [
155
+ s(:call, s(:call, s(:const, :Tempfile), :new), :path).freeze,
156
+ s(:call, s(:call, s(:const, :Tempfile), :create), :path).freeze
157
+ ].freeze
155
158
 
156
159
  def temp_file_path? exp
157
- exp == TEMP_FILE_PATH
160
+ TEMP_FILE_PATH.include? exp
158
161
  end
159
162
 
160
163
  #Report a warning
@@ -101,6 +101,11 @@ class Brakeman::CheckRender < Brakeman::BaseCheck
101
101
  def renderable? exp
102
102
  return false unless call?(exp) and constant?(exp.target)
103
103
 
104
+ if exp.method == :with_content
105
+ exp = exp.target
106
+ end
107
+
108
+ return false unless constant?(exp.target)
104
109
  target_class_name = class_name(exp.target)
105
110
  known_renderable_class?(target_class_name) or tracker.find_method(:render_in, target_class_name)
106
111
  end
@@ -188,14 +188,20 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
188
188
  when :find_by_sql, :count_by_sql
189
189
  check_by_sql_arguments call.first_arg
190
190
  when :calculate
191
- check_find_arguments call.third_arg
191
+ if call.num_args > 2
192
+ unsafe_sql?(call.second_arg) or check_find_arguments(call.third_arg)
193
+ elsif call.num_args > 1
194
+ unsafe_sql?(call.second_arg)
195
+ end
192
196
  when :last, :first, :all
193
197
  check_find_arguments call.first_arg
194
198
  when :average, :count, :maximum, :minimum, :sum
195
- if call.length > 5
196
- unsafe_sql?(call.first_arg) or check_find_arguments(call.last_arg)
199
+ if call.num_args > 1
200
+ if version_between?("0.0.0", "4.9.9") # In Rails 5+ these do not accept multiple arguments
201
+ check_find_arguments(call.first_arg) or check_find_arguments(call.second_arg)
202
+ end
197
203
  else
198
- check_find_arguments call.last_arg
204
+ check_find_arguments call.first_arg
199
205
  end
200
206
  when :where, :rewhere, :having, :find_by, :find_by!, :find_or_create_by, :find_or_create_by!, :find_or_initialize_by,:not, :delete_by, :destroy_by
201
207
  check_query_arguments call.arglist
@@ -315,6 +321,9 @@ class Brakeman::CheckSQL < Brakeman::BaseCheck
315
321
  check_hash_keys arg
316
322
  elsif node_type? arg, :lit, :str
317
323
  nil
324
+ elsif node_type? arg, :or
325
+ check_query_arguments(arg.lhs) or
326
+ check_query_arguments(arg.rhs)
318
327
  else
319
328
  #Hashes are safe...but we check above for hash, so...?
320
329
  unsafe_sql? arg, :ignore_hash
@@ -68,6 +68,10 @@ module Brakeman
68
68
  self.absolute
69
69
  end
70
70
 
71
+ # Required for Pathname compatibility.
72
+ # Ruby 3.5+ requires Pathname#initialize to receive a String or an object with to_path method.
73
+ alias to_path to_str
74
+
71
75
  # Returns a string with the absolute path.
72
76
  def to_s
73
77
  self.to_str
@@ -436,6 +436,12 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
436
436
  exp.method == :open
437
437
  end
438
438
 
439
+ def temp_file_create? exp
440
+ call? exp and
441
+ exp.target == TEMP_FILE_CLASS and
442
+ exp.method == :create
443
+ end
444
+
439
445
  def temp_file_new line
440
446
  s(:call, TEMP_FILE_CLASS, :new).line(line)
441
447
  end
@@ -465,6 +471,9 @@ class Brakeman::AliasProcessor < Brakeman::SexpProcessor
465
471
  elsif temp_file_open? call
466
472
  local = Sexp.new(:lvar, block_args.last)
467
473
  env.current[local] = temp_file_new(exp.line)
474
+ elsif temp_file_create? call
475
+ local = Sexp.new(:lvar, block_args.last)
476
+ env.current[local] = temp_file_new(exp.line)
468
477
  else
469
478
  block_args.each do |e|
470
479
  #Force block arg(s) to be local
@@ -166,7 +166,16 @@ class Brakeman::HamlTemplateProcessor < Brakeman::TemplateProcessor
166
166
  def haml_attribute_builder? exp
167
167
  call? exp and
168
168
  exp.target == ATTRIBUTE_BUILDER and
169
- exp.method == :build
169
+ escaped_builder_method? exp
170
+ end
171
+
172
+ def escaped_builder_method? exp
173
+ case exp.method
174
+ when :build, :build_aria, :build_boolean, :build_data, :build_id, :escape_html
175
+ true? exp.first_arg
176
+ else
177
+ false
178
+ end
170
179
  end
171
180
 
172
181
  def fix_textareas? exp
@@ -51,7 +51,7 @@ class Brakeman::Rails2ConfigProcessor < Brakeman::BasicProcessor
51
51
  if exp.target == RAILS_CONFIG
52
52
  #Get rid of '=' at end
53
53
  attribute = exp.method.to_s[0..-2].to_sym
54
- if exp.args.length > 1
54
+ if exp.num_args > 1
55
55
  #Multiple arguments?...not sure if this will ever happen
56
56
  @tracker.config.rails[attribute] = exp.args
57
57
  else
@@ -78,7 +78,7 @@ class Brakeman::Rails3ConfigProcessor < Brakeman::BasicProcessor
78
78
  if exp.target == RAILS_CONFIG
79
79
  #Get rid of '=' at end
80
80
  attribute = exp.method.to_s[0..-2].to_sym
81
- if exp.args.length > 1
81
+ if exp.num_args > 1
82
82
  #Multiple arguments?...not sure if this will ever happen
83
83
  @tracker.config.rails[attribute] = exp.args
84
84
  else
@@ -92,7 +92,7 @@ module Brakeman
92
92
  if system("which less > /dev/null")
93
93
  less_help = `less -?`
94
94
 
95
- ["-R ", "-F ", "-X "].each do |opt|
95
+ ["-R ", "-F ", "-X ", " --wordwrap"].each do |opt|
96
96
  if less_help.include? opt
97
97
  @less_options << opt
98
98
  end
@@ -51,7 +51,7 @@
51
51
  <tr>
52
52
  <td><%= tracker.app_path %></td>
53
53
  <td><%= rails_version %></td>
54
- <td><%= brakeman_version %>
54
+ <td><%= brakeman_version %></td>
55
55
  <td>
56
56
  <%= tracker.start_time %><br><br>
57
57
  <%= tracker.duration %> seconds
@@ -1,3 +1,3 @@
1
1
  module Brakeman
2
- Version = "7.1.0"
2
+ Version = "7.1.2"
3
3
  end
@@ -172,6 +172,20 @@ class Sexp
172
172
  self[2] = name
173
173
  end
174
174
 
175
+ # Number of arguments in a method call.
176
+ def num_args
177
+ expect :call, :attrasgn, :safe_call, :safe_attrasgn, :super, :zsuper
178
+
179
+ case self.node_type
180
+ when :call, :attrasgn, :safe_call, :safe_attrasgn
181
+ self.length - 3
182
+ when :super
183
+ self.length - 1
184
+ when :zsuper
185
+ 0
186
+ end
187
+ end
188
+
175
189
  #Sets the arglist in a method call.
176
190
  def arglist= exp
177
191
  expect :call, :attrasgn, :safe_call, :safe_attrasgn
metadata CHANGED
@@ -1,17 +1,31 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: brakeman-lib
3
3
  version: !ruby/object:Gem::Version
4
- version: 7.1.0
4
+ version: 7.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Justin Collins
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-07-18 00:00:00.000000000 Z
11
+ date: 2025-12-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '6.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '6.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: minitest-ci
15
29
  requirement: !ruby/object:Gem::Requirement
16
30
  requirements:
17
31
  - - ">="
@@ -25,7 +39,7 @@ dependencies:
25
39
  - !ruby/object:Gem::Version
26
40
  version: '0'
27
41
  - !ruby/object:Gem::Dependency
28
- name: minitest-ci
42
+ name: minitest-mock
29
43
  requirement: !ruby/object:Gem::Requirement
30
44
  requirements:
31
45
  - - ">="
@@ -72,14 +86,14 @@ dependencies:
72
86
  requirements:
73
87
  - - "~>"
74
88
  - !ruby/object:Gem::Version
75
- version: 3.20.2
89
+ version: 3.22.0
76
90
  type: :runtime
77
91
  prerelease: false
78
92
  version_requirements: !ruby/object:Gem::Requirement
79
93
  requirements:
80
94
  - - "~>"
81
95
  - !ruby/object:Gem::Version
82
- version: 3.20.2
96
+ version: 3.22.0
83
97
  - !ruby/object:Gem::Dependency
84
98
  name: sexp_processor
85
99
  requirement: !ruby/object:Gem::Requirement
@@ -463,7 +477,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
463
477
  requirements:
464
478
  - - ">="
465
479
  - !ruby/object:Gem::Version
466
- version: 2.5.0
480
+ version: 3.2.0
467
481
  required_rubygems_version: !ruby/object:Gem::Requirement
468
482
  requirements:
469
483
  - - ">="