license_finder 7.0.0 → 7.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'open-uri'
4
4
  require 'license_finder/license'
5
+ require 'license_finder/manual_licenses'
5
6
 
6
7
  module LicenseFinder
7
8
  class Decisions
@@ -11,8 +12,8 @@ module LicenseFinder
11
12
 
12
13
  attr_reader :packages, :permitted, :restricted, :ignored, :ignored_groups, :project_name, :inherited_decisions
13
14
 
14
- def licenses_of(name)
15
- @licenses[name]
15
+ def licenses_of(name, version = nil)
16
+ @manual_licenses.licenses_of(name, version)
16
17
  end
17
18
 
18
19
  def homepage_of(name)
@@ -76,7 +77,7 @@ module LicenseFinder
76
77
  def initialize
77
78
  @decisions = []
78
79
  @packages = Set.new
79
- @licenses = Hash.new { |h, k| h[k] = Set.new }
80
+ @manual_licenses = ManualLicenses.new
80
81
  @homepages = {}
81
82
  @approvals = {}
82
83
  @permitted = Set.new
@@ -100,13 +101,29 @@ module LicenseFinder
100
101
 
101
102
  def license(name, lic, txn = {})
102
103
  add_decision [:license, name, lic, txn]
103
- @licenses[name] << License.find_by_name(lic)
104
+
105
+ versions = txn[:versions]
106
+
107
+ if versions.nil? || versions.empty?
108
+ @manual_licenses.assign_to_all_versions(name, lic)
109
+ else
110
+ @manual_licenses.assign_to_specific_versions(name, lic, versions)
111
+ end
112
+
104
113
  self
105
114
  end
106
115
 
107
116
  def unlicense(name, lic, txn = {})
108
117
  add_decision [:unlicense, name, lic, txn]
109
- @licenses[name].delete(License.find_by_name(lic))
118
+
119
+ versions = txn[:versions]
120
+
121
+ if versions.nil? || versions.empty?
122
+ @manual_licenses.unassign_from_all_versions(name, lic)
123
+ else
124
+ @manual_licenses.unassign_from_specific_versions(name, lic, versions)
125
+ end
126
+
110
127
  self
111
128
  end
112
129
 
@@ -235,9 +252,10 @@ module LicenseFinder
235
252
  end
236
253
 
237
254
  def restore_inheritance(decisions)
255
+ previous_value = @inherited
238
256
  @inherited = true
239
257
  self.class.restore(decisions, self)
240
- @inherited = false
258
+ @inherited = previous_value
241
259
  self
242
260
  end
243
261
 
@@ -265,7 +265,9 @@ module LicenseFinder
265
265
  'BSD 3',
266
266
  'BSD-3',
267
267
  '3-clause BSD',
268
+ '3-Clause BSD License',
268
269
  'BSD-3-Clause',
270
+ 'BSD 3-Clause',
269
271
  'BSD 3-Clause License',
270
272
  'The 3-Clause BSD License',
271
273
  'BSD 3-clause New License',
@@ -168,5 +168,3 @@
168
168
  defend, and hold each Contributor harmless for any liability
169
169
  incurred by, or claims asserted against, such Contributor by reason
170
170
  of your accepting any such warranty or additional liability.
171
-
172
- END OF TERMS AND CONDITIONS
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LicenseFinder
4
+ class ManualLicenses
5
+ def initialize
6
+ @all_versions = {}
7
+ @specific_versions = {}
8
+ end
9
+
10
+ def licenses_of(name, version = nil)
11
+ return @all_versions[name] if @all_versions[name]
12
+
13
+ if version && @specific_versions[name] && @specific_versions[name][version]
14
+ @specific_versions[name][version]
15
+ else
16
+ Set.new
17
+ end
18
+ end
19
+
20
+ def assign_to_all_versions(name, lic)
21
+ # Ex: licenses add foo_gem MIT => Adds MIT at "all" versions for this gem
22
+
23
+ @all_versions[name] ||= Set.new
24
+ @all_versions[name] << to_license(lic)
25
+
26
+ @specific_versions.delete(name)
27
+ end
28
+
29
+ def assign_to_specific_versions(name, lic, versions)
30
+ # Ex: licenses add foo_gem MIT --version=1.0 => Adds MIT at only 1.0 for this gem
31
+
32
+ @specific_versions[name] ||= {}
33
+ versions.each do |version|
34
+ @specific_versions[name][version] ||= Set.new
35
+ @specific_versions[name][version] << to_license(lic)
36
+ end
37
+
38
+ @all_versions.delete(name)
39
+ end
40
+
41
+ def unassign_from_all_versions(name, lic = nil)
42
+ if lic
43
+ # Ex: licenses remove foo_gem MIT => Removes MIT at all versions for this gem
44
+ @all_versions[name]&.delete(to_license(lic))
45
+
46
+ @specific_versions[name]&.each do |_version, licenses|
47
+ licenses.delete(to_license(lic))
48
+ end
49
+ else
50
+ # Ex: licenses remove foo_gem => Removes all licenses for all versions of the gem
51
+ @all_versions.delete(name)
52
+ @specific_versions.delete(name)
53
+ end
54
+ end
55
+
56
+ def unassign_from_specific_versions(name, lic, versions)
57
+ return unless @specific_versions[name]
58
+
59
+ versions.each do |version|
60
+ if @specific_versions[name][version]
61
+ if lic
62
+ # Ex: licenses remove foo_gem MIT --version=1.0 => Removes MIT at only 1.0 for this gem
63
+ @specific_versions[name][version].delete(to_license(lic))
64
+ @specific_versions[name].delete(version) if @specific_versions[name][version].empty?
65
+ else
66
+ # Ex: licenses remove foo_gem --version=1.0 => Removes all licenses at only 1.0 for the gem
67
+ @specific_versions[name].delete(version)
68
+ end
69
+ end
70
+ end
71
+ end
72
+
73
+ private
74
+
75
+ def to_license(lic)
76
+ License.find_by_name(lic)
77
+ end
78
+ end
79
+ end
@@ -187,6 +187,7 @@ require 'license_finder/packages/merged_package'
187
187
  require 'license_finder/packages/nuget_package'
188
188
  require 'license_finder/packages/conan_package'
189
189
  require 'license_finder/packages/yarn_package'
190
+ require 'license_finder/packages/pnpm_package'
190
191
  require 'license_finder/packages/sbt_package'
191
192
  require 'license_finder/packages/cargo_package'
192
193
  require 'license_finder/packages/composer_package'
@@ -158,6 +158,7 @@ require 'license_finder/package_managers/go_modules'
158
158
  require 'license_finder/package_managers/trash'
159
159
  require 'license_finder/package_managers/bundler'
160
160
  require 'license_finder/package_managers/npm'
161
+ require 'license_finder/package_managers/pnpm'
161
162
  require 'license_finder/package_managers/yarn'
162
163
  require 'license_finder/package_managers/pip'
163
164
  require 'license_finder/package_managers/pipenv'
@@ -42,9 +42,13 @@ module LicenseFinder
42
42
  end
43
43
 
44
44
  def read_license_urls
45
- possible_spec_paths.flat_map do |path|
45
+ raw_licenses = possible_spec_paths.flat_map do |path|
46
46
  Nuget.nuspec_license_urls(File.read(path)) if File.exist? path
47
47
  end.compact
48
+
49
+ raw_licenses&.map! do |license|
50
+ license.gsub('https://licenses.nuget.org/', '')
51
+ end
48
52
  end
49
53
 
50
54
  def ==(other)
@@ -61,7 +65,6 @@ module LicenseFinder
61
65
  package_metadatas = asset_files
62
66
  .flat_map { |path| AssetFile.new(path).dependencies }
63
67
  .uniq { |d| [d.name, d.version] }
64
-
65
68
  package_metadatas.map do |d|
66
69
  path = Dir.glob("#{Dir.home}/.nuget/packages/#{d.name.downcase}/#{d.version}").first
67
70
  NugetPackage.new(d.name, d.version, spec_licenses: d.read_license_urls, install_path: path)
@@ -34,14 +34,10 @@ module LicenseFinder
34
34
  end
35
35
 
36
36
  def package_management_command
37
- wrapper = if Platform.windows?
38
- 'mvnw.cmd'
39
- else
40
- './mvnw'
41
- end
37
+ wrapper = File.join(project_path, Platform.windows? ? 'mvnw.cmd' : 'mvnw')
42
38
  maven = 'mvn'
43
39
 
44
- File.exist?(File.join(project_path, wrapper)) ? wrapper : maven
40
+ File.exist?(wrapper) ? wrapper : maven
45
41
  end
46
42
 
47
43
  def possible_package_paths
@@ -51,6 +51,10 @@ module LicenseFinder
51
51
  def current_packages
52
52
  dependencies.each_with_object({}) do |dep, memo|
53
53
  licenses = license_urls(dep)
54
+ licenses&.map! do |license|
55
+ license.gsub('https://licenses.nuget.org/', '')
56
+ end
57
+
54
58
  path = Dir.glob("#{Dir.home}/.nuget/packages/#{dep.name.downcase}/#{dep.version}").first
55
59
 
56
60
  memo[dep.name] ||= NugetPackage.new(dep.name, dep.version, spec_licenses: licenses, install_path: path)
@@ -60,6 +64,7 @@ module LicenseFinder
60
64
 
61
65
  def license_urls(dep)
62
66
  files = Dir["**/#{dep.name}.#{dep.version}.nupkg"]
67
+
63
68
  return nil if files.empty?
64
69
 
65
70
  file = files.first
@@ -0,0 +1,120 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+ require 'tempfile'
5
+
6
+ module LicenseFinder
7
+ class PNPM < PackageManager
8
+ def initialize(options = {})
9
+ super
10
+ @pnpm_options = options[:pnpm_options]
11
+ end
12
+
13
+ SHELL_COMMAND = 'pnpm licenses list --json --long'
14
+
15
+ def possible_package_paths
16
+ [project_path.join('pnpm-lock.yaml')]
17
+ end
18
+
19
+ def self.takes_priority_over
20
+ NPM
21
+ end
22
+
23
+ def current_packages
24
+ # check if the minimum version of PNPM is met
25
+ raise 'The minimum PNPM version is not met, requires 7.17.0 or later' unless supported_pnpm?
26
+
27
+ # check if the project directory has workspace file
28
+ cmd = PNPM::SHELL_COMMAND.to_s
29
+ cmd += ' --no-color'
30
+ cmd += ' --recursive' unless project_has_workspaces == false
31
+ cmd += " --dir #{project_path}" unless project_path.nil?
32
+ cmd += " #{@pnpm_options}" unless @pnpm_options.nil?
33
+
34
+ stdout, stderr, status = Cmd.run(cmd)
35
+ raise "Command '#{cmd}' failed to execute: #{stderr}" unless status.success?
36
+
37
+ json_objects = JSON.parse(stdout)
38
+ get_pnpm_packages(json_objects)
39
+ end
40
+
41
+ def get_pnpm_packages(json_objects)
42
+ packages = []
43
+ incompatible_packages = []
44
+
45
+ json_objects.map do |_, value|
46
+ value.each do |pkg|
47
+ name = pkg['name']
48
+ version = pkg['version']
49
+ license = pkg['license']
50
+ homepage = pkg['vendorUrl']
51
+ author = pkg['vendorName']
52
+ module_path = pkg['path']
53
+
54
+ package = PNPMPackage.new(
55
+ name,
56
+ version,
57
+ spec_licenses: [license],
58
+ homepage: homepage,
59
+ authors: author,
60
+ install_path: module_path
61
+ )
62
+ packages << package
63
+ end
64
+ end
65
+
66
+ packages + incompatible_packages.uniq
67
+ end
68
+
69
+ def package_management_command
70
+ 'pnpm'
71
+ end
72
+
73
+ def prepare_command
74
+ 'pnpm install --no-lockfile --ignore-scripts'
75
+ end
76
+
77
+ def prepare
78
+ prep_cmd = "#{prepare_command}#{production_flag}"
79
+ _stdout, stderr, status = Dir.chdir(project_path) { Cmd.run(prep_cmd) }
80
+
81
+ return if status.success?
82
+
83
+ log_errors stderr
84
+ raise "Prepare command '#{prep_cmd}' failed" unless @prepare_no_fail
85
+ end
86
+
87
+ private
88
+
89
+ def project_has_workspaces
90
+ Dir.chdir(project_path) do
91
+ return File.file?('pnpm-workspace.yaml')
92
+ end
93
+ end
94
+
95
+ # PNPM introduced the licenses command in 7.17.0
96
+ def supported_pnpm?
97
+ Dir.chdir(project_path) do
98
+ version_string, stderr_str, status = Cmd.run('pnpm --version')
99
+ raise "Command 'pnpm -v' failed to execute: #{stderr_str}" unless status.success?
100
+
101
+ version = version_string.split('.').map(&:to_i)
102
+ major = version[0]
103
+ minor = version[1]
104
+ patch = version[1]
105
+
106
+ return true if major > 7
107
+ return true if major == 7 && minor > 17
108
+ return true if major == 7 && minor == 17 && patch >= 0
109
+
110
+ return false
111
+ end
112
+ end
113
+
114
+ def production_flag
115
+ return '' if @ignored_groups.nil?
116
+
117
+ @ignored_groups.include?('devDependencies') ? ' --prod' : ''
118
+ end
119
+ end
120
+ end
@@ -2,40 +2,37 @@
2
2
 
3
3
  module LicenseFinder
4
4
  class Yarn < PackageManager
5
- SHELL_COMMAND = 'yarn licenses list --no-progress --json'
5
+ def initialize(options = {})
6
+ super
7
+ @yarn_options = options[:yarn_options]
8
+ end
9
+
10
+ SHELL_COMMAND = 'yarn licenses list --recursive --json'
6
11
 
7
12
  def possible_package_paths
8
13
  [project_path.join('yarn.lock')]
9
14
  end
10
15
 
11
16
  def current_packages
12
- cmd = "#{Yarn::SHELL_COMMAND}#{yarn1_production_flag}"
13
- suffix = " --cwd #{project_path}" unless project_path.nil?
14
- cmd += suffix unless suffix.nil?
17
+ # the licenses plugin supports the classic production flag
18
+ cmd = "#{Yarn::SHELL_COMMAND}#{classic_yarn_production_flag}"
19
+ if yarn_version == 1
20
+ cmd += ' --no-progress'
21
+ cmd += " --cwd #{project_path}" unless project_path.nil?
22
+ cmd += " #{@yarn_options}" unless @yarn_options.nil?
23
+ end
15
24
 
16
25
  stdout, stderr, status = Cmd.run(cmd)
17
26
  raise "Command '#{cmd}' failed to execute: #{stderr}" unless status.success?
18
27
 
19
- packages = []
20
- incompatible_packages = []
21
-
22
28
  json_strings = stdout.encode('ASCII', invalid: :replace, undef: :replace, replace: '?').split("\n")
23
29
  json_objects = json_strings.map { |json_object| JSON.parse(json_object) }
24
30
 
25
- if json_objects.last['type'] == 'table'
26
- license_json = json_objects.pop['data']
27
- packages = packages_from_json(license_json)
28
- end
29
-
30
- json_objects.each do |json_object|
31
- match = /(?<name>[\w,\-]+)@(?<version>(\d+\.?)+)/ =~ json_object['data'].to_s
32
- if match
33
- package = YarnPackage.new(name, version, spec_licenses: ['unknown'])
34
- incompatible_packages.push(package)
35
- end
31
+ if yarn_version == 1
32
+ get_yarn1_packages(json_objects)
33
+ else
34
+ get_yarn_packages(json_objects)
36
35
  end
37
-
38
- packages + incompatible_packages.uniq
39
36
  end
40
37
 
41
38
  def prepare
@@ -56,33 +53,96 @@ module LicenseFinder
56
53
  end
57
54
 
58
55
  def prepare_command
59
- if yarn2_project?
60
- yarn2_prepare_command
56
+ if yarn_version == 1
57
+ classic_yarn_prepare_command
61
58
  else
62
- yarn1_prepare_command
59
+ yarn_prepare_command
63
60
  end
64
61
  end
65
62
 
66
63
  private
67
64
 
68
- def yarn2_prepare_command
69
- "#{yarn2_production_flag}yarn install"
65
+ def yarn_prepare_command
66
+ "#{yarn_plugin_production_command}yarn install && yarn plugin import https://raw.githubusercontent.com/mhassan1/yarn-plugin-licenses/#{yarn_licenses_plugin_version}/bundles/@yarnpkg/plugin-licenses.js"
70
67
  end
71
68
 
72
- def yarn1_prepare_command
73
- "yarn install --ignore-engines --ignore-scripts#{yarn1_production_flag}"
69
+ def classic_yarn_prepare_command
70
+ "yarn install --ignore-engines --ignore-scripts#{classic_yarn_production_flag}"
74
71
  end
75
72
 
76
- def yarn2_project?
73
+ def yarn_licenses_plugin_version
74
+ if yarn_version == 2
75
+ 'v0.6.0'
76
+ else
77
+ 'v0.7.2'
78
+ end
79
+ end
80
+
81
+ def yarn_version
77
82
  Dir.chdir(project_path) do
78
83
  version_string, stderr_str, status = Cmd.run('yarn -v')
79
84
  raise "Command 'yarn -v' failed to execute: #{stderr_str}" unless status.success?
80
85
 
81
86
  version = version_string.split('.').map(&:to_i)
82
- return version[0] >= 2
87
+ return version[0]
83
88
  end
84
89
  end
85
90
 
91
+ def get_yarn_packages(json_objects)
92
+ packages = []
93
+ incompatible_packages = []
94
+ json_objects.each do |json_object|
95
+ license = json_object['value']
96
+ body = json_object['children']
97
+
98
+ body.each do |package_name, vendor_info|
99
+ valid_match = %r{(?<name>[@,\w,\-,/,.]+)@(?<manager>\D*):\D*(?<version>(\d+\.?)+)} =~ package_name.to_s
100
+ valid_match = %r{(?<name>[@,\w,\-,/,.]+)@virtual:.+#(\D*):\D*(?<version>(\d+\.?)+)} =~ package_name.to_s if manager.eql?('virtual')
101
+
102
+ if valid_match
103
+ homepage = vendor_info['children']['vendorUrl']
104
+ author = vendor_info['children']['vendorName']
105
+ package = YarnPackage.new(
106
+ name,
107
+ version,
108
+ spec_licenses: [license],
109
+ homepage: homepage,
110
+ authors: author,
111
+ install_path: project_path.join(modules_folder, name)
112
+ )
113
+ packages << package
114
+ end
115
+ incompatible_match = /(?<name>[\w,\-]+)@[a-z]*:(?<version>(\.))/ =~ package_name.to_s
116
+
117
+ if incompatible_match
118
+ package = YarnPackage.new(name, version, spec_licenses: ['unknown'])
119
+ incompatible_packages.push(package)
120
+ end
121
+ end
122
+ end
123
+
124
+ packages + incompatible_packages.uniq
125
+ end
126
+
127
+ def get_yarn1_packages(json_objects)
128
+ packages = []
129
+ incompatible_packages = []
130
+ if json_objects.last['type'] == 'table'
131
+ license_json = json_objects.pop['data']
132
+ packages = packages_from_json(license_json)
133
+ end
134
+
135
+ json_objects.each do |json_object|
136
+ match = /(?<name>[\w,\-]+)@(?<version>(\d+\.?)+)/ =~ json_object['data'].to_s
137
+ if match
138
+ package = YarnPackage.new(name, version, spec_licenses: ['unknown'])
139
+ incompatible_packages.push(package)
140
+ end
141
+ end
142
+
143
+ packages + incompatible_packages.uniq
144
+ end
145
+
86
146
  def packages_from_json(json_data)
87
147
  body = json_data['body']
88
148
  head = json_data['head']
@@ -120,13 +180,13 @@ module LicenseFinder
120
180
  all_packages - [yarn_internal_package]
121
181
  end
122
182
 
123
- def yarn1_production_flag
183
+ def classic_yarn_production_flag
124
184
  return '' if @ignored_groups.nil?
125
185
 
126
186
  @ignored_groups.include?('devDependencies') ? ' --production' : ''
127
187
  end
128
188
 
129
- def yarn2_production_flag
189
+ def yarn_plugin_production_command
130
190
  return '' if @ignored_groups.nil?
131
191
 
132
192
  @ignored_groups.include?('devDependencies') ? 'yarn plugin import workspace-tools && yarn workspaces focus --all --production && ' : ''
@@ -25,7 +25,9 @@ module LicenseFinder
25
25
  def definition(name, version)
26
26
  response = request("https://pypi.org/pypi/#{name}/#{version}/json")
27
27
  response.is_a?(Net::HTTPSuccess) ? JSON.parse(response.body).fetch('info', {}) : {}
28
- rescue *CONNECTION_ERRORS
28
+ rescue *CONNECTION_ERRORS => e
29
+ raise e, "Unable to read package from pypi.org #{name} #{version}: #{e}" unless @prepare_no_fail
30
+
29
31
  {}
30
32
  end
31
33
 
@@ -72,11 +72,32 @@ module LicenseFinder
72
72
  @identifier.version,
73
73
  description: npm_json['description'],
74
74
  homepage: npm_json['homepage'],
75
+ authors: author_names,
75
76
  spec_licenses: Package.license_names_from_standard_spec(npm_json),
76
77
  install_path: npm_json['path'],
77
78
  children: @dependencies.map(&:name))
78
79
  end
79
80
 
81
+ def author_names
82
+ names = []
83
+ names.push(author_name(@json['author'])) unless @json['author'].nil?
84
+ names += @json['contributors'].map { |c| author_name(c) } if @json['contributors'].is_a?(Array)
85
+ names.join(', ')
86
+ end
87
+
88
+ def author_name(author)
89
+ if author.instance_of?(String)
90
+ author_name_from_combined(author)
91
+ else
92
+ author['name']
93
+ end
94
+ end
95
+
96
+ def author_name_from_combined(author)
97
+ matches = author.match /^(.*?)\s*(<.*?>)?\s*(\(.*?\))?\s*$/
98
+ matches[1]
99
+ end
100
+
80
101
  def ==(other)
81
102
  other.is_a?(NpmPackage) && @identifier == other.identifier
82
103
  end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LicenseFinder
4
+ class PNPMPackage < Package
5
+ def package_manager
6
+ 'PNPM'
7
+ end
8
+
9
+ def package_url
10
+ "https://www.npmjs.com/package/#{CGI.escape(name)}/v/#{CGI.escape(version)}"
11
+ end
12
+ end
13
+ end
@@ -4,7 +4,7 @@ module LicenseFinder
4
4
  class CsvReport < Report
5
5
  COMMA_SEP = ','.freeze
6
6
  NEWLINE_SEP = '\@NL'.freeze
7
- AVAILABLE_COLUMNS = %w[name version authors licenses license_links approved summary description homepage install_path package_manager groups texts notice].freeze
7
+ AVAILABLE_COLUMNS = %w[name version authors licenses license_links approved summary description homepage install_path package_manager groups texts notice approved_by approved_reason].freeze
8
8
  MISSING_DEPENDENCY_TEXT = 'This package is not installed. Please install to determine licenses.'.freeze
9
9
 
10
10
  def initialize(dependencies, options)
@@ -95,5 +95,14 @@ module LicenseFinder
95
95
  dep.groups.join(self.class::COMMA_SEP)
96
96
  end
97
97
  end
98
+
99
+ def format_approved_by(dep)
100
+ dep.approved_manually? ? dep.manual_approval.who : ''
101
+ end
102
+
103
+ def format_approved_reason(dep)
104
+ dep.approved_manually? ? dep.manual_approval.why : ''
105
+ end
106
+
98
107
  end
99
108
  end
@@ -3,7 +3,7 @@
3
3
  module LicenseFinder
4
4
  class Scanner
5
5
  PACKAGE_MANAGERS = [
6
- GoModules, GoDep, GoWorkspace, Go15VendorExperiment, Glide, Gvt, Govendor, Trash, Dep, Bundler, NPM, Pip,
6
+ GoModules, GoDep, GoWorkspace, Go15VendorExperiment, Glide, Gvt, Govendor, Trash, Dep, Bundler, NPM, PNPM, Pip,
7
7
  Yarn, Bower, Maven, Gradle, CocoaPods, Rebar, Erlangmk, Nuget, Carthage, Mix, Conan, Sbt, Cargo, Dotnet, Composer, Pipenv,
8
8
  Conda, Spm, Pub
9
9
  ].freeze
@@ -50,11 +50,11 @@ Gem::Specification.new do |s|
50
50
  s.add_dependency 'with_env', '1.1.0'
51
51
  s.add_dependency 'xml-simple', '~> 1.1.9'
52
52
 
53
- s.add_development_dependency 'addressable', '2.8.0'
53
+ s.add_development_dependency 'addressable', '2.8.1'
54
54
  s.add_development_dependency 'capybara', '~> 3.32.2'
55
55
  s.add_development_dependency 'cocoapods', '>= 1.0.0' if RUBY_PLATFORM.match?(/darwin/)
56
56
  s.add_development_dependency 'e2mmap', '~> 0.1.0'
57
- s.add_development_dependency 'fakefs', '~> 1.4.1'
57
+ s.add_development_dependency 'fakefs', '~> 1.8.0'
58
58
  s.add_development_dependency 'matrix', '~> 0.1.0'
59
59
  s.add_development_dependency 'mime-types', '3.4.1'
60
60
  s.add_development_dependency 'pry', '~> 0.14.1'
@@ -66,8 +66,8 @@ Gem::Specification.new do |s|
66
66
  s.add_development_dependency 'webmock', '~> 3.14'
67
67
 
68
68
  s.add_development_dependency 'nokogiri', '~>1.10'
69
- s.add_development_dependency 'rack', '~> 2.2.3'
70
- s.add_development_dependency 'rack-test', '~> 1.1.0', '> 0.7'
69
+ s.add_development_dependency 'rack', '~> 3.0.0'
70
+ s.add_development_dependency 'rack-test', '> 0.7', '~> 2.0.2'
71
71
 
72
72
  s.files = `git ls-files`.split("\n").reject { |f| f.start_with?('spec', 'features') }
73
73
  s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }