brakeman-min 8.0.6 → 8.1.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 +4 -4
- data/CHANGES.md +12 -0
- data/lib/brakeman/app_tree.rb +14 -3
- data/lib/brakeman/checks/check_validation_regex.rb +3 -2
- data/lib/brakeman/options.rb +2 -2
- data/lib/brakeman/parsers/template_parser.rb +9 -2
- data/lib/brakeman/processors/haml_template_processor.rb +1 -1
- data/lib/brakeman/processors/model_processor.rb +18 -5
- data/lib/brakeman/report/report_sonar.rb +53 -19
- data/lib/brakeman/version.rb +1 -1
- data/lib/brakeman/warning.rb +1 -2
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5617f56b1375fc31177923381488b7a018322e9508712cbb6fcaef3ebb2c8190
|
|
4
|
+
data.tar.gz: 90f1ec8f568eebe6ae6a5f058395dbb035dcd6a5cfaf55b62c3542d398fb693e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e129e0b2729108abf747ec6c7b0077d1df3dae70be874e9a037fde99ac582103c42153efd63ba75f0440152af8b7b143eff3ff36682142755edbbd8ad2590741
|
|
7
|
+
data.tar.gz: 58733048687ad8cbac4e17d34e0c92e5d29955d6e72bfc9b80586d46167f082d26d07318946af366a8297e27b7e67eeac5f1620355e243d34d65e605312baf07
|
data/CHANGES.md
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
# 8.1.0 - 2026-09-30
|
|
2
|
+
|
|
3
|
+
* Better help and error message for `--ensure-latest`
|
|
4
|
+
* Fix frozen string error (Shai Coleman)
|
|
5
|
+
* Update Sonar report format (fangxing)
|
|
6
|
+
* Fix frozen `src` string error
|
|
7
|
+
* Recognize `Haml::AttributeBuilder.build_class` as an escaped output (Yuriy Tumanov)
|
|
8
|
+
* Include regex code in validation warnings (Eliot Sykes)
|
|
9
|
+
* Check validation regexes in non-activerecord models (Eliot Sykes)
|
|
10
|
+
* Skip top-level vendor directory before recursive globbing (Conor O'Donnell)
|
|
11
|
+
* Support Rails 7.1+ positional enum syntax in SQL injection check (Michael Vogl/Yuriy Tumanov)
|
|
12
|
+
|
|
1
13
|
# 8.0.6 - 2026-08-13
|
|
2
14
|
|
|
3
15
|
* Fix EOL date for Rails 8.0 (yeaseul-kim)
|
data/lib/brakeman/app_tree.rb
CHANGED
|
@@ -64,6 +64,8 @@ module Brakeman
|
|
|
64
64
|
@only_files = init_options[:only_files]
|
|
65
65
|
@additional_libs_path = init_options[:additional_libs_path] || []
|
|
66
66
|
@engine_paths = init_options[:engine_paths] || []
|
|
67
|
+
@additional_libs_path_pairs = @additional_libs_path.map { |p| [p, expand_path(p)] }
|
|
68
|
+
@engine_path_pairs = @engine_paths.map { |p| [p, expand_path(p)] }
|
|
67
69
|
@absolute_engine_paths = @engine_paths.select { |path| path.start_with?(File::SEPARATOR) }
|
|
68
70
|
@relative_engine_paths = @engine_paths - @absolute_engine_paths
|
|
69
71
|
@skip_vendor = init_options[:skip_vendor]
|
|
@@ -251,7 +253,10 @@ module Brakeman
|
|
|
251
253
|
paths.reject do |path|
|
|
252
254
|
relative_path = path.relative
|
|
253
255
|
|
|
254
|
-
if @skip_vendor and
|
|
256
|
+
if @skip_vendor and
|
|
257
|
+
(relative_path == 'vendor' || relative_path.include?('vendor/')) and
|
|
258
|
+
!in_engine_paths?(path) and
|
|
259
|
+
!in_add_libs_paths?(path)
|
|
255
260
|
true
|
|
256
261
|
else
|
|
257
262
|
match_path EXCLUDED_PATHS, path
|
|
@@ -260,11 +265,17 @@ module Brakeman
|
|
|
260
265
|
end
|
|
261
266
|
|
|
262
267
|
def in_engine_paths?(path)
|
|
263
|
-
@
|
|
268
|
+
@engine_path_pairs.any? do |original, expanded|
|
|
269
|
+
path.absolute.include?(original) ||
|
|
270
|
+
expanded.start_with?("#{path.absolute}#{File::SEPARATOR}")
|
|
271
|
+
end
|
|
264
272
|
end
|
|
265
273
|
|
|
266
274
|
def in_add_libs_paths?(path)
|
|
267
|
-
@
|
|
275
|
+
@additional_libs_path_pairs.any? do |original, expanded|
|
|
276
|
+
path.absolute.include?(original) ||
|
|
277
|
+
expanded.start_with?("#{path.absolute}#{File::SEPARATOR}")
|
|
278
|
+
end
|
|
268
279
|
end
|
|
269
280
|
|
|
270
281
|
def match_path files, path
|
|
@@ -16,7 +16,7 @@ class Brakeman::CheckValidationRegex < Brakeman::BaseCheck
|
|
|
16
16
|
FORMAT = Sexp.new(:lit, :format)
|
|
17
17
|
|
|
18
18
|
def run_check
|
|
19
|
-
|
|
19
|
+
tracker.models.each do |name, model|
|
|
20
20
|
@current_model = model
|
|
21
21
|
format_validations = model.options[:validates_format_of]
|
|
22
22
|
|
|
@@ -92,7 +92,8 @@ class Brakeman::CheckValidationRegex < Brakeman::BaseCheck
|
|
|
92
92
|
:message => msg("Insufficient validation for ", msg_code(get_name validator), " using ", msg_code(regex.inspect), ". Use ", msg_code("\\A"), " and ", msg_code("\\z"), " as anchors"),
|
|
93
93
|
:line => value.line,
|
|
94
94
|
:confidence => :high,
|
|
95
|
-
:cwe_id => [777]
|
|
95
|
+
:cwe_id => [777],
|
|
96
|
+
:code => validator
|
|
96
97
|
end
|
|
97
98
|
end
|
|
98
99
|
|
data/lib/brakeman/options.rb
CHANGED
|
@@ -63,9 +63,9 @@ module Brakeman::Options
|
|
|
63
63
|
options[:exit_on_error] = exit_on_error
|
|
64
64
|
end
|
|
65
65
|
|
|
66
|
-
opts.on "--ensure-latest [DAYS]", Integer, "Fail when Brakeman is outdated. Optionally set minimum age in days." do |days|
|
|
66
|
+
opts.on "--ensure-latest [DAYS]", Integer, "Fail when Brakeman is outdated. Optionally set minimum age in days (1-15)." do |days|
|
|
67
67
|
if days and not (1..15).include? days
|
|
68
|
-
raise OptionParser::InvalidArgument
|
|
68
|
+
raise OptionParser::InvalidArgument, "Minimum age must be 1-15 days."
|
|
69
69
|
end
|
|
70
70
|
|
|
71
71
|
options[:ensure_latest] = days || true
|
|
@@ -56,8 +56,15 @@ module Brakeman
|
|
|
56
56
|
else
|
|
57
57
|
ERB.new(text, nil, '-').src
|
|
58
58
|
end
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
|
|
60
|
+
# Encoding comment at the beginning throws off line numbers
|
|
61
|
+
# but the string is frozen in ERB 6.0.2+, so we don't want to
|
|
62
|
+
# unnecessarily duplicate the string
|
|
63
|
+
if src.start_with? '#'
|
|
64
|
+
src.sub(/^#.*\n/, '')
|
|
65
|
+
else
|
|
66
|
+
src
|
|
67
|
+
end
|
|
61
68
|
end
|
|
62
69
|
end
|
|
63
70
|
|
|
@@ -171,7 +171,7 @@ class Brakeman::HamlTemplateProcessor < Brakeman::TemplateProcessor
|
|
|
171
171
|
|
|
172
172
|
def escaped_builder_method? exp
|
|
173
173
|
case exp.method
|
|
174
|
-
when :build, :build_aria, :build_boolean, :build_data, :build_id, :escape_html
|
|
174
|
+
when :build, :build_aria, :build_boolean, :build_class, :build_data, :build_id, :escape_html
|
|
175
175
|
true? exp.first_arg
|
|
176
176
|
else
|
|
177
177
|
false
|
|
@@ -91,12 +91,25 @@ class Brakeman::ModelProcessor < Brakeman::BaseProcessor
|
|
|
91
91
|
end
|
|
92
92
|
|
|
93
93
|
def add_enum_method call
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
94
|
+
if call.second_arg.nil?
|
|
95
|
+
# Rails < 7.1 syntax: enum status: { active: 0, archived: 1 }
|
|
96
|
+
arg = call.first_arg
|
|
97
|
+
return unless hash? arg
|
|
98
|
+
return unless symbol? arg[1]
|
|
99
|
+
|
|
100
|
+
enum_name = arg[1].value # first key
|
|
101
|
+
enums = arg[2] # first value
|
|
102
|
+
else
|
|
103
|
+
# Rails >= 7.1 syntax: enum :status, { active: 0, archived: 1 }
|
|
104
|
+
first_arg = call.first_arg
|
|
105
|
+
second_arg = call.second_arg
|
|
106
|
+
return unless symbol? first_arg
|
|
107
|
+
return unless hash? second_arg or array? second_arg
|
|
108
|
+
|
|
109
|
+
enum_name = first_arg.value
|
|
110
|
+
enums = second_arg
|
|
111
|
+
end
|
|
97
112
|
|
|
98
|
-
enum_name = arg[1].value # first key
|
|
99
|
-
enums = arg[2] # first value
|
|
100
113
|
enums_name = pluralize(enum_name.to_s).to_sym
|
|
101
114
|
|
|
102
115
|
call_line = call.line
|
|
@@ -1,38 +1,72 @@
|
|
|
1
1
|
class Brakeman::Report::Sonar < Brakeman::Report::Base
|
|
2
2
|
def generate_report
|
|
3
|
+
warnings = all_warnings
|
|
3
4
|
report_object = {
|
|
4
|
-
|
|
5
|
+
rules: rules_json(warnings),
|
|
6
|
+
issues: warnings.map { |warning| issue_json(warning) }
|
|
5
7
|
}
|
|
6
|
-
|
|
8
|
+
JSON.pretty_generate report_object
|
|
7
9
|
end
|
|
8
|
-
|
|
10
|
+
|
|
9
11
|
private
|
|
10
|
-
|
|
12
|
+
|
|
13
|
+
def rules_json(warnings)
|
|
14
|
+
warnings
|
|
15
|
+
.each_with_object({}) do |w, unique_warnings|
|
|
16
|
+
unique_warnings[[w.warning_code, w.confidence]] ||= w
|
|
17
|
+
end
|
|
18
|
+
.values
|
|
19
|
+
.map do |w|
|
|
20
|
+
{
|
|
21
|
+
id: rule_id(w),
|
|
22
|
+
name: w.warning_type.to_s,
|
|
23
|
+
description: w.link,
|
|
24
|
+
engineId: "Brakeman",
|
|
25
|
+
cleanCodeAttribute: "TRUSTWORTHY",
|
|
26
|
+
type: "VULNERABILITY",
|
|
27
|
+
severity: rule_severity_for(w.confidence),
|
|
28
|
+
impacts: [
|
|
29
|
+
{
|
|
30
|
+
softwareQuality: "SECURITY",
|
|
31
|
+
severity: impact_severity_for(w.confidence)
|
|
32
|
+
}
|
|
33
|
+
]
|
|
34
|
+
}
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
11
38
|
def issue_json(warning)
|
|
12
39
|
{
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
type: "VULNERABILITY",
|
|
16
|
-
severity: severity_level_for(warning.confidence),
|
|
40
|
+
ruleId: rule_id(warning),
|
|
41
|
+
effortMinutes: (4 - warning.confidence) * 15,
|
|
17
42
|
primaryLocation: {
|
|
18
43
|
message: warning.message,
|
|
19
44
|
filePath: warning.file.relative,
|
|
20
45
|
textRange: {
|
|
21
|
-
|
|
22
|
-
|
|
46
|
+
startLine: warning.line || 1,
|
|
47
|
+
endLine: warning.line || 1
|
|
23
48
|
}
|
|
24
|
-
}
|
|
25
|
-
effortMinutes: (4 - warning.confidence) * 15
|
|
49
|
+
}
|
|
26
50
|
}
|
|
27
51
|
end
|
|
28
52
|
|
|
29
|
-
def
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
53
|
+
def rule_id(warning)
|
|
54
|
+
"BRAKEMAN_#{warning.warning_code}_#{rule_severity_for(warning.confidence)}"
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def rule_severity_for(confidence)
|
|
58
|
+
case confidence
|
|
59
|
+
when 0 then "CRITICAL"
|
|
60
|
+
when 1 then "MAJOR"
|
|
61
|
+
else "MINOR"
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def impact_severity_for(confidence)
|
|
66
|
+
case confidence
|
|
67
|
+
when 0 then "HIGH"
|
|
68
|
+
when 1 then "MEDIUM"
|
|
69
|
+
else "LOW"
|
|
36
70
|
end
|
|
37
71
|
end
|
|
38
72
|
end
|
data/lib/brakeman/version.rb
CHANGED
data/lib/brakeman/warning.rb
CHANGED
|
@@ -175,7 +175,7 @@ class Brakeman::Warning
|
|
|
175
175
|
def format_with_user_input strip = true, &block
|
|
176
176
|
if self.user_input
|
|
177
177
|
formatted = Brakeman::OutputProcessor.new.format(code, self.user_input, &block)
|
|
178
|
-
formatted.gsub
|
|
178
|
+
formatted = formatted.gsub(/(\t|\r|\n)+/, " ") if strip
|
|
179
179
|
formatted
|
|
180
180
|
else
|
|
181
181
|
format_code
|
|
@@ -321,4 +321,3 @@ class Brakeman::Warning
|
|
|
321
321
|
formatted
|
|
322
322
|
end
|
|
323
323
|
end
|
|
324
|
-
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: brakeman-min
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 8.0
|
|
4
|
+
version: 8.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Justin Collins
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-09-30 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: minitest
|
|
@@ -365,7 +365,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
365
365
|
- !ruby/object:Gem::Version
|
|
366
366
|
version: '0'
|
|
367
367
|
requirements: []
|
|
368
|
-
rubygems_version: 3.
|
|
368
|
+
rubygems_version: 3.5.11
|
|
369
369
|
signing_key:
|
|
370
370
|
specification_version: 4
|
|
371
371
|
summary: Security vulnerability scanner for Ruby on Rails.
|