cms_scanner 0.0.5 → 0.0.6

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: a4df8e5a102999fc7c177b6b99e3b2c31b6753a4
4
- data.tar.gz: 5558b190e7bf8f1b1ea5d13354fdb4ebab2c4b2b
3
+ metadata.gz: 4678e465b2b4eaf41a295ca51d5c8e19036cd608
4
+ data.tar.gz: 4791201f53009021294db6cb8ebbf8a502fe996a
5
5
  SHA512:
6
- metadata.gz: 4e28abacf6e31208804bbdc0e1f61368bcb598d3460f49940476bc8f878b7f9f9d0f2c9e579551ac15abcac69e49cf14e79848e0fe6256aa6c5f6acc91aef11b
7
- data.tar.gz: 49c1f25826da617ab18d36241c63cc2b012faef1a9391fa70297ed309c46a4064f5e6deb11bddf91ff7655f885cfa99852f3e88343eaa2872f2bd13275271643
6
+ metadata.gz: aa604fb6779740c7a82aa02d435b8281ed80bd422cf843660803d1eb12e5544c5b96686c5234d41aad53b61cdf101d4cded4c4731595ca1db9745b16fb78d312
7
+ data.tar.gz: 3fae9b03e48e97719cc01404a1cef60fc418b29137dd2cedf7892923a07ad243a69a3274b50758653f3ca676ad28d85fc69028d343a82145fa19b34b6053a519
data/.gitignore CHANGED
@@ -3,16 +3,5 @@
3
3
  .bundle
4
4
  .config
5
5
  coverage
6
- InstalledFiles
7
- lib/bundler/man
8
6
  pkg
9
- rdoc
10
- spec/reports
11
- test/tmp
12
- test/version_tmp
13
- tmp
14
-
15
- # YARD artifacts
16
- .yardoc
17
- _yardoc
18
- doc/
7
+ Gemfile.lock
data/.rubocop.yml CHANGED
@@ -4,3 +4,5 @@ ClassVars:
4
4
  Enabled: false
5
5
  MethodLength:
6
6
  Max: 15
7
+ Metrics/AbcSize:
8
+ Max: 20
data/.travis.yml CHANGED
@@ -5,6 +5,8 @@ rvm:
5
5
  - 2.1.1
6
6
  - 2.1.2
7
7
  - 2.1.3
8
+ - 2.1.4
9
+ - 2.1.5
8
10
  - ruby-head
9
11
  matrix:
10
12
  allow_failures:
@@ -2,15 +2,17 @@ Interesting Findings: <%= @findings.size %>
2
2
  <% @findings.each do |finding| -%>
3
3
 
4
4
  [+] <%= finding.url %>
5
+ <% if finding.confidence > 0 -%>
5
6
  | Confidence: <%= finding.confidence %>%
7
+ <% end -%>
6
8
  | Found By: <%= finding.found_by %>
7
9
  <% unless (confirmed = finding.confirmed_by).empty? -%>
8
10
  <% if confirmed.size == 1 -%>
9
- | Confirmed By: <%= confirmed.first.found_by %>, <%= confirmed.first.confidence %>% confidence
11
+ | Confirmed By: <%= confirmed.first.found_by %><% if confirmed.first.confidence > 0 %>, <%= confirmed.first.confidence %>% confidence<% end %>
10
12
  <% else -%>
11
13
  | Confirmed By:
12
14
  <% confirmed.each do |c| -%>
13
- | - <%= c.found_by %>, <%= c.confidence %>% confidence
15
+ | - <%= c.found_by %><% if c.confidence > 0 %>, <%= c.confidence %>% confidence<% end %>
14
16
  <% end -%>
15
17
  <% end -%>
16
18
  <% end -%>
@@ -1,3 +1,3 @@
1
1
  "stop_time": <%= @stop_time.to_i %>,
2
- "elapsed": <%= @elapsed %>,
3
- "used_memory": <%= @used_memory %>,
2
+ "elapsed": <%= @elapsed.to_i %>,
3
+ "used_memory": <%= @used_memory.to_i %>,
@@ -1,3 +1,3 @@
1
1
  "start_time": <%= @start_time.to_i %>,
2
- "start_memory": <%= @start_memory %>,
3
- "target_url": "<%= @url %>",
2
+ "start_memory": <%= @start_memory.to_i %>,
3
+ "target_url": <%= @url.to_s.to_json %>,
@@ -1 +1,25 @@
1
- "todo": "Not yet done",
1
+ "interesting_files": [
2
+ <% unless @findings.empty? -%>
3
+ {
4
+ <% last_index = @findings.size - 1 %>
5
+ <% @findings.each.with_index do |finding, index| -%>
6
+ <%= finding.url.to_s.to_json %>: {
7
+ "found_by": <%= finding.found_by.to_s.to_json %>,
8
+ "confidence": <%= finding.confidence.to_json %>,
9
+ "confirmed_by": [
10
+ <% unless (confirmed = finding.confirmed_by).empty? -%>
11
+ <% c_last_index = confirmed.size - 1 %>
12
+ {
13
+ <% confirmed.each.with_index do |c, i| -%>
14
+ <%= c.found_by.to_s.to_json %>: { "confidence": <%= c.confidence.to_json %> }<% unless i == c_last_index %>,<% end %>
15
+ <% end -%>
16
+ }
17
+ <% end -%>
18
+ ],
19
+ "references": <%= finding.references.to_json %>,
20
+ "interesting_entries": <%= finding.interesting_entries.to_json %>
21
+ }<% unless index == last_index %>,<% end %>
22
+ <% end -%>
23
+ }
24
+ <% end -%>
25
+ ],
data/cms_scanner.gemspec CHANGED
@@ -31,7 +31,7 @@ Gem::Specification.new do |s|
31
31
  s.add_development_dependency 'rspec', '~> 3.1'
32
32
  s.add_development_dependency 'rspec-its'
33
33
  s.add_development_dependency 'bundler', '~> 1.6'
34
- s.add_development_dependency 'rubocop', '~> 0.26'
34
+ s.add_development_dependency 'rubocop', '~> 0.27'
35
35
  s.add_development_dependency 'webmock', '>= 1.18'
36
36
  s.add_development_dependency 'simplecov', '~> 0.9'
37
37
  end
@@ -22,6 +22,11 @@ module CMSScanner
22
22
  @interesting_entries ||= []
23
23
  end
24
24
 
25
+ # @return [ Integer ]
26
+ def confidence
27
+ @confidence ||= 0
28
+ end
29
+
25
30
  # @param [ Hash ] opts
26
31
  # TODO: Maybe use instance_variable_set ?
27
32
  def parse_finding_options(opts = {})
@@ -8,7 +8,12 @@ module CMSScanner
8
8
  next unless found == other
9
9
 
10
10
  found.confirmed_by << other
11
- # TODO: Increase confidence (e.g: (found + other) / 1.5 ?)
11
+
12
+ confidence = (found.confidence + other.confidence) / 1.5
13
+ confidence = 100 if confidence > 100 || other.confidence == 100
14
+
15
+ found.confidence = confidence.floor unless found.confidence == 100
16
+
12
17
  return self
13
18
  end
14
19
 
@@ -17,11 +17,7 @@ module CMSScanner
17
17
  def run(opts = {})
18
18
  each do |finder|
19
19
  symbols_from_mode(opts[:mode]).each do |symbol|
20
- r = finder.send(symbol, opts)
21
-
22
- next unless r
23
-
24
- findings + [*r]
20
+ findings + [*finder.send(symbol, opts)]
25
21
  end
26
22
  end
27
23
 
@@ -1,4 +1,4 @@
1
1
  # Version
2
2
  module CMSScanner
3
- VERSION = '0.0.5'
3
+ VERSION = '0.0.6'
4
4
  end
@@ -22,11 +22,12 @@ describe 'App::Views' do
22
22
  end
23
23
 
24
24
  after do
25
- view_filename = "#{view}.#{formatter.to_s.underscore.downcase}"
26
- controller_dir = controller.class.to_s.demodulize.underscore.downcase
27
- output = File.read(File.join(fixtures, controller_dir, view_filename))
25
+ view_filename = defined?(expected_view) ? expected_view : view
26
+ view_filename = "#{view_filename}.#{formatter.to_s.underscore.downcase}"
27
+ controller_dir = controller.class.to_s.demodulize.underscore.downcase
28
+ expected_output = File.read(File.join(fixtures, controller_dir, view_filename))
28
29
 
29
- expect($stdout).to receive(:puts).with(output)
30
+ expect($stdout).to receive(:puts).with(expected_output)
30
31
 
31
32
  controller.output(view, @tpl_vars)
32
33
  controller.formatter.beautify # Mandatory to be able to test formatter such as JSON
@@ -22,8 +22,8 @@ describe CMSScanner::Scan do
22
22
 
23
23
  describe '#run' do
24
24
  it 'runs the controlllers and calls the formatter#beautify' do
25
- expect(scanner.controllers).to receive(:run)
26
- expect(scanner.formatter).to receive(:beautify)
25
+ expect(scanner.controllers).to receive(:run).ordered
26
+ expect(scanner.formatter).to receive(:beautify).ordered
27
27
  scanner.run
28
28
  end
29
29
 
@@ -37,14 +37,12 @@ describe CMSScanner::Controllers do
37
37
  spec = controller_mod::Spec.new
38
38
  base = controller_mod::Base.new
39
39
 
40
- controllers << spec << base
41
-
42
- # TODO: Any way to test the orders ? (after_scan should reverse the order)
43
- [base, spec].each do |c|
44
- expect(c).to receive(:before_scan)
45
- expect(c).to receive(:run)
46
- expect(c).to receive(:after_scan)
47
- end
40
+ controllers << base << spec
41
+
42
+ [base, spec].each { |c| expect(c).to receive(:before_scan).ordered }
43
+ [base, spec].each { |c| expect(c).to receive(:run).ordered }
44
+ [spec, base].each { |c| expect(c).to receive(:after_scan).ordered }
45
+
48
46
  controllers.run
49
47
  end
50
48
  end
@@ -17,48 +17,84 @@ describe CMSScanner::Finders::IndependentFinders do
17
17
  end
18
18
 
19
19
  before do
20
- finders << CMSScanner::Finders::DummyFinder.new(target) <<
21
- CMSScanner::Finders::NoAggressiveResult.new(target)
20
+ finders <<
21
+ CMSScanner::Finders::DummyFinder.new(target) <<
22
+ CMSScanner::Finders::NoAggressiveResult.new(target)
23
+ end
22
24
 
23
- @found = finders.run(mode: mode)
25
+ describe 'method call orders' do
26
+ after { finders.run(mode: mode) }
24
27
 
25
- expect(@found).to be_a(CMSScanner::Finders::Findings)
28
+ [:passive, :aggressive].each do |current_mode|
29
+ context "when #{current_mode} mode" do
30
+ let(:mode) { current_mode }
26
31
 
27
- @found.each { |f| expect(f).to be_a finding }
28
- end
32
+ it "calls the #{current_mode} method on each finder" do
33
+ finders.each { |f| expect(f).to receive(current_mode).ordered }
34
+ end
35
+ end
36
+ end
29
37
 
30
- context 'when :passive mode' do
31
- let(:mode) { :passive }
38
+ context 'when :mixed mode' do
39
+ let(:mode) { :mixed }
32
40
 
33
- it 'returns 2 results' do
34
- expect(@found.size).to eq 2
35
- expect(@found.first).to eql expected_passive.first
36
- expect(@found.last).to eql expected_passive.last
41
+ it 'calls :passive then :aggressive on each finder' do
42
+ finders.each do |finder|
43
+ [:passive, :aggressive].each do |method|
44
+ expect(finder).to receive(method).ordered
45
+ end
46
+ end
47
+ end
37
48
  end
38
49
  end
39
50
 
40
- context 'when :aggressive mode' do
41
- let(:mode) { :aggressive }
51
+ describe 'returned results' do
52
+ before do
53
+ @found = finders.run(mode: mode)
42
54
 
43
- it 'returns 1 result' do
44
- expect(@found.size).to eq 1
45
- expect(@found.first).to eql expected_aggressive
55
+ expect(@found).to be_a(CMSScanner::Finders::Findings)
56
+
57
+ @found.each { |f| expect(f).to be_a finding }
46
58
  end
47
- end
48
59
 
49
- context 'when :mixed mode' do
50
- let(:mode) { :mixed }
60
+ context 'when :passive mode' do
61
+ let(:mode) { :passive }
51
62
 
52
- it 'returns 2 results' do
53
- expect(@found.size).to eq 2
54
- expect(@found.first).to eql expected_passive.first
55
- expect(@found.first.confirmed_by).to eql [expected_aggressive]
56
- expect(@found.last).to eql expected_passive.last
63
+ it 'returns 2 results' do
64
+ expect(@found.size).to eq 2
65
+ expect(@found.first).to eql expected_passive.first
66
+ expect(@found.last).to eql expected_passive.last
67
+ end
57
68
  end
58
- end
59
69
 
60
- context 'when multiple results returned' do
70
+ context 'when :aggressive mode' do
71
+ let(:mode) { :aggressive }
61
72
 
73
+ it 'returns 1 result' do
74
+ expect(@found.size).to eq 1
75
+ expect(@found.first).to eql expected_aggressive
76
+ end
77
+ end
78
+
79
+ context 'when :mixed mode' do
80
+ let(:mode) { :mixed }
81
+
82
+ it 'returns 2 results' do
83
+ # As the first passive is confirmed by the expected_aggressive, the confidence
84
+ # increases and should be 100% due to the expected_aggressive.confidence
85
+ first_passive = expected_passive.first.dup
86
+ first_passive.confidence = 100
87
+
88
+ expect(@found.size).to eq 2
89
+ expect(@found.first).to eql first_passive
90
+ expect(@found.first.confirmed_by).to eql [expected_aggressive]
91
+ expect(@found.last).to eql expected_passive.last
92
+ end
93
+ end
94
+
95
+ context 'when multiple results returned' do
96
+ xit
97
+ end
62
98
  end
63
99
  end
64
100
 
@@ -1,4 +1,4 @@
1
1
 
2
- [+] Finished: Thu Oct 30 13:02:03 2014
2
+ [+] Finished: Thu Oct 30 12:02:03 2014
3
3
  [+] Memory used: 100 B
4
- [+] Elapsed time: 00:00:03
4
+ [+] Elapsed time: 00:00:02
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "stop_time": 1414670523,
3
- "elapsed": 3,
3
+ "elapsed": 2,
4
4
  "used_memory": 100
5
5
  }
@@ -1,3 +1,3 @@
1
1
  [+] URL: http://ex.lo/
2
- [+] Started: Thu Oct 30 13:02:01 2014
2
+ [+] Started: Thu Oct 30 12:02:01 2014
3
3
 
@@ -0,0 +1 @@
1
+ Interesting Findings: 0
@@ -0,0 +1,5 @@
1
+ {
2
+ "interesting_files": [
3
+
4
+ ]
5
+ }
@@ -1,21 +1,21 @@
1
- Interesting Findings: 3
1
+ Interesting Findings: 4
2
2
 
3
3
  [+] F1
4
4
  | Confidence: 10%
5
5
  | Found By: Spec
6
6
 
7
7
  [+] F2
8
- | Confidence: 10%
8
+ | Confidence: 13%
9
9
  | Found By: Spec
10
10
  | Confirmed By: Spec2, 10% confidence
11
11
  | Reference: R1
12
12
  | Interesting Entry: IE1
13
13
 
14
14
  [+] F3
15
- | Confidence: 10%
15
+ | Confidence: 100%
16
16
  | Found By: Spec
17
17
  | Confirmed By:
18
- | - Spec2, 10% confidence
18
+ | - Spec2, 100% confidence
19
19
  | - Spec3, 10% confidence
20
20
  | References:
21
21
  | - R1
@@ -23,3 +23,7 @@ Interesting Findings: 3
23
23
  | Interesting Entries:
24
24
  | - IE1
25
25
  | - IE2
26
+
27
+ [+] F4
28
+ | Found By: Spec
29
+ | Confirmed By: Spec2
@@ -1,3 +1,75 @@
1
1
  {
2
- "todo": "Not yet done"
2
+ "interesting_files": [
3
+ {
4
+ "F1": {
5
+ "found_by": "Spec",
6
+ "confidence": 10,
7
+ "confirmed_by": [
8
+
9
+ ],
10
+ "references": [
11
+
12
+ ],
13
+ "interesting_entries": [
14
+
15
+ ]
16
+ },
17
+ "F2": {
18
+ "found_by": "Spec",
19
+ "confidence": 13,
20
+ "confirmed_by": [
21
+ {
22
+ "Spec2": {
23
+ "confidence": 10
24
+ }
25
+ }
26
+ ],
27
+ "references": [
28
+ "R1"
29
+ ],
30
+ "interesting_entries": [
31
+ "IE1"
32
+ ]
33
+ },
34
+ "F3": {
35
+ "found_by": "Spec",
36
+ "confidence": 100,
37
+ "confirmed_by": [
38
+ {
39
+ "Spec2": {
40
+ "confidence": 100
41
+ },
42
+ "Spec3": {
43
+ "confidence": 10
44
+ }
45
+ }
46
+ ],
47
+ "references": [
48
+ "R1",
49
+ "R2"
50
+ ],
51
+ "interesting_entries": [
52
+ "IE1",
53
+ "IE2"
54
+ ]
55
+ },
56
+ "F4": {
57
+ "found_by": "Spec",
58
+ "confidence": 0,
59
+ "confirmed_by": [
60
+ {
61
+ "Spec2": {
62
+ "confidence": 0
63
+ }
64
+ }
65
+ ],
66
+ "references": [
67
+
68
+ ],
69
+ "interesting_entries": [
70
+
71
+ ]
72
+ }
73
+ }
74
+ ]
3
75
  }
@@ -13,6 +13,16 @@ shared_examples CMSScanner::Finders::Finding do
13
13
  end
14
14
  end
15
15
 
16
+ describe '#confidence' do
17
+ its(:confidence) { should eql 0 }
18
+
19
+ context 'when already set' do
20
+ before { subject.confidence = 10 }
21
+
22
+ its(:confidence) { should eql 10 }
23
+ end
24
+ end
25
+
16
26
  describe '#parse_finding_options' do
17
27
  xit
18
28
  end
@@ -33,8 +33,7 @@ shared_examples CMSScanner::Target::Platform::PHP do
33
33
  context 'when the body matches a FPD' do
34
34
  {
35
35
  'wp_rss_functions.php' => %w(/short-path/rss-f.php)
36
- }
37
- .each do |file, expected|
36
+ }.each do |file, expected|
38
37
  context "when #{file} body" do
39
38
  let(:body) { File.read(File.join(fixtures, 'fpd', file)) }
40
39
 
@@ -5,8 +5,7 @@ shared_examples 'WordPress::CustomDirectories' do
5
5
  describe '#content_dir' do
6
6
  {
7
7
  default: 'wp-content', https: 'wp-content', custom_w_spaces: 'custom content spaces'
8
- }
9
- .each do |file, expected|
8
+ }.each do |file, expected|
10
9
  it "returns #{expected} for #{file}.html" do
11
10
  fixture = File.join(fixtures, "#{file}.html")
12
11
 
@@ -2,7 +2,8 @@
2
2
  shared_examples 'App::Views::Core' do
3
3
 
4
4
  let(:controller) { CMSScanner::Controller::Core.new }
5
- let(:tpl_vars) { { url: target_url, start_time: Time.parse('2014-10-30 13:02:01 +0100') } }
5
+ let(:start) { Time.at(1_414_670_521).in_time_zone('Europe/London') }
6
+ let(:tpl_vars) { { url: target_url, start_time: start } }
6
7
 
7
8
  describe 'started' do
8
9
  let(:view) { 'started' }
@@ -17,9 +18,9 @@ shared_examples 'App::Views::Core' do
17
18
 
18
19
  it 'outputs the expected string' do
19
20
  @tpl_vars = tpl_vars.merge(
20
- stop_time: Time.parse('2014-10-30 13:02:03 +0100'),
21
+ stop_time: Time.at(1_414_670_523).in_time_zone('Europe/London'),
21
22
  used_memory: 100,
22
- elapsed: 3
23
+ elapsed: 2
23
24
  )
24
25
  end
25
26
  end
@@ -9,15 +9,27 @@ shared_examples 'App::Views::InterestingFiles' do
9
9
  let(:view) { 'findings' }
10
10
  let(:opts) { { confidence: 10, found_by: 'Spec' } }
11
11
 
12
+ context 'when empty results' do
13
+ let(:expected_view) { 'empty' }
14
+
15
+ it 'outputs the expected string' do
16
+ @tpl_vars = tpl_vars.merge(findings: [])
17
+ end
18
+ end
19
+
12
20
  it 'outputs the expected string' do
13
- findings = CMSScanner::Finders::Findings.new <<
21
+ findings = CMSScanner::Finders::Findings.new
22
+
23
+ findings <<
14
24
  interesting_file.new('F1', opts) <<
15
25
  interesting_file.new('F2', opts.merge(references: %w(R1), interesting_entries: %w(IE1))) <<
16
26
  interesting_file.new('F2', opts.merge(found_by: 'Spec2')) <<
17
27
  interesting_file.new('F3',
18
28
  opts.merge(references: %w(R1 R2), interesting_entries: %w(IE1 IE2))) <<
19
- interesting_file.new('F3', opts.merge(found_by: 'Spec2')) <<
20
- interesting_file.new('F3', opts.merge(found_by: 'Spec3'))
29
+ interesting_file.new('F3', opts.merge(found_by: 'Spec2', confidence: 100)) <<
30
+ interesting_file.new('F3', opts.merge(found_by: 'Spec3')) <<
31
+ interesting_file.new('F4', opts.merge(confidence: 0)) <<
32
+ interesting_file.new('F4', opts.merge(confidence: 0, found_by: 'Spec2'))
21
33
 
22
34
  @tpl_vars = tpl_vars.merge(findings: findings)
23
35
  end
data/spec/spec_helper.rb CHANGED
@@ -3,6 +3,7 @@ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
3
  require 'simplecov'
4
4
  require 'rspec/its'
5
5
  require 'webmock/rspec'
6
+ require 'active_support/time'
6
7
 
7
8
  if ENV['TRAVIS']
8
9
  require 'coveralls'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cms_scanner
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - WPScanTeam - Erwan le Rousseau
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-10-31 00:00:00.000000000 Z
11
+ date: 2014-11-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: opt_parse_validator
@@ -142,14 +142,14 @@ dependencies:
142
142
  requirements:
143
143
  - - "~>"
144
144
  - !ruby/object:Gem::Version
145
- version: '0.26'
145
+ version: '0.27'
146
146
  type: :development
147
147
  prerelease: false
148
148
  version_requirements: !ruby/object:Gem::Requirement
149
149
  requirements:
150
150
  - - "~>"
151
151
  - !ruby/object:Gem::Version
152
- version: '0.26'
152
+ version: '0.27'
153
153
  - !ruby/object:Gem::Dependency
154
154
  name: webmock
155
155
  requirement: !ruby/object:Gem::Requirement
@@ -324,6 +324,8 @@ files:
324
324
  - spec/output/core/finished.json
325
325
  - spec/output/core/started.cli_no_colour
326
326
  - spec/output/core/started.json
327
+ - spec/output/interesting_files/empty.cli_no_colour
328
+ - spec/output/interesting_files/empty.json
327
329
  - spec/output/interesting_files/findings.cli_no_colour
328
330
  - spec/output/interesting_files/findings.json
329
331
  - spec/shared_examples.rb
@@ -433,6 +435,8 @@ test_files:
433
435
  - spec/output/core/finished.json
434
436
  - spec/output/core/started.cli_no_colour
435
437
  - spec/output/core/started.json
438
+ - spec/output/interesting_files/empty.cli_no_colour
439
+ - spec/output/interesting_files/empty.json
436
440
  - spec/output/interesting_files/findings.cli_no_colour
437
441
  - spec/output/interesting_files/findings.json
438
442
  - spec/shared_examples.rb