chelsea 0.0.27 → 0.0.28
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/.circleci/config.yml +5 -2
- data/.github/ISSUE_TEMPLATE/bug_report.md +1 -1
- data/.rubocop.yml +6 -0
- data/Gemfile +7 -2
- data/Gemfile.lock +21 -1
- data/Rakefile +5 -3
- data/bin/chelsea +14 -7
- data/bin/console +5 -4
- data/chelsea.gemspec +30 -28
- data/lib/chelsea/bom.rb +3 -3
- data/lib/chelsea/cli.rb +13 -9
- data/lib/chelsea/config.rb +12 -11
- data/lib/chelsea/db.rb +4 -1
- data/lib/chelsea/dependency_exception.rb +4 -1
- data/lib/chelsea/deps.rb +5 -2
- data/lib/chelsea/formatters/factory.rb +4 -2
- data/lib/chelsea/formatters/formatter.rb +15 -11
- data/lib/chelsea/formatters/json.rb +5 -1
- data/lib/chelsea/formatters/text.rb +9 -4
- data/lib/chelsea/formatters/xml.rb +20 -16
- data/lib/chelsea/gems.rb +16 -17
- data/lib/chelsea/iq_client.rb +39 -41
- data/lib/chelsea/oss_index.rb +8 -9
- data/lib/chelsea/spinner.rb +3 -0
- data/lib/chelsea/version.rb +3 -1
- metadata +48 -47
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1d6bcb375015c64ae7e452f93e38b10cfabb4ecbc9425fad0121e926a0148efa
|
|
4
|
+
data.tar.gz: f1a171d3a72a0bf910ac4e22258cee6a0d6c3e8181307856a34a5b22ca0435c7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: decb1e4e8a54798161b2e888e1694d9558ba0bbacd6708c6cf32d4b71b32cb05520f017733a18e90dab99c0e2e2be500d3c8b8701b1ff464041ad63ab89ffa74
|
|
7
|
+
data.tar.gz: 94f91e9b3f248d7a3c494fdba567f832edf38b2e91e75f791ac1d9dace17b285e89d09c43bae25d6faacd0b2a76e5a4bb211acb3153dfc57ea4b581243f5d8d1
|
data/.circleci/config.yml
CHANGED
|
@@ -18,7 +18,7 @@ version: 2.1
|
|
|
18
18
|
jobs:
|
|
19
19
|
build:
|
|
20
20
|
docker:
|
|
21
|
-
- image: circleci/ruby:2.6.
|
|
21
|
+
- image: circleci/ruby:2.6.6-stretch
|
|
22
22
|
environment:
|
|
23
23
|
BUNDLE_PATH: vendor/bundle
|
|
24
24
|
steps:
|
|
@@ -48,6 +48,9 @@ jobs:
|
|
|
48
48
|
bundle exec rspec --format progress \
|
|
49
49
|
--format RspecJunitFormatter \
|
|
50
50
|
--out test_results/rspec.xml
|
|
51
|
+
- run:
|
|
52
|
+
name: Run linter
|
|
53
|
+
command: bundle exec rubocop
|
|
51
54
|
- run:
|
|
52
55
|
name: Build gem
|
|
53
56
|
command: gem build chelsea.gemspec
|
|
@@ -64,7 +67,7 @@ jobs:
|
|
|
64
67
|
path: test_results
|
|
65
68
|
release:
|
|
66
69
|
docker:
|
|
67
|
-
- image: circleci/ruby:2.6.
|
|
70
|
+
- image: circleci/ruby:2.6.6-stretch
|
|
68
71
|
steps:
|
|
69
72
|
- add_ssh_keys:
|
|
70
73
|
fingerprints:
|
|
@@ -23,7 +23,7 @@ If applicable, add screenshots to help explain your problem.
|
|
|
23
23
|
|
|
24
24
|
**Desktop (please complete the following information):**
|
|
25
25
|
- OS: [e.g. OS X 1.13.6]
|
|
26
|
-
- Ruby Version: [e.g. 2.6.
|
|
26
|
+
- Ruby Version: [e.g. 2.6.6]
|
|
27
27
|
- Bundler Version: [e.g. 2.1.4]
|
|
28
28
|
- chelsea Version [e.g. 0.0.11]
|
|
29
29
|
|
data/.rubocop.yml
ADDED
data/Gemfile
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
source 'https://rubygems.org'
|
|
4
|
+
|
|
5
|
+
git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
|
|
4
6
|
|
|
5
7
|
# Specify your gem's dependencies in chelsea.gemspec
|
|
6
8
|
gemspec
|
|
9
|
+
|
|
10
|
+
# linter
|
|
11
|
+
gem 'rubocop', require: false
|
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
chelsea (0.0.
|
|
4
|
+
chelsea (0.0.27)
|
|
5
5
|
bundler (>= 1.2.0, < 3)
|
|
6
6
|
ox (~> 2.13.2)
|
|
7
7
|
pastel (~> 0.7.2)
|
|
@@ -16,6 +16,7 @@ GEM
|
|
|
16
16
|
specs:
|
|
17
17
|
addressable (2.7.0)
|
|
18
18
|
public_suffix (>= 2.0.2, < 5.0)
|
|
19
|
+
ast (2.4.2)
|
|
19
20
|
byebug (11.1.2)
|
|
20
21
|
crack (0.4.3)
|
|
21
22
|
safe_yaml (~> 1.0.0)
|
|
@@ -32,15 +33,21 @@ GEM
|
|
|
32
33
|
necromancer (0.6.0)
|
|
33
34
|
netrc (0.11.0)
|
|
34
35
|
ox (2.13.4)
|
|
36
|
+
parallel (1.20.1)
|
|
37
|
+
parser (3.0.0.0)
|
|
38
|
+
ast (~> 2.4.1)
|
|
35
39
|
pastel (0.7.4)
|
|
36
40
|
equatable (~> 0.6)
|
|
37
41
|
tty-color (~> 0.5)
|
|
38
42
|
public_suffix (4.0.3)
|
|
43
|
+
rainbow (3.0.0)
|
|
39
44
|
rake (12.3.3)
|
|
45
|
+
regexp_parser (2.0.3)
|
|
40
46
|
rest-client (2.0.2)
|
|
41
47
|
http-cookie (>= 1.0.2, < 2.0)
|
|
42
48
|
mime-types (>= 1.16, < 4.0)
|
|
43
49
|
netrc (~> 0.8)
|
|
50
|
+
rexml (3.2.4)
|
|
44
51
|
rspec (3.9.0)
|
|
45
52
|
rspec-core (~> 3.9.0)
|
|
46
53
|
rspec-expectations (~> 3.9.0)
|
|
@@ -56,6 +63,18 @@ GEM
|
|
|
56
63
|
rspec-support (3.9.2)
|
|
57
64
|
rspec_junit_formatter (0.4.1)
|
|
58
65
|
rspec-core (>= 2, < 4, != 2.12.0)
|
|
66
|
+
rubocop (1.9.0)
|
|
67
|
+
parallel (~> 1.10)
|
|
68
|
+
parser (>= 3.0.0.0)
|
|
69
|
+
rainbow (>= 2.2.2, < 4.0)
|
|
70
|
+
regexp_parser (>= 1.8, < 3.0)
|
|
71
|
+
rexml
|
|
72
|
+
rubocop-ast (>= 1.2.0, < 2.0)
|
|
73
|
+
ruby-progressbar (~> 1.7)
|
|
74
|
+
unicode-display_width (>= 1.4.0, < 3.0)
|
|
75
|
+
rubocop-ast (1.4.1)
|
|
76
|
+
parser (>= 2.7.1.5)
|
|
77
|
+
ruby-progressbar (1.11.0)
|
|
59
78
|
safe_yaml (1.0.5)
|
|
60
79
|
slop (4.8.2)
|
|
61
80
|
strings (0.1.8)
|
|
@@ -94,6 +113,7 @@ DEPENDENCIES
|
|
|
94
113
|
rake (~> 12.3)
|
|
95
114
|
rspec (~> 3.0)
|
|
96
115
|
rspec_junit_formatter (~> 0.4.1)
|
|
116
|
+
rubocop
|
|
97
117
|
webmock (~> 3.8.3)
|
|
98
118
|
|
|
99
119
|
BUNDLED WITH
|
data/Rakefile
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
#
|
|
2
4
|
# Copyright 2019-Present Sonatype Inc.
|
|
3
5
|
#
|
|
@@ -14,9 +16,9 @@
|
|
|
14
16
|
# limitations under the License.
|
|
15
17
|
#
|
|
16
18
|
|
|
17
|
-
require
|
|
18
|
-
require
|
|
19
|
+
require 'bundler/gem_tasks'
|
|
20
|
+
require 'rspec/core/rake_task'
|
|
19
21
|
|
|
20
22
|
RSpec::Core::RakeTask.new(:spec)
|
|
21
23
|
|
|
22
|
-
task :
|
|
24
|
+
task default: :spec
|
data/bin/chelsea
CHANGED
|
@@ -16,7 +16,8 @@
|
|
|
16
16
|
#
|
|
17
17
|
|
|
18
18
|
# frozen_string_literal: true
|
|
19
|
-
|
|
19
|
+
|
|
20
|
+
require_relative '../lib/chelsea'
|
|
20
21
|
require 'slop'
|
|
21
22
|
opts =
|
|
22
23
|
begin
|
|
@@ -31,13 +32,19 @@ opts =
|
|
|
31
32
|
o.string '-iu', '--iquser', 'Specify the IQ username', default: 'admin'
|
|
32
33
|
o.string '-it', '--iqpass', 'Specify the IQ auth token', default: 'admin123'
|
|
33
34
|
o.string '-w', '--whitelist', 'Set path to vulnerability whitelist file'
|
|
34
|
-
o.bool '-v', '--verbose',
|
|
35
|
-
|
|
35
|
+
o.bool '-v', '--verbose',
|
|
36
|
+
'For text format, list dependencies, their reverse dependencies (what brought them in to your project), and
|
|
37
|
+
if they are vulnerable. (default: false)', default: false
|
|
38
|
+
o.string '-t', '--format',
|
|
39
|
+
'Choose what type of format you want your report in (default: text) (options: text, json, xml)',
|
|
40
|
+
default: 'text'
|
|
36
41
|
o.bool '-b', '--iq', 'Use Nexus IQ Server to audit your project'
|
|
37
|
-
o.string '-s', '--stage',
|
|
42
|
+
o.string '-s', '--stage',
|
|
43
|
+
'Specify Nexus IQ Stage (default: build) (options: develop, build, stage-release, release, operate)',
|
|
44
|
+
default: 'build'
|
|
38
45
|
o.on '--version', 'Print the version' do
|
|
39
|
-
|
|
40
|
-
|
|
46
|
+
puts Chelsea::VERSION
|
|
47
|
+
exit
|
|
41
48
|
end
|
|
42
49
|
o.on '-h', '--help', 'Show usage' do
|
|
43
50
|
puts(o)
|
|
@@ -45,7 +52,7 @@ opts =
|
|
|
45
52
|
end
|
|
46
53
|
end
|
|
47
54
|
rescue Slop::Error => e
|
|
48
|
-
puts(e.message
|
|
55
|
+
puts("#{e.message} (try --help)")
|
|
49
56
|
exit 1
|
|
50
57
|
end
|
|
51
58
|
if opts.arguments.count.positive?
|
data/bin/console
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
2
4
|
#
|
|
3
5
|
# Copyright 2019-Present Sonatype Inc.
|
|
4
6
|
#
|
|
@@ -15,9 +17,8 @@
|
|
|
15
17
|
# limitations under the License.
|
|
16
18
|
#
|
|
17
19
|
|
|
20
|
+
require 'bundler/setup'
|
|
21
|
+
require 'chelsea'
|
|
18
22
|
|
|
19
|
-
require
|
|
20
|
-
require "chelsea"
|
|
21
|
-
|
|
22
|
-
require "irb"
|
|
23
|
+
require 'irb'
|
|
23
24
|
IRB.start(__FILE__)
|
data/chelsea.gemspec
CHANGED
|
@@ -1,41 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
|
|
2
|
-
lib = File.expand_path(
|
|
3
|
+
lib = File.expand_path('lib', __dir__)
|
|
3
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
|
-
require
|
|
5
|
+
require 'chelsea/version'
|
|
5
6
|
|
|
6
7
|
Gem::Specification.new do |spec|
|
|
7
|
-
spec.name =
|
|
8
|
-
spec.license =
|
|
8
|
+
spec.name = 'chelsea'
|
|
9
|
+
spec.license = 'Apache-2.0'
|
|
9
10
|
spec.version = Chelsea::VERSION
|
|
10
|
-
spec.authors = [
|
|
11
|
-
spec.email = [
|
|
11
|
+
spec.authors = ['Allister Beharry']
|
|
12
|
+
spec.email = ['allister.beharry@gmail.com']
|
|
13
|
+
spec.required_ruby_version = '>= 2.6.6'
|
|
12
14
|
|
|
13
|
-
spec.summary =
|
|
14
|
-
spec.homepage =
|
|
15
|
-
|
|
16
|
-
spec.metadata["homepage_uri"] = spec.homepage
|
|
17
|
-
spec.metadata["source_code_uri"] = "https://github.com/sonatype-nexus-community/chelsea"
|
|
18
|
-
spec.metadata["changelog_uri"] = "https://github.com/sonatype-nexus-community/chelsea/CHANGELOG"
|
|
15
|
+
spec.summary = 'Audit Ruby package dependencies for security vulnerabilities.'
|
|
16
|
+
spec.homepage = 'https://github.com/sonatype-nexus-community/chelsea'
|
|
19
17
|
|
|
20
|
-
spec.
|
|
18
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
|
19
|
+
spec.metadata['source_code_uri'] = 'https://github.com/sonatype-nexus-community/chelsea'
|
|
20
|
+
spec.metadata['changelog_uri'] = 'https://github.com/sonatype-nexus-community/chelsea/CHANGELOG'
|
|
21
|
+
|
|
22
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
|
21
23
|
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
|
22
24
|
end
|
|
23
|
-
spec.bindir =
|
|
25
|
+
spec.bindir = 'bin'
|
|
24
26
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
|
25
|
-
spec.require_paths = [
|
|
27
|
+
spec.require_paths = ['lib']
|
|
26
28
|
|
|
27
|
-
spec.add_dependency
|
|
28
|
-
spec.add_dependency
|
|
29
|
-
spec.add_dependency
|
|
30
|
-
spec.add_dependency
|
|
31
|
-
spec.add_dependency
|
|
32
|
-
spec.add_dependency
|
|
33
|
-
spec.add_dependency
|
|
34
|
-
spec.add_dependency
|
|
29
|
+
spec.add_dependency 'bundler', '>= 1.2.0', '< 3'
|
|
30
|
+
spec.add_dependency 'ox', '~> 2.13.2'
|
|
31
|
+
spec.add_dependency 'pastel', '~> 0.7.2'
|
|
32
|
+
spec.add_dependency 'rest-client', '~> 2.0.2'
|
|
33
|
+
spec.add_dependency 'slop', '~> 4.8.1'
|
|
34
|
+
spec.add_dependency 'tty-font', '~> 0.5.0'
|
|
35
|
+
spec.add_dependency 'tty-spinner', '~> 0.9.3'
|
|
36
|
+
spec.add_dependency 'tty-table', '~> 0.11.0'
|
|
35
37
|
|
|
36
|
-
spec.add_development_dependency
|
|
37
|
-
spec.add_development_dependency
|
|
38
|
-
spec.add_development_dependency
|
|
39
|
-
spec.add_development_dependency
|
|
40
|
-
spec.add_development_dependency
|
|
38
|
+
spec.add_development_dependency 'byebug', '~> 11.1.2'
|
|
39
|
+
spec.add_development_dependency 'rake', '~> 12.3'
|
|
40
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
|
41
|
+
spec.add_development_dependency 'rspec_junit_formatter', '~> 0.4.1'
|
|
42
|
+
spec.add_development_dependency 'webmock', '~> 3.8.3'
|
|
41
43
|
end
|
data/lib/chelsea/bom.rb
CHANGED
|
@@ -40,7 +40,7 @@ module Chelsea
|
|
|
40
40
|
end
|
|
41
41
|
|
|
42
42
|
def random_urn_uuid
|
|
43
|
-
|
|
43
|
+
"urn:uuid:#{SecureRandom.uuid}"
|
|
44
44
|
end
|
|
45
45
|
|
|
46
46
|
private
|
|
@@ -87,8 +87,8 @@ module Chelsea
|
|
|
87
87
|
component
|
|
88
88
|
end
|
|
89
89
|
|
|
90
|
-
def _show_logo
|
|
91
|
-
logo = %
|
|
90
|
+
def _show_logo # rubocop:disable Metrics/MethodLength
|
|
91
|
+
logo = %(
|
|
92
92
|
-o/
|
|
93
93
|
-+hNmNN-
|
|
94
94
|
.:+osyhddddyso/-``ody+- .NN.
|
data/lib/chelsea/cli.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
#
|
|
2
4
|
# Copyright 2019-Present Sonatype Inc.
|
|
3
5
|
#
|
|
@@ -26,7 +28,7 @@ require_relative 'config'
|
|
|
26
28
|
module Chelsea
|
|
27
29
|
##
|
|
28
30
|
# This class provides an interface to the oss index, gems and deps
|
|
29
|
-
class CLI
|
|
31
|
+
class CLI # rubocop:disable Metrics/ClassLength
|
|
30
32
|
def initialize(opts)
|
|
31
33
|
@opts = opts
|
|
32
34
|
@pastel = Pastel.new
|
|
@@ -34,26 +36,28 @@ module Chelsea
|
|
|
34
36
|
_show_logo # Move to formatter
|
|
35
37
|
end
|
|
36
38
|
|
|
37
|
-
|
|
39
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
|
40
|
+
def process! # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/PerceivedComplexity
|
|
38
41
|
if @opts.config?
|
|
39
42
|
_set_config # move to init
|
|
40
43
|
elsif @opts.clear?
|
|
41
44
|
require_relative 'db'
|
|
42
45
|
Chelsea::DB.new.clear_cache
|
|
43
|
-
puts
|
|
46
|
+
puts 'OSS Index cache cleared'
|
|
44
47
|
elsif @opts.file? && @opts.iq?
|
|
45
48
|
dependencies = _process_file_iq
|
|
46
49
|
_submit_sbom(dependencies)
|
|
47
50
|
elsif !@opts.file? && @opts.iq?
|
|
48
|
-
abort
|
|
51
|
+
abort 'Missing the --file argument. It is required with the --iq argument.'
|
|
49
52
|
elsif @opts.file?
|
|
50
53
|
_process_file
|
|
51
54
|
elsif @opts.help? # quit on opts.help earlier
|
|
52
55
|
puts _cli_flags # this doesn't exist
|
|
53
56
|
else
|
|
54
|
-
abort
|
|
57
|
+
abort 'Missing arguments! Chelsea did nothing. Try providing the --file <Gemfile.lock> argument.'
|
|
55
58
|
end
|
|
56
59
|
end
|
|
60
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
|
57
61
|
|
|
58
62
|
def self.version
|
|
59
63
|
Chelsea::VERSION
|
|
@@ -61,7 +65,7 @@ module Chelsea
|
|
|
61
65
|
|
|
62
66
|
private
|
|
63
67
|
|
|
64
|
-
def _submit_sbom(gems)
|
|
68
|
+
def _submit_sbom(gems) # rubocop:disable Metrics/MethodLength
|
|
65
69
|
iq = Chelsea::IQClient.new(
|
|
66
70
|
options: {
|
|
67
71
|
public_application_id: @opts[:application],
|
|
@@ -74,7 +78,7 @@ module Chelsea
|
|
|
74
78
|
bom = Chelsea::Bom.new(gems.deps.dependencies).collect
|
|
75
79
|
|
|
76
80
|
status_url = iq.post_sbom(bom)
|
|
77
|
-
|
|
81
|
+
|
|
78
82
|
return unless status_url
|
|
79
83
|
|
|
80
84
|
msg, color, exit_code = iq.poll_status(status_url)
|
|
@@ -131,7 +135,7 @@ module Chelsea
|
|
|
131
135
|
|
|
132
136
|
def _flags_set?
|
|
133
137
|
# I'm still unsure what this is trying to express
|
|
134
|
-
valid_flags = _flags.collect {|arg| @opts[arg] }.compact
|
|
138
|
+
valid_flags = _flags.collect { |arg| @opts[arg] }.compact
|
|
135
139
|
valid_flags.count > 1
|
|
136
140
|
end
|
|
137
141
|
|
|
@@ -143,7 +147,7 @@ module Chelsea
|
|
|
143
147
|
def _show_logo
|
|
144
148
|
font = TTY::Font.new(:doom)
|
|
145
149
|
puts @pastel.green(font.write('Chelsea'))
|
|
146
|
-
puts @pastel.green(
|
|
150
|
+
puts @pastel.green("Version: #{CLI.version}")
|
|
147
151
|
end
|
|
148
152
|
|
|
149
153
|
def _load_config
|
data/lib/chelsea/config.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
#
|
|
2
4
|
# Copyright 2019-Present Sonatype Inc.
|
|
3
5
|
#
|
|
@@ -17,6 +19,7 @@
|
|
|
17
19
|
require 'yaml'
|
|
18
20
|
require_relative 'oss_index'
|
|
19
21
|
|
|
22
|
+
# Saved credentials
|
|
20
23
|
module Chelsea
|
|
21
24
|
@oss_index_config_location = File.join(Dir.home.to_s, '.ossindex')
|
|
22
25
|
@oss_index_config_filename = '.oss-index-config'
|
|
@@ -43,10 +46,8 @@ module Chelsea
|
|
|
43
46
|
@client
|
|
44
47
|
end
|
|
45
48
|
|
|
46
|
-
def self.oss_index_config
|
|
47
|
-
if
|
|
48
|
-
{ oss_index_user_name: '', oss_index_user_token: '' }
|
|
49
|
-
else
|
|
49
|
+
def self.oss_index_config # rubocop:disable Metrics/MethodLength
|
|
50
|
+
if File.exist? File.join(@oss_index_config_location, @oss_index_config_filename)
|
|
50
51
|
conf_hash = YAML.safe_load(
|
|
51
52
|
File.read(
|
|
52
53
|
File.join(@oss_index_config_location, @oss_index_config_filename)
|
|
@@ -56,6 +57,8 @@ module Chelsea
|
|
|
56
57
|
oss_index_user_name: conf_hash['Username'],
|
|
57
58
|
oss_index_user_token: conf_hash['Token']
|
|
58
59
|
}
|
|
60
|
+
else
|
|
61
|
+
{ oss_index_user_name: '', oss_index_user_token: '' }
|
|
59
62
|
end
|
|
60
63
|
end
|
|
61
64
|
|
|
@@ -71,20 +74,18 @@ module Chelsea
|
|
|
71
74
|
config = {}
|
|
72
75
|
|
|
73
76
|
puts 'What username do you want to authenticate as (ex: your email address)? '
|
|
74
|
-
config['Username'] =
|
|
77
|
+
config['Username'] = $stdin.gets.chomp
|
|
75
78
|
|
|
76
79
|
puts 'What token do you want to use? '
|
|
77
|
-
config['Token'] =
|
|
80
|
+
config['Token'] = $stdin.gets.chomp
|
|
78
81
|
|
|
79
82
|
_write_oss_index_config_file(config)
|
|
80
83
|
end
|
|
81
84
|
|
|
82
85
|
def self._write_oss_index_config_file(config)
|
|
83
|
-
unless File.exist? @oss_index_config_location
|
|
84
|
-
|
|
85
|
-
end
|
|
86
|
-
File.open(File.join(@oss_index_config_location, @oss_index_config_filename), "w") do |file|
|
|
86
|
+
Dir.mkdir(@oss_index_config_location) unless File.exist? @oss_index_config_location
|
|
87
|
+
File.open(File.join(@oss_index_config_location, @oss_index_config_filename), 'w') do |file|
|
|
87
88
|
file.write config.to_yaml
|
|
88
89
|
end
|
|
89
90
|
end
|
|
90
|
-
end
|
|
91
|
+
end
|
data/lib/chelsea/db.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
#
|
|
2
4
|
# Copyright 2019-Present Sonatype Inc.
|
|
3
5
|
#
|
|
@@ -17,6 +19,7 @@
|
|
|
17
19
|
require 'pstore'
|
|
18
20
|
|
|
19
21
|
module Chelsea
|
|
22
|
+
# OSS Index data cache
|
|
20
23
|
class DB
|
|
21
24
|
def initialize
|
|
22
25
|
@store = PStore.new(_get_db_store_location)
|
|
@@ -45,7 +48,7 @@ module Chelsea
|
|
|
45
48
|
end
|
|
46
49
|
end
|
|
47
50
|
|
|
48
|
-
def _get_db_store_location
|
|
51
|
+
def _get_db_store_location
|
|
49
52
|
initial_path = File.join(Dir.home.to_s, '.ossindex')
|
|
50
53
|
Dir.mkdir(initial_path) unless File.exist? initial_path
|
|
51
54
|
File.join(initial_path, 'chelsea.pstore')
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
#
|
|
2
4
|
# Copyright 2019-Present Sonatype Inc.
|
|
3
5
|
#
|
|
@@ -15,8 +17,9 @@
|
|
|
15
17
|
#
|
|
16
18
|
|
|
17
19
|
module Chelsea
|
|
20
|
+
# Project dependency exception
|
|
18
21
|
class DependencyException < StandardError
|
|
19
|
-
def initialize(msg=
|
|
22
|
+
def initialize(msg = 'This is a custom exception', exception_type = 'custom')
|
|
20
23
|
@exception_type = exception_type
|
|
21
24
|
super(msg)
|
|
22
25
|
end
|
data/lib/chelsea/deps.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
#
|
|
2
4
|
# Copyright 2019-Present Sonatype Inc.
|
|
3
5
|
#
|
|
@@ -22,6 +24,7 @@ require 'json'
|
|
|
22
24
|
require 'rest-client'
|
|
23
25
|
|
|
24
26
|
module Chelsea
|
|
27
|
+
# Project dependencies
|
|
25
28
|
class Deps
|
|
26
29
|
def initialize(path:, verbose: false)
|
|
27
30
|
@verbose = verbose
|
|
@@ -47,7 +50,7 @@ module Chelsea
|
|
|
47
50
|
|
|
48
51
|
# Collects all reverse dependencies in reverse_dependencies instance var
|
|
49
52
|
# this rescue block honks
|
|
50
|
-
def reverse_dependencies
|
|
53
|
+
def reverse_dependencies # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
|
51
54
|
reverse = Gem::Commands::DependencyCommand.new
|
|
52
55
|
reverse.options[:reverse_dependencies] = true
|
|
53
56
|
# We want to filter the reverses dependencies by specs in lockfile
|
|
@@ -68,7 +71,7 @@ module Chelsea
|
|
|
68
71
|
# in dependencies_versions and coordinates instance vars
|
|
69
72
|
def coordinates
|
|
70
73
|
dependencies.each_with_object({ 'coordinates' => [] }) do |(name, v), coords|
|
|
71
|
-
coords['coordinates'] << self.class.to_purl(name, v[1])
|
|
74
|
+
coords['coordinates'] << self.class.to_purl(name, v[1])
|
|
72
75
|
end
|
|
73
76
|
end
|
|
74
77
|
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
#
|
|
2
4
|
# Copyright 2019-Present Sonatype Inc.
|
|
3
5
|
#
|
|
@@ -20,7 +22,7 @@ require_relative 'text'
|
|
|
20
22
|
|
|
21
23
|
# Factory for formatting dependencies
|
|
22
24
|
class FormatterFactory
|
|
23
|
-
def get_formatter(format: 'text'
|
|
25
|
+
def get_formatter(verbose:, format: 'text')
|
|
24
26
|
case format
|
|
25
27
|
when 'text'
|
|
26
28
|
Chelsea::TextFormatter.new verbose: verbose
|
|
@@ -28,7 +30,7 @@ class FormatterFactory
|
|
|
28
30
|
Chelsea::JsonFormatter.new verbose: verbose
|
|
29
31
|
when 'xml'
|
|
30
32
|
Chelsea::XMLFormatter.new verbose: verbose
|
|
31
|
-
else
|
|
33
|
+
else # rubocop:disable Lint/DuplicateBranch
|
|
32
34
|
Chelsea::TextFormatter.new verbose: verbose
|
|
33
35
|
end
|
|
34
36
|
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
#
|
|
2
4
|
# Copyright 2019-Present Sonatype Inc.
|
|
3
5
|
#
|
|
@@ -14,15 +16,17 @@
|
|
|
14
16
|
# limitations under the License.
|
|
15
17
|
#
|
|
16
18
|
|
|
19
|
+
# Base formatter class
|
|
17
20
|
class Formatter
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
end
|
|
21
|
+
def initialize
|
|
22
|
+
@pastel = Pastel.new
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def fetch_results
|
|
26
|
+
raise 'must implement get_results method in subclass'
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def do_print
|
|
30
|
+
raise 'must implement do_print method in subclass'
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
#
|
|
2
4
|
# Copyright 2019-Present Sonatype Inc.
|
|
3
5
|
#
|
|
@@ -18,12 +20,14 @@ require 'json'
|
|
|
18
20
|
require_relative 'formatter'
|
|
19
21
|
|
|
20
22
|
module Chelsea
|
|
23
|
+
# Produce output in json format
|
|
21
24
|
class JsonFormatter < Formatter
|
|
22
25
|
def initialize(options)
|
|
26
|
+
super()
|
|
23
27
|
@options = options
|
|
24
28
|
end
|
|
25
29
|
|
|
26
|
-
def
|
|
30
|
+
def fetch_results(server_response, _reverse_deps)
|
|
27
31
|
server_response.to_json
|
|
28
32
|
end
|
|
29
33
|
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
# rubocop:disable Style/FrozenStringLiteralComment
|
|
2
|
+
# rubocop:enable Style/FrozenStringLiteralComment
|
|
3
|
+
|
|
1
4
|
#
|
|
2
5
|
# Copyright 2019-Present Sonatype Inc.
|
|
3
6
|
#
|
|
@@ -19,13 +22,16 @@ require 'tty-table'
|
|
|
19
22
|
require_relative 'formatter'
|
|
20
23
|
|
|
21
24
|
module Chelsea
|
|
25
|
+
# Produce output in text format
|
|
22
26
|
class TextFormatter < Formatter
|
|
23
27
|
def initialize(options)
|
|
28
|
+
super()
|
|
24
29
|
@options = options
|
|
25
30
|
@pastel = Pastel.new
|
|
26
31
|
end
|
|
27
32
|
|
|
28
|
-
|
|
33
|
+
# rubocop:disable Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity, Metrics/AbcSize
|
|
34
|
+
def fetch_results(server_response, reverse_dependencies) # rubocop:disable Metrics/MethodLength
|
|
29
35
|
response = ''
|
|
30
36
|
if @options[:verbose]
|
|
31
37
|
response += "\n"\
|
|
@@ -65,6 +71,7 @@ module Chelsea
|
|
|
65
71
|
response += table.render(:unicode)
|
|
66
72
|
response
|
|
67
73
|
end
|
|
74
|
+
# rubocop:enable Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity, Metrics/AbcSize
|
|
68
75
|
|
|
69
76
|
def do_print(results)
|
|
70
77
|
puts results
|
|
@@ -109,9 +116,7 @@ module Chelsea
|
|
|
109
116
|
def _get_reverse_deps(coords, name)
|
|
110
117
|
coords.each_with_object('') do |dep, s|
|
|
111
118
|
dep.each do |gran|
|
|
112
|
-
if gran.
|
|
113
|
-
s << "\tRequired by: #{gran}\n"
|
|
114
|
-
end
|
|
119
|
+
s << "\tRequired by: #{gran}\n" if gran.instance_of?(String) && !gran.include?(name)
|
|
115
120
|
end
|
|
116
121
|
end
|
|
117
122
|
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
#
|
|
2
4
|
# Copyright 2019-Present Sonatype Inc.
|
|
3
5
|
#
|
|
@@ -17,12 +19,14 @@
|
|
|
17
19
|
require 'ox'
|
|
18
20
|
require_relative 'formatter'
|
|
19
21
|
module Chelsea
|
|
22
|
+
# Produce output in xml format
|
|
20
23
|
class XMLFormatter < Formatter
|
|
21
24
|
def initialize(options)
|
|
25
|
+
super()
|
|
22
26
|
@options = options
|
|
23
27
|
end
|
|
24
28
|
|
|
25
|
-
def
|
|
29
|
+
def fetch_results(server_response, _reverse_deps) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
|
26
30
|
doc = Ox::Document.new
|
|
27
31
|
instruct = Ox::Instruct.new(:xml)
|
|
28
32
|
instruct[:version] = '1.0'
|
|
@@ -37,13 +41,13 @@ module Chelsea
|
|
|
37
41
|
|
|
38
42
|
server_response.each do |coord|
|
|
39
43
|
testcase = Ox::Element.new('testcase')
|
|
40
|
-
testcase[:classname] = coord[
|
|
41
|
-
testcase[:name] = coord[
|
|
44
|
+
testcase[:classname] = coord['coordinates']
|
|
45
|
+
testcase[:name] = coord['coordinates']
|
|
42
46
|
|
|
43
47
|
if coord['vulnerabilities'].length.positive?
|
|
44
48
|
failure = Ox::Element.new('failure')
|
|
45
|
-
failure[:type] =
|
|
46
|
-
failure << get_vulnerability_block(coord[
|
|
49
|
+
failure[:type] = 'Vulnerable Dependency'
|
|
50
|
+
failure << get_vulnerability_block(coord['vulnerabilities'])
|
|
47
51
|
testcase << failure
|
|
48
52
|
testsuite << testcase
|
|
49
53
|
elsif @options[:verbose]
|
|
@@ -58,20 +62,20 @@ module Chelsea
|
|
|
58
62
|
puts Ox.dump(results)
|
|
59
63
|
end
|
|
60
64
|
|
|
61
|
-
def get_vulnerability_block(vulnerabilities)
|
|
62
|
-
|
|
65
|
+
def get_vulnerability_block(vulnerabilities) # rubocop:disable Metrics/MethodLength
|
|
66
|
+
vuln_block = ''
|
|
63
67
|
vulnerabilities.each do |vuln|
|
|
64
|
-
|
|
65
|
-
"ID: #{vuln[
|
|
66
|
-
"Description: #{vuln[
|
|
67
|
-
"CVSS Score: #{vuln[
|
|
68
|
-
"CVSS Vector: #{vuln[
|
|
69
|
-
"CVE: #{vuln[
|
|
70
|
-
"Reference: #{vuln[
|
|
68
|
+
vuln_block += "Vulnerability Title: #{vuln['title']}\n"\
|
|
69
|
+
"ID: #{vuln['id']}\n"\
|
|
70
|
+
"Description: #{vuln['description']}\n"\
|
|
71
|
+
"CVSS Score: #{vuln['cvssScore']}\n"\
|
|
72
|
+
"CVSS Vector: #{vuln['cvssVector']}\n"\
|
|
73
|
+
"CVE: #{vuln['cve']}\n"\
|
|
74
|
+
"Reference: #{vuln['reference']}"\
|
|
71
75
|
"\n"
|
|
72
76
|
end
|
|
73
|
-
|
|
74
|
-
|
|
77
|
+
|
|
78
|
+
vuln_block
|
|
75
79
|
end
|
|
76
80
|
end
|
|
77
81
|
end
|
data/lib/chelsea/gems.rb
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
#
|
|
16
16
|
|
|
17
17
|
# frozen_string_literal: true
|
|
18
|
+
|
|
18
19
|
require 'pastel'
|
|
19
20
|
require 'bundler'
|
|
20
21
|
require 'bundler/lockfile_parser'
|
|
@@ -31,11 +32,10 @@ module Chelsea
|
|
|
31
32
|
# Class to collect and audit packages from a Gemfile.lock
|
|
32
33
|
class Gems
|
|
33
34
|
attr_accessor :deps
|
|
34
|
-
|
|
35
|
+
|
|
36
|
+
def initialize(file:, verbose:, options: { format: 'text' }) # rubocop:disable Metrics/MethodLength
|
|
35
37
|
@verbose = verbose
|
|
36
|
-
unless File.file?(file) || file.nil?
|
|
37
|
-
raise 'Gemfile.lock not found, check --file path'
|
|
38
|
-
end
|
|
38
|
+
raise 'Gemfile.lock not found, check --file path' unless File.file?(file) || file.nil?
|
|
39
39
|
|
|
40
40
|
_silence_stderr unless @verbose
|
|
41
41
|
|
|
@@ -52,7 +52,7 @@ module Chelsea
|
|
|
52
52
|
# Audits depenencies using deps library and prints results
|
|
53
53
|
# using formatter library
|
|
54
54
|
|
|
55
|
-
def execute
|
|
55
|
+
def execute # rubocop:disable Metrics/MethodLength
|
|
56
56
|
server_response, dependencies, reverse_dependencies = audit
|
|
57
57
|
if dependencies.nil?
|
|
58
58
|
_print_err 'No dependencies retrieved. Exiting.'
|
|
@@ -62,20 +62,19 @@ module Chelsea
|
|
|
62
62
|
_print_success 'No vulnerability data retrieved from server. Exiting.'
|
|
63
63
|
return
|
|
64
64
|
end
|
|
65
|
-
results = @formatter.
|
|
65
|
+
results = @formatter.fetch_results(server_response, reverse_dependencies)
|
|
66
66
|
@formatter.do_print(results)
|
|
67
67
|
|
|
68
68
|
server_response.map { |r| r['vulnerabilities'].length.positive? }.any?
|
|
69
69
|
end
|
|
70
70
|
|
|
71
71
|
def collect_iq
|
|
72
|
-
|
|
73
|
-
dependencies
|
|
72
|
+
@deps.dependencies
|
|
74
73
|
end
|
|
75
74
|
|
|
76
75
|
# Runs through auditing algorithm, raising exceptions
|
|
77
76
|
# on REST calls made by @deps.get_vulns
|
|
78
|
-
def audit
|
|
77
|
+
def audit # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
|
79
78
|
# This spinner management is out of control
|
|
80
79
|
# we should wrap a block with start and stop messages,
|
|
81
80
|
# or use a stack to ensure all spinners stop.
|
|
@@ -84,7 +83,7 @@ module Chelsea
|
|
|
84
83
|
begin
|
|
85
84
|
dependencies = @deps.dependencies
|
|
86
85
|
spin.success('...done.')
|
|
87
|
-
rescue StandardError
|
|
86
|
+
rescue StandardError
|
|
88
87
|
spin.stop
|
|
89
88
|
_print_err "Parsing dependency line #{gem} failed."
|
|
90
89
|
end
|
|
@@ -100,16 +99,16 @@ module Chelsea
|
|
|
100
99
|
begin
|
|
101
100
|
server_response = @client.get_vulns(coordinates)
|
|
102
101
|
spin.success('...done.')
|
|
103
|
-
rescue SocketError
|
|
102
|
+
rescue SocketError
|
|
104
103
|
spin.stop('...request failed.')
|
|
105
104
|
_print_err 'Socket error getting data from OSS Index server.'
|
|
106
105
|
rescue RestClient::RequestFailed => e
|
|
107
106
|
spin.stop('...request failed.')
|
|
108
107
|
_print_err "Error getting data from OSS Index server:#{e.response}."
|
|
109
|
-
rescue RestClient::ResourceNotFound
|
|
108
|
+
rescue RestClient::ResourceNotFound
|
|
110
109
|
spin.stop('...request failed.')
|
|
111
110
|
_print_err 'Error getting data from OSS Index server. Resource not found.'
|
|
112
|
-
rescue Errno::ECONNREFUSED
|
|
111
|
+
rescue Errno::ECONNREFUSED
|
|
113
112
|
spin.stop('...request failed.')
|
|
114
113
|
_print_err 'Error getting data from OSS Index server. Connection refused.'
|
|
115
114
|
end
|
|
@@ -122,12 +121,12 @@ module Chelsea
|
|
|
122
121
|
$stderr.reopen('/dev/null', 'w')
|
|
123
122
|
end
|
|
124
123
|
|
|
125
|
-
def _print_err(
|
|
126
|
-
puts @pastel.red.bold(
|
|
124
|
+
def _print_err(msg)
|
|
125
|
+
puts @pastel.red.bold(msg)
|
|
127
126
|
end
|
|
128
127
|
|
|
129
|
-
def _print_success(
|
|
130
|
-
puts @pastel.green.bold(
|
|
128
|
+
def _print_success(msg)
|
|
129
|
+
puts @pastel.green.bold(msg)
|
|
131
130
|
end
|
|
132
131
|
end
|
|
133
132
|
end
|
data/lib/chelsea/iq_client.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
#
|
|
2
4
|
# Copyright 2019-Present Sonatype Inc.
|
|
3
5
|
#
|
|
@@ -22,8 +24,8 @@ require 'uri'
|
|
|
22
24
|
require_relative 'spinner'
|
|
23
25
|
|
|
24
26
|
module Chelsea
|
|
25
|
-
|
|
26
|
-
|
|
27
|
+
# IQ audit operations
|
|
28
|
+
class IQClient # rubocop:disable Metrics/ClassLength
|
|
27
29
|
DEFAULT_OPTIONS = {
|
|
28
30
|
public_application_id: 'testapp',
|
|
29
31
|
server_url: 'http://localhost:8070',
|
|
@@ -31,7 +33,7 @@ module Chelsea
|
|
|
31
33
|
auth_token: 'admin123',
|
|
32
34
|
internal_application_id: '',
|
|
33
35
|
stage: 'build'
|
|
34
|
-
}
|
|
36
|
+
}.freeze
|
|
35
37
|
|
|
36
38
|
def initialize(options: DEFAULT_OPTIONS)
|
|
37
39
|
@options = options
|
|
@@ -39,8 +41,8 @@ module Chelsea
|
|
|
39
41
|
@spinner = Chelsea::Spinner.new
|
|
40
42
|
end
|
|
41
43
|
|
|
42
|
-
def post_sbom(sbom)
|
|
43
|
-
spin = @spinner.spin_msg
|
|
44
|
+
def post_sbom(sbom) # rubocop:disable Metrics/MethodLength
|
|
45
|
+
spin = @spinner.spin_msg 'Submitting sbom to Nexus IQ Server'
|
|
44
46
|
@internal_application_id = _get_internal_application_id
|
|
45
47
|
resource = RestClient::Resource.new(
|
|
46
48
|
_api_url,
|
|
@@ -48,12 +50,12 @@ module Chelsea
|
|
|
48
50
|
password: @options[:auth_token]
|
|
49
51
|
)
|
|
50
52
|
res = resource.post sbom.to_s, _headers.merge(content_type: 'application/xml')
|
|
51
|
-
if res.code
|
|
53
|
+
if res.code == 202
|
|
54
|
+
spin.success('...done.')
|
|
55
|
+
status_url(res)
|
|
56
|
+
else
|
|
52
57
|
spin.stop('...request failed.')
|
|
53
58
|
nil
|
|
54
|
-
else
|
|
55
|
-
spin.success("...done.")
|
|
56
|
-
status_url(res)
|
|
57
59
|
end
|
|
58
60
|
end
|
|
59
61
|
|
|
@@ -63,17 +65,15 @@ module Chelsea
|
|
|
63
65
|
end
|
|
64
66
|
|
|
65
67
|
def poll_status(url)
|
|
66
|
-
spin = @spinner.spin_msg
|
|
68
|
+
spin = @spinner.spin_msg 'Polling Nexus IQ Server for results'
|
|
67
69
|
loop do
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
return _handle_response(res)
|
|
73
|
-
end
|
|
74
|
-
rescue
|
|
75
|
-
sleep(1)
|
|
70
|
+
res = _poll_iq_server(url)
|
|
71
|
+
if res.code == 200
|
|
72
|
+
spin.success('...done.')
|
|
73
|
+
return _handle_response(res)
|
|
76
74
|
end
|
|
75
|
+
rescue StandardError
|
|
76
|
+
sleep(1)
|
|
77
77
|
end
|
|
78
78
|
end
|
|
79
79
|
|
|
@@ -88,28 +88,28 @@ module Chelsea
|
|
|
88
88
|
|
|
89
89
|
private
|
|
90
90
|
|
|
91
|
-
def _handle_response(res)
|
|
91
|
+
def _handle_response(res) # rubocop:disable Metrics/MethodLength
|
|
92
92
|
res = JSON.parse(res.body)
|
|
93
93
|
# get absolute report url
|
|
94
94
|
absolute_report_html_url = URI.join(@options[:server_url], res['reportHtmlUrl'])
|
|
95
95
|
|
|
96
96
|
case res['policyAction']
|
|
97
97
|
when POLICY_ACTION_FAILURE
|
|
98
|
-
|
|
98
|
+
['Hi! Chelsea here, you have some policy violations to clean up!'\
|
|
99
99
|
"\nReport URL: #{absolute_report_html_url}",
|
|
100
|
-
|
|
100
|
+
COLOR_FAILURE, 1]
|
|
101
101
|
when POLICY_ACTION_WARNING
|
|
102
|
-
|
|
102
|
+
['Hi! Chelsea here, you have some policy warnings to peck at!'\
|
|
103
103
|
"\nReport URL: #{absolute_report_html_url}",
|
|
104
|
-
|
|
104
|
+
COLOR_WARNING, 0]
|
|
105
105
|
when POLICY_ACTION_NONE
|
|
106
|
-
|
|
106
|
+
['Hi! Chelsea here, no policy violations for this audit!'\
|
|
107
107
|
"\nReport URL: #{absolute_report_html_url}",
|
|
108
|
-
|
|
108
|
+
COLOR_NONE, 0]
|
|
109
109
|
else
|
|
110
|
-
|
|
110
|
+
['Hi! Chelsea here, no policy violations for this audit, but unknown policy action!'\
|
|
111
111
|
"\nReport URL: #{absolute_report_html_url}",
|
|
112
|
-
|
|
112
|
+
COLOR_FAILURE, 1]
|
|
113
113
|
end
|
|
114
114
|
end
|
|
115
115
|
|
|
@@ -137,26 +137,22 @@ module Chelsea
|
|
|
137
137
|
res['statusUrl']
|
|
138
138
|
end
|
|
139
139
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
def _poll_status
|
|
140
|
+
def _poll_status # rubocop:disable Metrics/MethodLength
|
|
143
141
|
return unless @status_url
|
|
144
142
|
|
|
145
143
|
loop do
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
break
|
|
151
|
-
end
|
|
152
|
-
rescue RestClient::ResourceNotFound => _e
|
|
153
|
-
print '.'
|
|
154
|
-
sleep(1)
|
|
144
|
+
res = check_status(@status_url)
|
|
145
|
+
if res.code == 200
|
|
146
|
+
puts JSON.parse(res.body)
|
|
147
|
+
break
|
|
155
148
|
end
|
|
149
|
+
rescue RestClient::ResourceNotFound => _e
|
|
150
|
+
print '.'
|
|
151
|
+
sleep(1)
|
|
156
152
|
end
|
|
157
153
|
end
|
|
158
154
|
|
|
159
|
-
def _get_internal_application_id
|
|
155
|
+
def _get_internal_application_id # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
|
160
156
|
resource = RestClient::Resource.new(
|
|
161
157
|
_internal_application_id_api_url,
|
|
162
158
|
user: @options[:username],
|
|
@@ -164,7 +160,7 @@ module Chelsea
|
|
|
164
160
|
)
|
|
165
161
|
res = resource.get _headers
|
|
166
162
|
if res.code != 200
|
|
167
|
-
puts "
|
|
163
|
+
puts "failure reading application id: #{@options[:public_application_id]}. response status: #{res.code}"
|
|
168
164
|
return
|
|
169
165
|
end
|
|
170
166
|
body = JSON.parse(res)
|
|
@@ -180,7 +176,9 @@ module Chelsea
|
|
|
180
176
|
end
|
|
181
177
|
|
|
182
178
|
def _api_url
|
|
179
|
+
# rubocop:disable Layout/LineLength
|
|
183
180
|
"#{@options[:server_url]}/api/v2/scan/applications/#{@internal_application_id}/sources/chelsea?stageId=#{@options[:stage]}"
|
|
181
|
+
# rubocop:enable Layout/LineLength
|
|
184
182
|
end
|
|
185
183
|
|
|
186
184
|
def _internal_application_id_api_url
|
data/lib/chelsea/oss_index.rb
CHANGED
|
@@ -21,11 +21,12 @@ require 'rest-client'
|
|
|
21
21
|
require_relative 'db'
|
|
22
22
|
|
|
23
23
|
module Chelsea
|
|
24
|
+
# OSS Index audit operations
|
|
24
25
|
class OSSIndex
|
|
25
26
|
DEFAULT_OPTIONS = {
|
|
26
27
|
oss_index_username: '',
|
|
27
28
|
oss_index_user_token: ''
|
|
28
|
-
}
|
|
29
|
+
}.freeze
|
|
29
30
|
def initialize(options: DEFAULT_OPTIONS)
|
|
30
31
|
@oss_index_user_name = options[:oss_index_user_name]
|
|
31
32
|
@oss_index_user_token = options[:oss_index_user_token]
|
|
@@ -37,13 +38,11 @@ module Chelsea
|
|
|
37
38
|
|
|
38
39
|
def get_vulns(coordinates)
|
|
39
40
|
remaining_coordinates, cached_server_response = _cache(coordinates)
|
|
40
|
-
unless remaining_coordinates['coordinates'].count.positive?
|
|
41
|
-
return cached_server_response
|
|
42
|
-
end
|
|
41
|
+
return cached_server_response unless remaining_coordinates['coordinates'].count.positive?
|
|
43
42
|
|
|
44
43
|
remaining_coordinates['coordinates'].each_slice(128).to_a.each do |coords|
|
|
45
44
|
res_json = JSON.parse(call_oss_index({ 'coordinates' => coords }))
|
|
46
|
-
cached_server_response
|
|
45
|
+
cached_server_response.concat(res_json)
|
|
47
46
|
@db.save_values_to_db(res_json)
|
|
48
47
|
end
|
|
49
48
|
|
|
@@ -57,15 +56,15 @@ module Chelsea
|
|
|
57
56
|
|
|
58
57
|
private
|
|
59
58
|
|
|
60
|
-
def _cache(coordinates)
|
|
59
|
+
def _cache(coordinates) # rubocop:disable Metrics/MethodLength
|
|
61
60
|
new_coords = { 'coordinates' => [] }
|
|
62
61
|
cached_server_response = []
|
|
63
62
|
coordinates['coordinates'].each do |coord|
|
|
64
63
|
record = @db.get_cached_value_from_db(coord)
|
|
65
|
-
if
|
|
66
|
-
cached_server_response << record
|
|
67
|
-
else
|
|
64
|
+
if record.nil?
|
|
68
65
|
new_coords['coordinates'].push(coord)
|
|
66
|
+
else
|
|
67
|
+
cached_server_response << record
|
|
69
68
|
end
|
|
70
69
|
end
|
|
71
70
|
[new_coords, cached_server_response]
|
data/lib/chelsea/spinner.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
#
|
|
2
4
|
# Copyright 2019-Present Sonatype Inc.
|
|
3
5
|
#
|
|
@@ -18,6 +20,7 @@ require 'tty-spinner'
|
|
|
18
20
|
require 'pastel'
|
|
19
21
|
|
|
20
22
|
module Chelsea
|
|
23
|
+
# the spinner we use in Chelsea, needs work
|
|
21
24
|
class Spinner
|
|
22
25
|
def initialize
|
|
23
26
|
@pastel = Pastel.new
|
data/lib/chelsea/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: chelsea
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.28
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Allister Beharry
|
|
@@ -11,109 +11,109 @@ cert_chain: []
|
|
|
11
11
|
date: 2021-01-29 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
|
-
name:
|
|
14
|
+
name: bundler
|
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
|
16
16
|
requirements:
|
|
17
|
-
- - "
|
|
17
|
+
- - ">="
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
|
-
version:
|
|
19
|
+
version: 1.2.0
|
|
20
|
+
- - "<"
|
|
21
|
+
- !ruby/object:Gem::Version
|
|
22
|
+
version: '3'
|
|
20
23
|
type: :runtime
|
|
21
24
|
prerelease: false
|
|
22
25
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
26
|
requirements:
|
|
24
|
-
- - "
|
|
27
|
+
- - ">="
|
|
25
28
|
- !ruby/object:Gem::Version
|
|
26
|
-
version:
|
|
29
|
+
version: 1.2.0
|
|
30
|
+
- - "<"
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '3'
|
|
27
33
|
- !ruby/object:Gem::Dependency
|
|
28
|
-
name:
|
|
34
|
+
name: ox
|
|
29
35
|
requirement: !ruby/object:Gem::Requirement
|
|
30
36
|
requirements:
|
|
31
37
|
- - "~>"
|
|
32
38
|
- !ruby/object:Gem::Version
|
|
33
|
-
version:
|
|
39
|
+
version: 2.13.2
|
|
34
40
|
type: :runtime
|
|
35
41
|
prerelease: false
|
|
36
42
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
43
|
requirements:
|
|
38
44
|
- - "~>"
|
|
39
45
|
- !ruby/object:Gem::Version
|
|
40
|
-
version:
|
|
46
|
+
version: 2.13.2
|
|
41
47
|
- !ruby/object:Gem::Dependency
|
|
42
|
-
name:
|
|
48
|
+
name: pastel
|
|
43
49
|
requirement: !ruby/object:Gem::Requirement
|
|
44
50
|
requirements:
|
|
45
51
|
- - "~>"
|
|
46
52
|
- !ruby/object:Gem::Version
|
|
47
|
-
version:
|
|
53
|
+
version: 0.7.2
|
|
48
54
|
type: :runtime
|
|
49
55
|
prerelease: false
|
|
50
56
|
version_requirements: !ruby/object:Gem::Requirement
|
|
51
57
|
requirements:
|
|
52
58
|
- - "~>"
|
|
53
59
|
- !ruby/object:Gem::Version
|
|
54
|
-
version:
|
|
60
|
+
version: 0.7.2
|
|
55
61
|
- !ruby/object:Gem::Dependency
|
|
56
|
-
name:
|
|
62
|
+
name: rest-client
|
|
57
63
|
requirement: !ruby/object:Gem::Requirement
|
|
58
64
|
requirements:
|
|
59
65
|
- - "~>"
|
|
60
66
|
- !ruby/object:Gem::Version
|
|
61
|
-
version: 0.
|
|
67
|
+
version: 2.0.2
|
|
62
68
|
type: :runtime
|
|
63
69
|
prerelease: false
|
|
64
70
|
version_requirements: !ruby/object:Gem::Requirement
|
|
65
71
|
requirements:
|
|
66
72
|
- - "~>"
|
|
67
73
|
- !ruby/object:Gem::Version
|
|
68
|
-
version: 0.
|
|
74
|
+
version: 2.0.2
|
|
69
75
|
- !ruby/object:Gem::Dependency
|
|
70
|
-
name:
|
|
76
|
+
name: slop
|
|
71
77
|
requirement: !ruby/object:Gem::Requirement
|
|
72
78
|
requirements:
|
|
73
79
|
- - "~>"
|
|
74
80
|
- !ruby/object:Gem::Version
|
|
75
|
-
version:
|
|
81
|
+
version: 4.8.1
|
|
76
82
|
type: :runtime
|
|
77
83
|
prerelease: false
|
|
78
84
|
version_requirements: !ruby/object:Gem::Requirement
|
|
79
85
|
requirements:
|
|
80
86
|
- - "~>"
|
|
81
87
|
- !ruby/object:Gem::Version
|
|
82
|
-
version:
|
|
88
|
+
version: 4.8.1
|
|
83
89
|
- !ruby/object:Gem::Dependency
|
|
84
|
-
name:
|
|
90
|
+
name: tty-font
|
|
85
91
|
requirement: !ruby/object:Gem::Requirement
|
|
86
92
|
requirements:
|
|
87
|
-
- - "
|
|
88
|
-
- !ruby/object:Gem::Version
|
|
89
|
-
version: 1.2.0
|
|
90
|
-
- - "<"
|
|
93
|
+
- - "~>"
|
|
91
94
|
- !ruby/object:Gem::Version
|
|
92
|
-
version:
|
|
95
|
+
version: 0.5.0
|
|
93
96
|
type: :runtime
|
|
94
97
|
prerelease: false
|
|
95
98
|
version_requirements: !ruby/object:Gem::Requirement
|
|
96
99
|
requirements:
|
|
97
|
-
- - "
|
|
98
|
-
- !ruby/object:Gem::Version
|
|
99
|
-
version: 1.2.0
|
|
100
|
-
- - "<"
|
|
100
|
+
- - "~>"
|
|
101
101
|
- !ruby/object:Gem::Version
|
|
102
|
-
version:
|
|
102
|
+
version: 0.5.0
|
|
103
103
|
- !ruby/object:Gem::Dependency
|
|
104
|
-
name:
|
|
104
|
+
name: tty-spinner
|
|
105
105
|
requirement: !ruby/object:Gem::Requirement
|
|
106
106
|
requirements:
|
|
107
107
|
- - "~>"
|
|
108
108
|
- !ruby/object:Gem::Version
|
|
109
|
-
version:
|
|
109
|
+
version: 0.9.3
|
|
110
110
|
type: :runtime
|
|
111
111
|
prerelease: false
|
|
112
112
|
version_requirements: !ruby/object:Gem::Requirement
|
|
113
113
|
requirements:
|
|
114
114
|
- - "~>"
|
|
115
115
|
- !ruby/object:Gem::Version
|
|
116
|
-
version:
|
|
116
|
+
version: 0.9.3
|
|
117
117
|
- !ruby/object:Gem::Dependency
|
|
118
118
|
name: tty-table
|
|
119
119
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -128,6 +128,20 @@ dependencies:
|
|
|
128
128
|
- - "~>"
|
|
129
129
|
- !ruby/object:Gem::Version
|
|
130
130
|
version: 0.11.0
|
|
131
|
+
- !ruby/object:Gem::Dependency
|
|
132
|
+
name: byebug
|
|
133
|
+
requirement: !ruby/object:Gem::Requirement
|
|
134
|
+
requirements:
|
|
135
|
+
- - "~>"
|
|
136
|
+
- !ruby/object:Gem::Version
|
|
137
|
+
version: 11.1.2
|
|
138
|
+
type: :development
|
|
139
|
+
prerelease: false
|
|
140
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
141
|
+
requirements:
|
|
142
|
+
- - "~>"
|
|
143
|
+
- !ruby/object:Gem::Version
|
|
144
|
+
version: 11.1.2
|
|
131
145
|
- !ruby/object:Gem::Dependency
|
|
132
146
|
name: rake
|
|
133
147
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -184,20 +198,6 @@ dependencies:
|
|
|
184
198
|
- - "~>"
|
|
185
199
|
- !ruby/object:Gem::Version
|
|
186
200
|
version: 3.8.3
|
|
187
|
-
- !ruby/object:Gem::Dependency
|
|
188
|
-
name: byebug
|
|
189
|
-
requirement: !ruby/object:Gem::Requirement
|
|
190
|
-
requirements:
|
|
191
|
-
- - "~>"
|
|
192
|
-
- !ruby/object:Gem::Version
|
|
193
|
-
version: 11.1.2
|
|
194
|
-
type: :development
|
|
195
|
-
prerelease: false
|
|
196
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
197
|
-
requirements:
|
|
198
|
-
- - "~>"
|
|
199
|
-
- !ruby/object:Gem::Version
|
|
200
|
-
version: 11.1.2
|
|
201
201
|
description:
|
|
202
202
|
email:
|
|
203
203
|
- allister.beharry@gmail.com
|
|
@@ -217,6 +217,7 @@ files:
|
|
|
217
217
|
- ".github/pull_request_template.md"
|
|
218
218
|
- ".gitignore"
|
|
219
219
|
- ".rspec"
|
|
220
|
+
- ".rubocop.yml"
|
|
220
221
|
- ".vscode/launch.json"
|
|
221
222
|
- CODE_OF_CONDUCT.md
|
|
222
223
|
- CONTRIBUTORS.md
|
|
@@ -267,7 +268,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
267
268
|
requirements:
|
|
268
269
|
- - ">="
|
|
269
270
|
- !ruby/object:Gem::Version
|
|
270
|
-
version:
|
|
271
|
+
version: 2.6.6
|
|
271
272
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
272
273
|
requirements:
|
|
273
274
|
- - ">="
|