pronto-bundler_audit 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 14598d0b688654057c7bf84f388f5d9881394d916c89e93aabed9f359046fa4e
4
- data.tar.gz: aebe7dc2245ad8459e002bb2e2454343bec3c0f6906ce67b97d310dadeb36cca
3
+ metadata.gz: 2a6328fffd859750def2c69f570ea970ecc44aa1b31362dfa03b5933cde49201
4
+ data.tar.gz: c6c226e11867996c7d19d53089a31e20b87acaebe3593713f11d310f7e1b602b
5
5
  SHA512:
6
- metadata.gz: 107cc7d4a03d1db7cca881a5a0e3f8fc63efa57f43aeb328fc65bcd75eb569e89d5a77d5fd968c02b9904fd7983a5430ce5535e1985c566d061883aba0017369
7
- data.tar.gz: 3047f3525a76613c0199c05353c4a2342434a07e689c586dfd1586a70c533cd263879567b7ebc8f9549bb70f618a83340014316589f0c3710cff78df50cc9d64
6
+ metadata.gz: df67a7343d90292e9b15fdfeb6c75eab64b76b27a98ee1feffb3ac9b2c1ef3f0e20822048a595018904d19655c8c82142635644409e01faaee3fa313fccc5826
7
+ data.tar.gz: 167db3c4bfbd04bec6b25d519f0fd060809de610f899d8e3cc166601baac28ffcc512129ab02496305899df4b7f192fc77a274352f4cc2fcdfcb8f6c846e5edb
data/.rubocop ADDED
@@ -0,0 +1,4 @@
1
+ --display-cop-names
2
+ --display-style-guide
3
+ --extra-details
4
+ --format=fuubar
data/.rubocop.yml ADDED
@@ -0,0 +1,156 @@
1
+ AllCops:
2
+ UseCache: true
3
+ DisplayCopNames: true
4
+ DisplayStyleGuide: true
5
+ ExtraDetails: false
6
+ TargetRubyVersion: 2.5.3
7
+
8
+ Layout/ClassStructure:
9
+ Enabled: true
10
+ Categories:
11
+ module_inclusion:
12
+ - extend
13
+ - include
14
+ - prepend
15
+ attributes:
16
+ - attr_accessor
17
+ - attr_reader
18
+ - attr_writer
19
+ ExpectedOrder:
20
+ - constants
21
+ - module_inclusion
22
+ - attributes
23
+ - public_class_methods
24
+ - initializer
25
+ - public_methods
26
+ - predicates
27
+ - protected_methods
28
+ - private_methods
29
+
30
+ Layout/DotPosition:
31
+ EnforcedStyle: trailing
32
+
33
+ Layout/EmptyLineAfterGuardClause:
34
+ Enabled: true
35
+
36
+ Layout/EndOfLine:
37
+ EnforcedStyle: lf
38
+
39
+ Layout/IndentFirstArgument:
40
+ EnforcedStyle: consistent_relative_to_receiver
41
+
42
+ Layout/IndentFirstArrayElement:
43
+ EnforcedStyle: consistent
44
+
45
+ Layout/IndentFirstHashElement:
46
+ EnforcedStyle: consistent
47
+
48
+ Layout/MultilineAssignmentLayout:
49
+ Enabled: true
50
+
51
+ Layout/MultilineMethodCallBraceLayout:
52
+ EnforcedStyle: same_line
53
+
54
+ Layout/MultilineMethodCallIndentation:
55
+ EnforcedStyle: indented_relative_to_receiver
56
+
57
+ Layout/MultilineMethodDefinitionBraceLayout:
58
+ EnforcedStyle: same_line
59
+
60
+ Layout/MultilineOperationIndentation:
61
+ Enabled: false # Waiting for e.g. `indented_relative_to_receiver`.
62
+
63
+ Lint/AmbiguousOperator:
64
+ Enabled: false # Conflicts with other rules.
65
+
66
+ Lint/AmbiguousRegexpLiteral:
67
+ Enabled: false # Conflicts with other rules.
68
+
69
+ Lint/Void:
70
+ CheckForMethodsWithNoSideEffects: true
71
+
72
+ Metrics/BlockLength:
73
+ ExcludedMethods:
74
+ - new
75
+ - describe # Tests
76
+ - context # Tests
77
+ - ips # Benchmarking
78
+
79
+ Metrics/ClassLength:
80
+ Exclude:
81
+ - "test/**/*"
82
+ - "lib/object_inspector/formatters/templating_formatter.rb"
83
+
84
+ Metrics/LineLength:
85
+ Max: 80
86
+ Exclude:
87
+ - "test/**/*"
88
+ - "object_inspector.gemspec"
89
+
90
+ Naming/UncommunicativeMethodParamName:
91
+ AllowedNames:
92
+ - a
93
+ - b
94
+
95
+ Style/Alias:
96
+ EnforcedStyle: prefer_alias_method
97
+
98
+ Style/BlockDelimiters:
99
+ Enabled: false # Reconsider later.
100
+
101
+ Style/ClassAndModuleChildren:
102
+ AutoCorrect: true
103
+ Exclude:
104
+ - "test/**/*"
105
+
106
+ Style/CollectionMethods:
107
+ Enabled: true
108
+ PreferredMethods:
109
+ collect: map
110
+ collect!: map!
111
+ find_all: select
112
+ detect: detect
113
+ inject: inject
114
+
115
+ Style/EmptyElse:
116
+ # It"s helpful to show intent by including a comment in an else block.
117
+ Enabled: false
118
+
119
+ Style/EmptyMethod:
120
+ EnforcedStyle: expanded
121
+
122
+ Style/ExpandPathArguments:
123
+ Exclude:
124
+ - "object_inspector.gemspec"
125
+
126
+ Style/FormatString:
127
+ Enabled: false # % notation with an Array just reads better sometimes.
128
+
129
+ Style/Lambda:
130
+ EnforcedStyle: literal
131
+
132
+ Style/NumericPredicate:
133
+ Enabled: false # Trying to be welcoming to earlier versions of Ruby.
134
+ # AutoCorrect: true
135
+
136
+ Style/RegexpLiteral:
137
+ EnforcedStyle: mixed
138
+
139
+ Style/RescueStandardError:
140
+ EnforcedStyle: implicit
141
+
142
+ Style/ReturnNil:
143
+ Enabled: true
144
+
145
+ Style/StringMethods:
146
+ Enabled: true
147
+
148
+ Style/SingleLineMethods:
149
+ Exclude:
150
+ - "test/**/*_test.rb"
151
+
152
+ Style/StringLiterals:
153
+ EnforcedStyle: double_quotes
154
+
155
+ Style/StringLiteralsInInterpolation:
156
+ EnforcedStyle: double_quotes
data/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ ### 0.3.0 - 2019-05-03
2
+ - Internal rewrite into smaller objects with full test coverage
3
+ - Switch to using the verbose advisory formatter by default
4
+
1
5
  ### 0.2.1 - 2019-04-30
2
6
  - Fix handling of the Pronto::Git::Patches collection in Pronto::BundlerAudit#run
3
7
  - Ensure an Array is returned by Pronto::BundlerAudit#run, as expected by Pronto
data/Gemfile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  source "https://rubygems.org"
2
4
 
3
5
  # Specify your gem's dependencies in pronto-bundler_audit.gemspec
data/Gemfile.lock CHANGED
@@ -1,14 +1,14 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- pronto-bundler_audit (0.2.1)
4
+ pronto-bundler_audit (0.3.0)
5
5
  bundler-audit (~> 0)
6
6
  pronto (~> 0)
7
7
 
8
8
  GEM
9
9
  remote: https://rubygems.org/
10
10
  specs:
11
- addressable (2.5.2)
11
+ addressable (2.6.0)
12
12
  public_suffix (>= 2.0.2, < 4.0)
13
13
  ansi (1.5.0)
14
14
  ast (2.4.0)
@@ -29,7 +29,6 @@ GEM
29
29
  multi_xml (>= 0.5.2)
30
30
  jaro_winkler (1.5.2)
31
31
  json (2.2.0)
32
- metaclass (0.0.4)
33
32
  method_source (0.9.2)
34
33
  mime-types (3.2.2)
35
34
  mime-types-data (~> 3.2015)
@@ -40,8 +39,7 @@ GEM
40
39
  builder
41
40
  minitest (>= 5.0)
42
41
  ruby-progressbar
43
- mocha (1.8.0)
44
- metaclass (~> 0.0.1)
42
+ much-stub (0.1.0)
45
43
  multi_xml (0.6.0)
46
44
  multipart-post (2.0.0)
47
45
  octokit (4.14.0)
@@ -65,7 +63,7 @@ GEM
65
63
  public_suffix (3.0.3)
66
64
  rainbow (3.0.0)
67
65
  rake (12.3.2)
68
- rubocop (0.68.0)
66
+ rubocop (0.68.1)
69
67
  jaro_winkler (~> 1.5.1)
70
68
  parallel (~> 1.10)
71
69
  parser (>= 2.5, != 2.5.1.1)
@@ -74,9 +72,9 @@ GEM
74
72
  unicode-display_width (>= 1.4.0, < 1.6)
75
73
  ruby-progressbar (1.10.0)
76
74
  rugged (0.28.1)
77
- sawyer (0.8.1)
78
- addressable (>= 2.3.5, < 2.6)
79
- faraday (~> 0.8, < 1.0)
75
+ sawyer (0.8.2)
76
+ addressable (>= 2.3.5)
77
+ faraday (> 0.8, < 2.0)
80
78
  simplecov (0.16.1)
81
79
  docile (~> 1.1)
82
80
  json (>= 1.8, < 3)
@@ -95,7 +93,7 @@ DEPENDENCIES
95
93
  byebug (~> 11)
96
94
  minitest (~> 5)
97
95
  minitest-reporters (~> 1)
98
- mocha (~> 1)
96
+ much-stub (~> 0)
99
97
  pronto-bundler_audit!
100
98
  pry (~> 0)
101
99
  pry-byebug (~> 3)
data/README.md CHANGED
@@ -64,7 +64,6 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
64
64
 
65
65
  ## TODO
66
66
 
67
- * Add more tests
68
67
  * Add configuration for compact vs expanded advisories reporting
69
68
 
70
69
  ## Contributing
data/Rakefile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "bundler/gem_tasks"
2
4
  require "rake/testtask"
3
5
 
@@ -7,4 +9,4 @@ Rake::TestTask.new(:test) do |t|
7
9
  t.test_files = FileList["test/**/*_test.rb"]
8
10
  end
9
11
 
10
- task :default => :test
12
+ task default: :test
data/bin/console CHANGED
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
4
  require "bundler/setup"
4
5
  require "pronto/bundler_audit"
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pronto
4
+ class BundlerAudit
5
+ module AdvisoryFormatters
6
+ # Pronto::BundlerAudit::AdvisoryFormatters::BaseAdvisoryFormatter is an
7
+ # abstract base class for formatting Bundler::Audit::Advisory objects
8
+ # as a String in the context of the given `gem`
9
+ # (Bundler::LazySpecification).
10
+ class BaseAdvisoryFormatter
11
+ # param gem [Bundler::LazySpecification]
12
+ # param advisory [Bundler::Audit::Advisory]
13
+ def initialize(gem:, advisory:)
14
+ @gem = gem
15
+ @advisory = advisory
16
+ end
17
+
18
+ def to_s
19
+ raise NotImplementedError
20
+ end
21
+
22
+ private
23
+
24
+ def gem_name
25
+ @gem.name
26
+ end
27
+
28
+ def gem_version
29
+ @gem.version
30
+ end
31
+
32
+ def advisory_description
33
+ if @advisory.cve
34
+ "CVE-#{@advisory.cve}"
35
+ elsif @advisory.osvdb
36
+ @advisory.osvdb
37
+ end
38
+ end
39
+
40
+ def advisory_criticality
41
+ str = @advisory.criticality.to_s.capitalize
42
+ str = "Unknown" if str.empty?
43
+ str
44
+ end
45
+
46
+ def advisory_url
47
+ @advisory.url
48
+ end
49
+
50
+ def advisory_title
51
+ @advisory.title
52
+ end
53
+
54
+ def advisory_solution
55
+ if any_patched_versions?
56
+ "Upgrade to #{patched_versions}."
57
+ else
58
+ "Remove or disable this gem until a patch is available!"
59
+ end
60
+ end
61
+
62
+ def patched_versions
63
+ @advisory.patched_versions.join(", ")
64
+ end
65
+
66
+ def any_patched_versions?
67
+ !@advisory.patched_versions.empty?
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base_advisory_formatter"
4
+
5
+ module Pronto
6
+ class BundlerAudit
7
+ module AdvisoryFormatters
8
+ # Pronto::BundlerAudit::AdvisoryFormatters::Compact is a compact message
9
+ # formatter for the given gem object and Bundler::Audit::Advisory#advisory
10
+ # object.
11
+ class Compact < BaseAdvisoryFormatter
12
+ def to_s
13
+ [
14
+ "Gem: #{gem_name} v#{gem_version}",
15
+ "#{advisory_criticality} Advisory: #{advisory_title} -- "\
16
+ "#{advisory_description} (#{advisory_url})",
17
+ "Solution: #{advisory_solution}"
18
+ ].join(" | ")
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base_advisory_formatter"
4
+
5
+ module Pronto
6
+ class BundlerAudit
7
+ module AdvisoryFormatters
8
+ # Pronto::BundlerAudit::AdvisoryFormatters::Verbose is a verbose message
9
+ # formatter for the given gem object and Bundler::Audit::Advisory#advisory
10
+ # object.
11
+ class Verbose < BaseAdvisoryFormatter
12
+ def to_s
13
+ [
14
+ "Name: #{gem_name}",
15
+ "Version: #{gem_version}",
16
+ "Advisory: #{advisory_description}",
17
+ "Criticality: #{advisory_criticality}",
18
+ "URL: #{advisory_url}",
19
+ "Title: #{advisory_title}",
20
+ "Solution: #{advisory_solution}"
21
+ ].join("\n")
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "pronto/bundler_audit/scanner"
4
+
5
+ module Pronto
6
+ class BundlerAudit
7
+ # Pronto::BundlerAudit::Auditor:
8
+ # 1. updates the local ruby security database, and then
9
+ # 2. runs {Pronto::BundlerAudit::Scanner#call} on the given `patch`.
10
+ class Auditor
11
+ def initialize(patch)
12
+ @patch = patch
13
+ end
14
+
15
+ # @return (see: #run_scan)
16
+ def call
17
+ update_ruby_advisory_db
18
+ run_scanner
19
+ end
20
+
21
+ private
22
+
23
+ def update_ruby_advisory_db
24
+ Bundler::Audit::Database.update!(quiet: true)
25
+ end
26
+
27
+ # @return [Array>] if no advisories were found
28
+ # @return [Array<Pronto::Message>] if advisories were found
29
+ def run_scanner
30
+ scanner = Scanner.new(@patch)
31
+ scanner.call
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pronto
4
+ class BundlerAudit
5
+ module Results
6
+ # Pronto::BundlerAudit::Results::BaseResult is an abstract base class for
7
+ # the various Bundler::Audit::Scanner::* issue types.
8
+ class BaseResult
9
+ def initialize(scan_result)
10
+ @scan_result = scan_result
11
+ @gem = scan_result.gem
12
+ @advisory = scan_result.advisory
13
+ end
14
+
15
+ def call
16
+ report_result
17
+ end
18
+
19
+ private
20
+
21
+ def report_result
22
+ raise NotImplementedError
23
+ end
24
+
25
+ def build_message(message, level:, line:)
26
+ Message.new(
27
+ GEMFILE_LOCK_FILENAME,
28
+ line,
29
+ level,
30
+ message,
31
+ nil,
32
+ Pronto::BundlerAudit)
33
+ end
34
+
35
+ def message
36
+ raise NotImplementedError
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base_result"
4
+
5
+ module Pronto
6
+ class BundlerAudit
7
+ module Results
8
+ # Pronto::BundlerAudit::Results::InsecureSource builds a Pronto::Message
9
+ # for Bundler::Audit::Scanner::InsecureSource issues.
10
+ class InsecureSource < BaseResult
11
+ private
12
+
13
+ def report_result
14
+ build_message(
15
+ message,
16
+ line: nil,
17
+ level: :warning)
18
+ end
19
+
20
+ def message
21
+ "Insecure Source URI found: #{@scan_result.source}"
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base_result"
4
+ require "pronto/bundler_audit/advisory_formatters/verbose"
5
+ require "pronto/bundler_audit/advisory_formatters/compact"
6
+
7
+ module Pronto
8
+ class BundlerAudit
9
+ module Results
10
+ # Pronto::BundlerAudit::Results::UnpatchedGem builds a Pronto::Message for
11
+ # Bundler::Audit::Scanner::UnpatchedGem issues.
12
+ class UnpatchedGem < BaseResult
13
+ def initialize(scan_result, patch:)
14
+ super(scan_result)
15
+ @patch = patch
16
+ end
17
+
18
+ private
19
+
20
+ def report_result
21
+ build_message(
22
+ message,
23
+ level: :error,
24
+ line: find_relevant_line)
25
+ end
26
+
27
+ # @return [Pronto::Git::Line]
28
+ def find_relevant_line
29
+ first_added_line_for_affected_gem_name(@gem.name)
30
+ end
31
+
32
+ # @return [Pronto::Git::Line]
33
+ def first_added_line_for_affected_gem_name(gem_name)
34
+ @patch.added_lines.detect { |line| line.content.include?(gem_name) }
35
+ end
36
+
37
+ def message
38
+ advisory_formatter.to_s
39
+ end
40
+
41
+ def advisory_formatter
42
+ # TODO: Switch type based on configuration options, once available.
43
+ AdvisoryFormatters::Verbose.new(gem: @gem, advisory: @advisory)
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "results/insecure_source"
4
+ require_relative "results/unpatched_gem"
5
+
6
+ module Pronto
7
+ class BundlerAudit
8
+ # Pronto::BundlerAudit::Scanner runs runs Bundler::Audit::Scanner#scan on
9
+ # the given patch and then calls a {Pronto::BundlerAudit::BaseResult} based
10
+ # for each scan result.
11
+ class Scanner
12
+ def initialize(patch)
13
+ @patch = patch
14
+ end
15
+
16
+ # @return [Array>] if no advisories were found
17
+ # @return [Array<Pronto::Message>] if advisories were found)
18
+ def call
19
+ run_scan
20
+ end
21
+
22
+ private
23
+
24
+ def run_scan
25
+ run_scanner.map do |scan_result|
26
+ match_result(scan_result).call
27
+ end
28
+ end
29
+
30
+ def run_scanner
31
+ Bundler::Audit::Scanner.new.scan
32
+ end
33
+
34
+ def match_result(scan_result)
35
+ case scan_result
36
+ when Bundler::Audit::Scanner::InsecureSource
37
+ Results::InsecureSource.new(scan_result, patch: @patch)
38
+ when Bundler::Audit::Scanner::UnpatchedGem
39
+ Results::UnpatchedGem.new(scan_result, patch: @patch)
40
+ else
41
+ raise ArgumentError, "Unexpected type: #{scan_result.class}"
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -1,6 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Pronto
2
4
  # Pronto::BundlerAuditVersion
3
5
  module BundlerAuditVersion
4
- VERSION = "0.2.1"
6
+ VERSION = "0.3.0"
5
7
  end
6
8
  end
@@ -1,8 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "pronto"
2
4
  require "bundler/audit/database"
3
5
  require "bundler/audit/scanner"
4
- require "pronto/bundler_audit/version"
5
- require "pronto/bundler_audit/patch_handler"
6
6
 
7
7
  module Pronto
8
8
  # Pronto::BundlerAudit is a Pronto::Runner that:
@@ -12,13 +12,13 @@ module Pronto
12
12
  # 3. Runs bundle-audit to scan the Gemfile.lock
13
13
  # 4. Returns an Array of Pronto::Message objects if any advisories are found
14
14
  class BundlerAudit < Runner
15
- GEMFILE_LOCK_FILENAME = "Gemfile.lock".freeze
15
+ GEMFILE_LOCK_FILENAME = "Gemfile.lock"
16
16
 
17
17
  # @return [Array] per Pronto expectation
18
18
  def run
19
19
  if (patch = find_relevant_patch)
20
- patch_handler = PatchHandler.new(patch, runner: self)
21
- patch_handler.call
20
+ auditor = Auditor.new(patch)
21
+ auditor.call
22
22
  else
23
23
  []
24
24
  end
@@ -38,3 +38,6 @@ module Pronto
38
38
  end
39
39
  end
40
40
  end
41
+
42
+ require "pronto/bundler_audit/version"
43
+ require "pronto/bundler_audit/auditor"
@@ -1,4 +1,6 @@
1
- lib = File.expand_path("../lib", __FILE__)
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path("lib", __dir__)
2
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
5
  require "pronto/bundler_audit/version"
4
6
 
@@ -8,40 +10,31 @@ Gem::Specification.new do |spec|
8
10
  spec.authors = ["Paul Dobbins"]
9
11
  spec.email = ["paul.dobbins@icloud.com"]
10
12
 
11
- spec.summary = %q{Pronto runner for bundler-audit, patch-level verification for bundler.}
13
+ spec.summary =
14
+ "Pronto runner for bundler-audit, patch-level verification for bundler."
12
15
  spec.homepage = "http://github.com/pdobb/pronto-bundler_audit"
13
16
  spec.license = "MIT"
14
17
 
15
- # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
16
- # to allow pushing to a single host or delete this section to allow pushing to any host.
17
- # if spec.respond_to?(:metadata)
18
- # spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
19
-
20
- # spec.metadata["homepage_uri"] = spec.homepage
21
- # spec.metadata["source_code_uri"] = "https://github.com/pdobb/pronto-bundler_audit"
22
- # spec.metadata["changelog_uri"] = "https://github.com/pdobb/pronto-bundler_audit/blob/master/CHANGELOG.md"
23
- # else
24
- # raise "RubyGems 2.0 or newer is required to protect against " \
25
- # "public gem pushes."
26
- # end
27
-
28
18
  # Specify which files should be added to the gem when it is released.
29
- # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
30
- spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
31
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
19
+ # The `git ls-files -z` loads the files in the RubyGem that have been added
20
+ # into git.
21
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
22
+ `git ls-files -z`.split("\x0").reject { |f|
23
+ f.match(%r{^(test|spec|features)/})
24
+ }
32
25
  end
33
26
  spec.bindir = "exe"
34
27
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
35
28
  spec.require_paths = ["lib"]
36
29
 
37
- spec.add_runtime_dependency "pronto", "~> 0"
38
30
  spec.add_runtime_dependency "bundler-audit", "~> 0"
31
+ spec.add_runtime_dependency "pronto", "~> 0"
39
32
 
40
33
  spec.add_development_dependency "bundler", "~> 2"
41
34
  spec.add_development_dependency "byebug", "~> 11"
42
35
  spec.add_development_dependency "minitest", "~> 5"
43
36
  spec.add_development_dependency "minitest-reporters", "~> 1"
44
- spec.add_development_dependency "mocha", "~> 1"
37
+ spec.add_development_dependency "much-stub", "~> 0"
45
38
  spec.add_development_dependency "pry", "~> 0"
46
39
  spec.add_development_dependency "pry-byebug", "~> 3"
47
40
  spec.add_development_dependency "rake", "~> 12"
metadata CHANGED
@@ -1,17 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pronto-bundler_audit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paul Dobbins
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-04-30 00:00:00.000000000 Z
11
+ date: 2019-05-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: pronto
14
+ name: bundler-audit
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
@@ -25,7 +25,7 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
- name: bundler-audit
28
+ name: pronto
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
@@ -95,19 +95,19 @@ dependencies:
95
95
  - !ruby/object:Gem::Version
96
96
  version: '1'
97
97
  - !ruby/object:Gem::Dependency
98
- name: mocha
98
+ name: much-stub
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
101
  - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: '1'
103
+ version: '0'
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
108
  - - "~>"
109
109
  - !ruby/object:Gem::Version
110
- version: '1'
110
+ version: '0'
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: pry
113
113
  requirement: !ruby/object:Gem::Requirement
@@ -192,6 +192,8 @@ extensions: []
192
192
  extra_rdoc_files: []
193
193
  files:
194
194
  - ".gitignore"
195
+ - ".rubocop"
196
+ - ".rubocop.yml"
195
197
  - ".travis.yml"
196
198
  - CHANGELOG.md
197
199
  - Gemfile
@@ -204,7 +206,14 @@ files:
204
206
  - images/github-check.png
205
207
  - images/github-comment.png
206
208
  - lib/pronto/bundler_audit.rb
207
- - lib/pronto/bundler_audit/patch_handler.rb
209
+ - lib/pronto/bundler_audit/advisory_formatters/base_advisory_formatter.rb
210
+ - lib/pronto/bundler_audit/advisory_formatters/compact.rb
211
+ - lib/pronto/bundler_audit/advisory_formatters/verbose.rb
212
+ - lib/pronto/bundler_audit/auditor.rb
213
+ - lib/pronto/bundler_audit/results/base_result.rb
214
+ - lib/pronto/bundler_audit/results/insecure_source.rb
215
+ - lib/pronto/bundler_audit/results/unpatched_gem.rb
216
+ - lib/pronto/bundler_audit/scanner.rb
208
217
  - lib/pronto/bundler_audit/version.rb
209
218
  - pronto-bundler_audit.gemspec
210
219
  homepage: http://github.com/pdobb/pronto-bundler_audit
@@ -1,165 +0,0 @@
1
- module Pronto
2
- class BundlerAudit < Runner
3
- # Pronto::BundlerAudit::PatchHandler runs Bundle Audit on the given patch
4
- # and returns an Array of Pronto::Message objects if any advisories are
5
- # found.
6
- class PatchHandler
7
- def initialize(patch, runner:)
8
- @patch = patch
9
- @runner = runner
10
- end
11
-
12
- # @return (see: #run_scan)
13
- def call
14
- update_ruby_advisory_db
15
- run_scan
16
- end
17
-
18
- private
19
-
20
- def update_ruby_advisory_db
21
- Bundler::Audit::Database.update!(quiet: true)
22
- end
23
-
24
- # @return [Array>] if no advisories were found
25
- # @return [Array<Pronto::Message>] if advisories were found
26
- def run_scan
27
- scanner = Bundler::Audit::Scanner.new
28
-
29
- scanner.scan.inject([]) do |acc, scan_result|
30
- acc << process_scan_result(scan_result)
31
- end
32
- end
33
-
34
- def process_scan_result(scan_result)
35
- case scan_result
36
- when Bundler::Audit::Scanner::InsecureSource
37
- report_insecure_source_scan_result
38
- when Bundler::Audit::Scanner::UnpatchedGem
39
- report_unpatched_gem_scan_result(scan_result)
40
- else
41
- raise ArgumentError, "unexpected type: #{scan_result.class}"
42
- end
43
- end
44
-
45
- def report_insecure_source_scan_result(scan_result)
46
- build_warning_message(
47
- "Insecure Source URI found: #{scan_result.source}")
48
- end
49
-
50
- def report_unpatched_gem_scan_result(scan_result)
51
- advisory =
52
- AdvisoryFormatter.new(
53
- gem: scan_result.gem, advisory: scan_result.advisory)
54
- message = advisory.to_compact_s
55
- line = find_relevant_line(advisory)
56
-
57
- build_error_message(message, line: line)
58
- end
59
-
60
- # @return [Pronto::Git::Line]
61
- def find_relevant_line(advisory)
62
- first_added_line_for_affected_gem_name(advisory.gem_name)
63
- end
64
-
65
- # @return [Pronto::Git::Line]
66
- def first_added_line_for_affected_gem_name(gem_name)
67
- @patch.added_lines.detect { |line| line.content.include?(gem_name) }
68
- end
69
-
70
- def build_warning_message(message)
71
- build_message(message, level: :warning)
72
- end
73
-
74
- def build_error_message(message, line:)
75
- build_message(message, level: :error, line: line)
76
- end
77
-
78
- def build_message(message, level:, line:)
79
- Message.new(
80
- GEMFILE_LOCK_FILENAME, line, level, message, nil, @runner.class)
81
- end
82
-
83
- # Pronto::BundlerAudit::PatchHandler::AdvisoryFormatter is a message
84
- # formatter for the given gem object and Bundler::Audit::Advisory#advisory
85
- # object.
86
- class AdvisoryFormatter
87
- # param gem [Bundler::LazySpecification]
88
- # param advisory [Bundler::Audit::Advisory]
89
- def initialize(gem:, advisory:)
90
- @gem = gem
91
- @advisory = advisory
92
- end
93
-
94
- def to_s
95
- [
96
- "Name: #{gem_name}",
97
- "Version: #{gem_version}",
98
- "Advisory: #{advisory_description}",
99
- "Criticality: #{advisory_criticality}",
100
- "URL: #{advisory_url}",
101
- "Title: #{advisory_title}",
102
- "Solution: #{advisory_solution}"
103
- ].join("\n")
104
- end
105
-
106
- def to_compact_s
107
- [
108
- "Gem: #{gem_name} v#{gem_version}",
109
- "#{advisory_criticality} Advisory: #{advisory_title} -- "\
110
- "#{advisory_description} (#{advisory_url})",
111
- "Solution: #{advisory_solution}"
112
- ].join(" | ")
113
- end
114
-
115
- def gem_name
116
- @gem.name
117
- end
118
-
119
- private
120
-
121
- def gem_version
122
- @gem.version
123
- end
124
-
125
- def advisory_description
126
- if @advisory.cve
127
- "CVE-#{@advisory.cve}"
128
- elsif @advisory.osvdb
129
- @advisory.osvdb
130
- end
131
- end
132
-
133
- def advisory_criticality
134
- str = @advisory.criticality.to_s.capitalize
135
- str = "Unknown" if str.empty?
136
- str
137
- end
138
-
139
- def advisory_url
140
- @advisory.url
141
- end
142
-
143
- def advisory_title
144
- @advisory.title
145
- end
146
-
147
- def advisory_solution
148
- if any_patched_versions?
149
- "Upgrade to #{patched_versions}."
150
- else
151
- "Remove or disable this gem until a patch is available!"
152
- end
153
- end
154
-
155
- def patched_versions
156
- @advisory.patched_versions.join(', ')
157
- end
158
-
159
- def any_patched_versions?
160
- !@advisory.patched_versions.empty?
161
- end
162
- end
163
- end
164
- end
165
- end