bundler-audit 0.8.0 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE/bug-report.md +44 -0
  3. data/.github/workflows/ruby.yml +14 -2
  4. data/.rubocop.yml +83 -0
  5. data/COPYING.txt +4 -4
  6. data/ChangeLog.md +25 -0
  7. data/Gemfile +7 -3
  8. data/README.md +14 -10
  9. data/Rakefile +7 -3
  10. data/bundler-audit.gemspec +3 -4
  11. data/lib/bundler/audit/advisory.rb +18 -2
  12. data/lib/bundler/audit/cli/formats/json.rb +16 -2
  13. data/lib/bundler/audit/cli/formats/junit.rb +127 -0
  14. data/lib/bundler/audit/cli/formats/text.rb +11 -7
  15. data/lib/bundler/audit/cli/formats.rb +7 -3
  16. data/lib/bundler/audit/cli.rb +32 -15
  17. data/lib/bundler/audit/configuration.rb +7 -4
  18. data/lib/bundler/audit/database.rb +20 -4
  19. data/lib/bundler/audit/results/insecure_source.rb +4 -1
  20. data/lib/bundler/audit/results/unpatched_gem.rb +6 -2
  21. data/lib/bundler/audit/results.rb +1 -1
  22. data/lib/bundler/audit/scanner.rb +8 -2
  23. data/lib/bundler/audit/task.rb +20 -5
  24. data/lib/bundler/audit/version.rb +2 -2
  25. data/lib/bundler/audit.rb +1 -1
  26. data/spec/advisory_spec.rb +9 -1
  27. data/spec/bundle/insecure_sources/Gemfile.lock +69 -71
  28. data/spec/bundle/secure/Gemfile.lock +51 -53
  29. data/spec/cli/formats/json_spec.rb +1 -0
  30. data/spec/cli/formats/junit_spec.rb +284 -0
  31. data/spec/cli/formats/text_spec.rb +87 -17
  32. data/spec/cli_spec.rb +57 -17
  33. data/spec/database_spec.rb +25 -1
  34. data/spec/fixtures/advisory/CVE-2020-1234.yml +1 -0
  35. data/spec/fixtures/lib/bundler/audit/cli/formats/bad.rb +0 -2
  36. data/spec/fixtures/lib/bundler/audit/cli/formats/good.rb +0 -2
  37. data/spec/results/unpatched_gem_spec.rb +2 -2
  38. data/spec/scanner_spec.rb +25 -1
  39. data/spec/spec_helper.rb +5 -1
  40. metadata +10 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c98968f6509b0551b595706cc23591bf2741626a472dcccda17e107c2e7788d0
4
- data.tar.gz: 61c7ea8687934092a74aca4f0358e2565ce9eec53fe0713198bd1eadd5e2ae31
3
+ metadata.gz: 1c6db011cec167c3f5091b4bc3928b297862b2d3e74184db2c33a203374f8d67
4
+ data.tar.gz: fe1c745f2e1202bfddfee708c512cbd34f928d6a429d8161f82394695d52b462
5
5
  SHA512:
6
- metadata.gz: 3a10a9071b08c8781c33db982d9d72929c63c2ec3ce69839cf93186bcd47775e8483fe397cf9b05363f13c785757f9b7cb3dfef2bced8085f9913c38553d6714
7
- data.tar.gz: 4789e6c07340509b1e08218b6f9b2e16fcc40f24f42476ca92fe530171b2035bab209984b324783bf387758c9262d3fce724ceb0f76cdc0e78c967109112431d
6
+ metadata.gz: edd782d23e4e776350bf77cc1dadda0d78d89cf8816540ae8b20706b42f0dbefd7a3bb30fa9093afa23c5feb78dcbe1471139fc9471cde2c575f9cb5a658a71e
7
+ data.tar.gz: 50c0fa97a5d5a73624cf59dde9fe5ee5f0e300230b725b1055c2b74908866d2d962c91764e3d248878237eea66b23ce170a0e70ba4829f00a7e4423a76dd6774
@@ -0,0 +1,44 @@
1
+ ---
2
+ name: Bug Report
3
+ about: Report a bug
4
+ title: ''
5
+ labels: bug
6
+ assignees: ''
7
+
8
+ ---
9
+ <!--
10
+ **Double Check**
11
+
12
+ - Did you update to the latest bundler-audit? (ex: `bundle update bundler-audit` or `gem update bundler-audit`)
13
+ - Did you update the ruby-advisory-db? (ex: `bundler-audit update`)
14
+ -->
15
+
16
+ ## Description
17
+
18
+ <!-- A clear and concise description of what the bug is. -->
19
+
20
+ ## Steps To Reproduce
21
+
22
+ Steps to reproduce the bug:
23
+ 1. `$ bundle-audit ...`
24
+ 2. ???
25
+
26
+ ## Expected Behavior
27
+
28
+ <!-- What should happen. -->
29
+
30
+ ## Actual Behavior
31
+
32
+ <!-- The error message or backtrace. -->
33
+ ```
34
+ ```
35
+
36
+ ## Environment
37
+
38
+ $ bundler-audit --version
39
+ ...
40
+ $ bundle --version
41
+ ...
42
+ $ ruby --version
43
+ ...
44
+
@@ -9,8 +9,6 @@ jobs:
9
9
  fail-fast: false
10
10
  matrix:
11
11
  ruby:
12
- - 2.4
13
- - 2.5
14
12
  - 2.6
15
13
  - 2.7
16
14
  - 3.0
@@ -27,3 +25,17 @@ jobs:
27
25
  run: bundle install --jobs 4 --retry 3
28
26
  - name: Run tests
29
27
  run: bundle exec rake test
28
+
29
+ # rubocop linting
30
+ rubocop:
31
+ runs-on: ubuntu-latest
32
+ steps:
33
+ - uses: actions/checkout@v2
34
+ - name: Set up Ruby
35
+ uses: ruby/setup-ruby@v1
36
+ with:
37
+ ruby-version: 2.7
38
+ - name: Install dependencies
39
+ run: bundle install --jobs 4 --retry 3
40
+ - name: Run rubocop
41
+ run: bundle exec rubocop --parallel
data/.rubocop.yml ADDED
@@ -0,0 +1,83 @@
1
+ AllCops:
2
+ NewCops: enable
3
+ SuggestExtensions: false
4
+ TargetRubyVersion: 2.7
5
+ Exclude:
6
+ - 'spec/bundle/**/*'
7
+ - 'spec/fixtures/database/**/*'
8
+ - 'vendor/**/*'
9
+
10
+ #
11
+ # Style
12
+ #
13
+ Layout/FirstArrayElementIndentation: { EnforcedStyle: consistent }
14
+ Layout/FirstHashElementIndentation: { EnforcedStyle: consistent }
15
+ Layout/SpaceAroundEqualsInParameterDefault: { EnforcedStyle: no_space }
16
+ Style/SymbolArray: { EnforcedStyle: brackets }
17
+ Style/PercentLiteralDelimiters:
18
+ Enabled: true
19
+ PreferredDelimiters:
20
+ default: '{}'
21
+ '%i': '[]'
22
+ '%I': '[]'
23
+ '%w': '[]'
24
+ '%W': '[]'
25
+
26
+ #
27
+ # Rules that conflict with my style.
28
+ #
29
+ Metrics: { Enabled: false }
30
+ Layout/BeginEndAlignment: { Enabled: false } # Offense count: 1
31
+ Layout/BlockAlignment: { Enabled: false } # Offense count: 1
32
+ Layout/EmptyLinesAroundClassBody: { Enabled: false } # Offense count: 15
33
+ Layout/ExtraSpacing: { Enabled: false } # Offense count: 9
34
+ Layout/HashAlignment: { Enabled: false } # Offense count: 3
35
+ Layout/SpaceAfterComma: { Enabled: false } # Offense count: 122
36
+ Layout/SpaceInsideHashLiteralBraces: { Enabled: false } # Offense count: 8
37
+ Lint/MissingSuper: { Enabled: false } # Offense count: 3
38
+ Lint/ShadowingOuterLocalVariable: { Enabled: false }
39
+ Lint/ConstantDefinitionInBlock: { Exclude: ['spec/cli/formats_spec.rb'] }
40
+ Lint/SuppressedException: { Exclude: ['spec/cli_spec.rb'] }
41
+ Lint/UnusedBlockArgument: { Enabled: false } # Offense count: 4
42
+ Lint/UnusedMethodArgument: { Enabled: false } # Offense count: 6
43
+ Naming/RescuedExceptionsVariableName: { Enabled: false } # Offense count: 2
44
+ Style/BlockDelimiters: { Enabled: false } # Offense count: 20
45
+ Style/CaseEquality: { Exclude: ['lib/bundler/audit/advisory.rb'] }
46
+ Style/ClassCheck: { Enabled: false } # Offense count: 4
47
+ Style/Documentation: { Enabled: false } # Offense count: 12
48
+ Style/GuardClause: { Enabled: false } # Offense count: 1
49
+ Style/HashSyntax:
50
+ Exclude:
51
+ - 'Rakefile'
52
+ - 'lib/bundler/audit/task.rb'
53
+ Style/IfUnlessModifier: { Enabled: false } # Offense count: 14
54
+ Style/MethodCallWithoutArgsParentheses: { Enabled: false } # Offense count: 1
55
+ Style/MultilineBlockChain: { Exclude: ['spec/**/*'] } # Offense count: 6
56
+ Style/MutableConstant: { Enabled: false } # Offense count: 4
57
+ Style/ParenthesesAroundCondition: { Enabled: false } # Offense count: 1
58
+ Style/RedundantBegin: { Exclude: ['spec/cli_spec.rb'] } # Offense count: 1
59
+ Style/RedundantReturn: { Enabled: false } # Offense count: 6
60
+ Style/SpecialGlobalVars: { Enabled: false } # Offense count: 5
61
+ Style/StringLiterals: { Enabled: false } # Offense count: 333
62
+ Style/StructInheritance: { Enabled: false } # Offense count: 1
63
+ Style/UnlessElse: { Enabled: false } # Offense count: 1
64
+ Style/WordArray: { Enabled: false } # Offense count: 1
65
+ Style/Lambda: { Enabled: false } # Offense count: 2
66
+ Style/SafeNavigation: { Enabled: false } # Offense count: 2
67
+ Lint/IneffectiveAccessModifier: { Enabled: false } # Offense count: 1
68
+
69
+ #
70
+ # Rules that may be disabled in the future.
71
+ #
72
+ # Layout/SpaceInsideParens: { Enabled: false }
73
+ # Layout/TrailingWhitespace: { Enabled: false }
74
+
75
+ #
76
+ # Rules that I want to fully enabled in the future.
77
+ #
78
+ Style/DoubleNegation: { Exclude: ['spec/spec_helper.rb'] } # Offense count: 1
79
+ Style/EmptyMethod: { Exclude: ['spec/cli/formats_spec.rb'] } # Offense count: 2
80
+ Style/ExpandPathArguments: { Enabled: false } # Offense count: 5
81
+ Style/FrozenStringLiteralComment: { Enabled: false } # Offense count: 42
82
+ Style/MixinUsage: { Exclude: ['spec/spec_helper.rb'] } # Offense count: 1
83
+ Layout/LineLength: { Enabled: false }
data/COPYING.txt CHANGED
@@ -1,7 +1,7 @@
1
1
  GNU GENERAL PUBLIC LICENSE
2
2
  Version 3, 29 June 2007
3
3
 
4
- Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
4
+ Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
5
5
  Everyone is permitted to copy and distribute verbatim copies
6
6
  of this license document, but changing it is not allowed.
7
7
 
@@ -645,7 +645,7 @@ the "copyright" line and a pointer to where the full notice is found.
645
645
  GNU General Public License for more details.
646
646
 
647
647
  You should have received a copy of the GNU General Public License
648
- along with this program. If not, see <http://www.gnu.org/licenses/>.
648
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
649
649
 
650
650
  Also add information on how to contact you by electronic and paper mail.
651
651
 
@@ -664,11 +664,11 @@ might be different; for a GUI interface, you would use an "about box".
664
664
  You should also get your employer (if you work as a programmer) or school,
665
665
  if any, to sign a "copyright disclaimer" for the program, if necessary.
666
666
  For more information on this, and how to apply and follow the GNU GPL, see
667
- <http://www.gnu.org/licenses/>.
667
+ <https://www.gnu.org/licenses/>.
668
668
 
669
669
  The GNU General Public License does not permit incorporating your program
670
670
  into proprietary programs. If your program is a subroutine library, you
671
671
  may consider it more useful to permit linking proprietary applications with
672
672
  the library. If this is what you want to do, use the GNU Lesser General
673
673
  Public License instead of this License. But first, please read
674
- <http://www.gnu.org/philosophy/why-not-lgpl.html>.
674
+ <https://www.gnu.org/philosophy/why-not-lgpl.html>.
data/ChangeLog.md CHANGED
@@ -1,3 +1,28 @@
1
+ ### 0.9.0 / 2021-08-31
2
+
3
+ * Load advisory metadata using `YAML.safe_load`. (issue #302)
4
+ * Explicitly permit the `Date` class for Psych >= 4.0.0 and Ruby >= 3.1.0.
5
+ * Added {Bundler::Audit::Advisory#to_h}. (pull #310)
6
+ * Added {Bundler::Audit::Database#commit_id}.
7
+
8
+ #### CLI
9
+
10
+ * Added the `--config` option. (pull #306)
11
+ * Added the `junit` output format (ex: `--format junit`). (pull #314)
12
+ * Add missing output for CVSSv3 criticality information. (pull #302)
13
+ * Include criticality information in the JSON output as well. (pull #310)
14
+ * `bundle-audit stats` now prints the commit ID of the ruby-advisory-db.
15
+ * Fixed a deprecation warning from Thor. (issue #317)
16
+
17
+ #### Rake Task
18
+
19
+ * Add the `bundle:audit:update` task for updating the [ruby-advisory-db].
20
+ (pull #296)
21
+ * Aliased `bundle:audit` to `bundle:audit:check`.
22
+ * Aliased `bundler:audit:*` to `bundle:audit:*`.
23
+ * Rake tasks now execute `bundle-audit` command as a subprocess to ensure
24
+ isolation.
25
+
1
26
  ### 0.8.0 / 2021-03-10
2
27
 
3
28
  * No longer vendor [ruby-advisory-db].
data/Gemfile CHANGED
@@ -4,10 +4,14 @@ gemspec
4
4
 
5
5
  group :development do
6
6
  gem 'rake'
7
- gem 'kramdown', '~> 2.0'
8
-
9
7
  gem 'rubygems-tasks', '~> 0.2'
8
+
9
+ gem 'rubocop', '~> 1.18'
10
+
10
11
  gem 'rspec', '~> 3.0'
12
+ gem 'simplecov', '~> 0.7', require: false
13
+
14
+ gem 'kramdown', '~> 2.0'
11
15
  gem 'yard', '~> 0.9'
12
- gem 'simplecov', '~> 0.7', :require => false
16
+ gem 'yard-spellcheck', require: false
13
17
  end
data/README.md CHANGED
@@ -13,7 +13,7 @@ Patch-level verification for [bundler].
13
13
  ## Features
14
14
 
15
15
  * Checks for vulnerable versions of gems in `Gemfile.lock`.
16
- * Checks for insecure gem sources (`http://`).
16
+ * Checks for insecure gem sources (`http://` and `git://`).
17
17
  * Allows ignoring certain advisories that have been manually worked around.
18
18
  * Prints advisory information.
19
19
  * Does not require a network connection.
@@ -131,13 +131,14 @@ Output the audit's results in JSON, to a file:
131
131
 
132
132
  $ bundle-audit check --format json --output bundle-audit.json
133
133
 
134
- Rake task:
134
+ ## Rake Tasks
135
135
 
136
- ```ruby
137
- require 'bundler/audit/task'
138
- Bundler::Audit::Task.new
136
+ Bundler-audit provides Rake tasks for checking the code and for updating
137
+ its vulnerability database:
139
138
 
140
- task default: 'bundle:audit'
139
+ ```bash
140
+ rake bundle:audit
141
+ rake bundle:audit:update
141
142
  ```
142
143
 
143
144
  ## Configuration File
@@ -153,6 +154,10 @@ bundler-audit also supports a per-project configuration file:
153
154
 
154
155
  * `ignore:` \[Array\<String\>\] - A list of advisory IDs to ignore.
155
156
 
157
+ You can provide a path to a config file using the `--config` flag:
158
+
159
+ $ bundle-audit check --config bundler-audit.custom.yaml
160
+
156
161
  ## Requirements
157
162
 
158
163
  * [git]
@@ -188,7 +193,7 @@ bundler-audit also supports a per-project configuration file:
188
193
  1. https://github.com/rubysec/bundler-audit/fork
189
194
  2. `git clone YOUR_FORK_URI`
190
195
  3. `cd bundler-audit/`
191
- 4. `budle install`
196
+ 4. `bundle install`
192
197
  5. `bundle exec rake spec`
193
198
  6. `git checkout -b YOUR_FEATURE`
194
199
  7. Make your changes
@@ -211,14 +216,13 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
211
216
  GNU General Public License for more details.
212
217
 
213
218
  You should have received a copy of the GNU General Public License
214
- along with bundler-audit. If not, see <http://www.gnu.org/licenses/>.
219
+ along with bundler-audit. If not, see <https://www.gnu.org/licenses/>.
215
220
 
216
221
  [git]: https://git-scm.com
217
222
  [ruby]: https://ruby-lang.org
218
223
  [rubygems]: https://rubygems.org
219
224
  [thor]: http://whatisthor.com/
220
- [bundler]: https://github.com/carlhuda/bundler#readme
221
- [git]: https://github.com/git/git
225
+ [bundler]: https://bundler.io
222
226
 
223
227
  [OSVDB]: http://osvdb.org/
224
228
  [ruby-advisory-db]: https://github.com/rubysec/ruby-advisory-db
data/Rakefile CHANGED
@@ -1,5 +1,3 @@
1
- # encoding: utf-8
2
-
3
1
  require 'rubygems'
4
2
 
5
3
  begin
@@ -36,5 +34,11 @@ task :test => :spec
36
34
  task :default => :spec
37
35
 
38
36
  require 'yard'
39
- YARD::Rake::YardocTask.new
37
+ YARD::Rake::YardocTask.new
40
38
  task :doc => :yard
39
+
40
+ require 'bundler/audit/task'
41
+ Bundler::Audit::Task.new
42
+
43
+ require 'rubocop/rake_task'
44
+ RuboCop::RakeTask.new
@@ -1,5 +1,3 @@
1
- # encoding: utf-8
2
-
3
1
  require 'yaml'
4
2
 
5
3
  Gem::Specification.new do |gem|
@@ -23,8 +21,9 @@ Gem::Specification.new do |gem|
23
21
 
24
22
  glob = lambda { |patterns| gem.files & Dir[*patterns] }
25
23
 
26
- gem.files = `git ls-files`.split($/)
27
- gem.files = glob[gemspec['files']] if gemspec['files']
24
+ gem.files = if gemspec['files'] then glob[gemspec['files']]
25
+ else `git ls-files`.split($/)
26
+ end
28
27
 
29
28
  gem.executables = gemspec.fetch('executables') do
30
29
  glob['bin/*'].map { |path| File.basename(path) }
@@ -12,13 +12,16 @@
12
12
  # GNU General Public License for more details.
13
13
  #
14
14
  # You should have received a copy of the GNU General Public License
15
- # along with bundler-audit. If not, see <http://www.gnu.org/licenses/>.
15
+ # along with bundler-audit. If not, see <https://www.gnu.org/licenses/>.
16
16
  #
17
17
 
18
18
  require 'yaml'
19
19
 
20
20
  module Bundler
21
21
  module Audit
22
+ #
23
+ # Represents an advisory loaded from the {Database}.
24
+ #
22
25
  class Advisory < Struct.new(:path,
23
26
  :id,
24
27
  :url,
@@ -45,7 +48,9 @@ module Bundler
45
48
  #
46
49
  def self.load(path)
47
50
  id = File.basename(path).chomp('.yml')
48
- data = YAML.load_file(path)
51
+ data = File.open(path) do |yaml|
52
+ YAML.safe_load(yaml, permitted_classes: [Date])
53
+ end
49
54
 
50
55
  unless data.kind_of?(Hash)
51
56
  raise("advisory data in #{path.dump} was not a Hash")
@@ -200,6 +205,17 @@ module Bundler
200
205
  id == other.id
201
206
  end
202
207
 
208
+ #
209
+ # Converts the advisory to a Hash.
210
+ #
211
+ # @return [Hash{Symbol => Object}]
212
+ #
213
+ def to_h
214
+ super.merge({
215
+ criticality: criticality
216
+ })
217
+ end
218
+
203
219
  alias to_s id
204
220
 
205
221
  end
@@ -12,7 +12,7 @@
12
12
  # GNU General Public License for more details.
13
13
  #
14
14
  # You should have received a copy of the GNU General Public License
15
- # along with bundler-audit. If not, see <http://www.gnu.org/licenses/>.
15
+ # along with bundler-audit. If not, see <https://www.gnu.org/licenses/>.
16
16
  #
17
17
 
18
18
  require 'thor'
@@ -22,6 +22,9 @@ module Bundler
22
22
  module Audit
23
23
  class CLI < ::Thor
24
24
  module Formats
25
+ #
26
+ # The JSON output format.
27
+ #
25
28
  module JSON
26
29
  #
27
30
  # Outputs the report as JSON. Will pretty-print JSON if `output`
@@ -37,11 +40,22 @@ module Bundler
37
40
  hash = report.to_h
38
41
 
39
42
  if output.tty?
40
- output.puts ::JSON.pretty_generate(hash)
43
+ output.puts(::JSON.pretty_generate(hash))
41
44
  else
42
45
  output.write(::JSON.generate(hash))
43
46
  end
44
47
  end
48
+
49
+ def criticality_label(advisory)
50
+ case advisory.criticality
51
+ when :none then "none"
52
+ when :low then "low"
53
+ when :medium then "medium"
54
+ when :high then "high"
55
+ when :critical then "critical"
56
+ else "unknown"
57
+ end
58
+ end
45
59
  end
46
60
 
47
61
  Formats.register :json, JSON
@@ -0,0 +1,127 @@
1
+ #
2
+ # Copyright (c) 2013-2021 Hal Brodigan (postmodern.mod3 at gmail.com)
3
+ #
4
+ # bundler-audit is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # bundler-audit is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with bundler-audit. If not, see <https://www.gnu.org/licenses/>.
16
+ #
17
+
18
+ require 'thor'
19
+ require 'cgi'
20
+
21
+ module Bundler
22
+ module Audit
23
+ class CLI < ::Thor
24
+ module Formats
25
+ module Junit
26
+ #
27
+ # Prints any findings as an XML junit report.
28
+ #
29
+ # @param [Report] report
30
+ # The results from the {Scanner}.
31
+ #
32
+ # @param [IO, File] output
33
+ # Optional output stream.
34
+ #
35
+ def print_report(report, output=$stdout)
36
+ original_stdout = $stdout
37
+ $stdout = output
38
+
39
+ print_xml_testsuite(report) do
40
+ report.each do |result|
41
+ print_xml_testcase(result)
42
+ end
43
+ end
44
+
45
+ $stdout = original_stdout
46
+ end
47
+
48
+ private
49
+
50
+ def say_xml(*lines)
51
+ say(lines.join($/))
52
+ end
53
+
54
+ def print_xml_testsuite(report)
55
+ say_xml(
56
+ %{<?xml version="1.0" encoding="UTF-8" ?>},
57
+ %{<testsuites id="#{Time.now.to_i}" name="Bundle Audit">},
58
+ %{ <testsuite id="Gemfile" name="Ruby Gemfile" failures="#{report.count}">}
59
+ )
60
+
61
+ yield
62
+
63
+ say_xml(
64
+ %{ </testsuite>},
65
+ %{</testsuites>}
66
+ )
67
+ end
68
+
69
+ def xml(string)
70
+ CGI.escapeHTML(string.to_s)
71
+ end
72
+
73
+ def print_xml_testcase(result)
74
+ case result
75
+ when Results::InsecureSource
76
+ say_xml(
77
+ %{ <testcase id="#{xml(result.source)}" name="Insecure Source URI found: #{xml(result.source)}">},
78
+ %{ <failure message="Insecure Source URI found: #{xml(result.source)}" type="Unknown"></failure>},
79
+ %{ </testcase>}
80
+ )
81
+ when Results::UnpatchedGem
82
+ say_xml(
83
+ %{ <testcase id="#{xml(result.gem.name)}" name="#{xml(bundle_title(result))}">},
84
+ %{ <failure message="#{xml(result.advisory.title)}" type="#{xml(result.advisory.criticality)}">},
85
+ %{ Name: #{xml(result.gem.name)}},
86
+ %{ Version: #{xml(result.gem.version)}},
87
+ %{ Advisory: #{xml(advisory_ref(result.advisory))}},
88
+ %{ Criticality: #{xml(advisory_criticality(result.advisory))}},
89
+ %{ URL: #{xml(result.advisory.url)}},
90
+ %{ Title: #{xml(result.advisory.title)}},
91
+ %{ Solution: #{xml(advisory_solution(result.advisory))}},
92
+ %{ </failure>},
93
+ %{ </testcase>}
94
+ )
95
+ end
96
+ end
97
+
98
+ def bundle_title(result)
99
+ "#{advisory_criticality(result.advisory).upcase} #{result.gem.name}(#{result.gem.version}) #{result.advisory.title}"
100
+ end
101
+
102
+ def advisory_solution(advisory)
103
+ unless advisory.patched_versions.empty?
104
+ "upgrade to #{advisory.patched_versions.join(', ')}"
105
+ else
106
+ "remove or disable this gem until a patch is available!"
107
+ end
108
+ end
109
+
110
+ def advisory_criticality(advisory)
111
+ if advisory.criticality
112
+ advisory.criticality.to_s.capitalize
113
+ else
114
+ "Unknown"
115
+ end
116
+ end
117
+
118
+ def advisory_ref(advisory)
119
+ advisory.identifiers.join(" ")
120
+ end
121
+
122
+ Formats.register :junit, Junit
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end