dependabot-bundler 0.121.1 → 0.124.0
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/lib/dependabot/bundler/file_fetcher.rb +1 -0
- data/lib/dependabot/bundler/file_parser.rb +44 -91
- data/lib/dependabot/bundler/file_parser/gemfile_declaration_finder.rb +5 -3
- data/lib/dependabot/bundler/file_updater.rb +8 -5
- data/lib/dependabot/bundler/file_updater/lockfile_updater.rb +16 -245
- data/lib/dependabot/bundler/native_helpers.rb +18 -0
- data/lib/dependabot/bundler/update_checker/file_preparer.rb +1 -0
- data/lib/dependabot/bundler/update_checker/force_updater.rb +32 -186
- data/lib/dependabot/bundler/update_checker/latest_version_finder.rb +0 -4
- data/lib/dependabot/bundler/update_checker/latest_version_finder/dependency_source.rb +43 -52
- data/lib/dependabot/bundler/update_checker/shared_bundler_helpers.rb +68 -89
- data/lib/dependabot/bundler/update_checker/version_resolver.rb +63 -132
- metadata +35 -9
- data/lib/dependabot/monkey_patches/bundler/definition_bundler_version_patch.rb +0 -15
- data/lib/dependabot/monkey_patches/bundler/definition_ruby_version_patch.rb +0 -17
- data/lib/dependabot/monkey_patches/bundler/git_source_patch.rb +0 -61
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Dependabot
|
4
|
+
module Bundler
|
5
|
+
module NativeHelpers
|
6
|
+
def self.helper_path
|
7
|
+
"bundle exec ruby #{File.join(native_helpers_root, 'run.rb')}"
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.native_helpers_root
|
11
|
+
helpers_root = ENV["DEPENDABOT_NATIVE_HELPERS_PATH"]
|
12
|
+
return File.join(helpers_root, "bundler") unless helpers_root.nil?
|
13
|
+
|
14
|
+
File.join(__dir__, "../../../helpers")
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -283,6 +283,7 @@ module Dependabot
|
|
283
283
|
end
|
284
284
|
# rubocop:enable Metrics/PerceivedComplexity
|
285
285
|
|
286
|
+
# TODO: Stop sanitizing the lockfile once we have bundler 2 installed
|
286
287
|
def sanitized_lockfile_content
|
287
288
|
re = FileUpdater::LockfileUpdater::LOCKFILE_ENDING
|
288
289
|
lockfile.content.gsub(re, "")
|
@@ -1,20 +1,20 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "dependabot/
|
4
|
-
require "dependabot/
|
5
|
-
require "dependabot/
|
6
|
-
|
3
|
+
require "dependabot/bundler/file_parser"
|
4
|
+
require "dependabot/bundler/file_updater/lockfile_updater"
|
5
|
+
require "dependabot/bundler/native_helpers"
|
7
6
|
require "dependabot/bundler/update_checker"
|
8
7
|
require "dependabot/bundler/update_checker/requirements_updater"
|
9
|
-
require "dependabot/bundler/file_updater/lockfile_updater"
|
10
|
-
require "dependabot/bundler/file_parser"
|
11
|
-
require "dependabot/shared_helpers"
|
12
8
|
require "dependabot/errors"
|
9
|
+
require "dependabot/shared_helpers"
|
13
10
|
|
14
11
|
module Dependabot
|
15
12
|
module Bundler
|
16
13
|
class UpdateChecker
|
17
14
|
class ForceUpdater
|
15
|
+
require_relative "shared_bundler_helpers"
|
16
|
+
include SharedBundlerHelpers
|
17
|
+
|
18
18
|
def initialize(dependency:, dependency_files:, repo_contents_path: nil,
|
19
19
|
credentials:, target_version:,
|
20
20
|
requirements_update_strategy:,
|
@@ -42,154 +42,28 @@ module Dependabot
|
|
42
42
|
end
|
43
43
|
|
44
44
|
def force_update
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
)
|
62
|
-
|
63
|
-
raise if new_dependencies_to_unlock.none?
|
64
|
-
|
65
|
-
other_updates += new_dependencies_to_unlock
|
66
|
-
retry
|
67
|
-
end
|
68
|
-
end
|
69
|
-
rescue SharedHelpers::ChildProcessFailed => e
|
70
|
-
raise_unresolvable_error(e)
|
71
|
-
end
|
72
|
-
|
73
|
-
#########################
|
74
|
-
# Bundler context setup #
|
75
|
-
#########################
|
76
|
-
|
77
|
-
def in_a_temporary_bundler_context
|
78
|
-
base_directory = dependency_files.first.directory
|
79
|
-
SharedHelpers.in_a_temporary_repo_directory(base_directory,
|
80
|
-
repo_contents_path) do
|
81
|
-
write_temporary_dependency_files
|
82
|
-
|
83
|
-
SharedHelpers.in_a_forked_process do
|
84
|
-
# Remove installed gems from the default Rubygems index
|
85
|
-
::Gem::Specification.all =
|
86
|
-
::Gem::Specification.send(:default_stubs, "*.gemspec")
|
87
|
-
|
88
|
-
# Set flags and credentials
|
89
|
-
set_bundler_flags_and_credentials
|
90
|
-
|
91
|
-
yield
|
92
|
-
end
|
45
|
+
in_a_native_bundler_context(error_handling: false) do |tmp_dir|
|
46
|
+
updated_deps, specs = SharedHelpers.run_helper_subprocess(
|
47
|
+
command: NativeHelpers.helper_path,
|
48
|
+
function: "force_update",
|
49
|
+
args: {
|
50
|
+
dir: tmp_dir,
|
51
|
+
dependency_name: dependency.name,
|
52
|
+
target_version: target_version,
|
53
|
+
credentials: relevant_credentials,
|
54
|
+
gemfile_name: gemfile.name,
|
55
|
+
lockfile_name: lockfile.name,
|
56
|
+
using_bundler_2: using_bundler_2?,
|
57
|
+
update_multiple_dependencies: update_multiple_dependencies?
|
58
|
+
}
|
59
|
+
)
|
60
|
+
dependencies_from(updated_deps, specs)
|
93
61
|
end
|
94
|
-
|
95
|
-
|
96
|
-
def new_dependencies_to_unlock_from(error:, already_unlocked:)
|
97
|
-
potentials_deps =
|
98
|
-
relevant_conflicts(error, already_unlocked).
|
99
|
-
flat_map(&:requirement_trees).
|
100
|
-
reject do |tree|
|
101
|
-
# If the final requirement wasn't specific, it can't be binding
|
102
|
-
next true if tree.last.requirement == Gem::Requirement.new(">= 0")
|
103
|
-
|
104
|
-
# If the conflict wasn't for the dependency we're updating then
|
105
|
-
# we don't have enough info to reject it
|
106
|
-
next false unless tree.last.name == dependency.name
|
107
|
-
|
108
|
-
# If the final requirement *was* for the dependency we're updating
|
109
|
-
# then we can ignore the tree if it permits the target version
|
110
|
-
tree.last.requirement.satisfied_by?(
|
111
|
-
Gem::Version.new(target_version)
|
112
|
-
)
|
113
|
-
end.map(&:first)
|
114
|
-
|
115
|
-
potentials_deps.
|
116
|
-
reject { |dep| already_unlocked.map(&:name).include?(dep.name) }.
|
117
|
-
reject { |dep| [dependency.name, "ruby\0"].include?(dep.name) }.
|
118
|
-
uniq
|
119
|
-
end
|
120
|
-
|
121
|
-
def relevant_conflicts(error, dependencies_being_unlocked)
|
122
|
-
names = [*dependencies_being_unlocked.map(&:name), dependency.name]
|
123
|
-
|
124
|
-
# For a conflict to be relevant to the updates we're making it must be
|
125
|
-
# 1) caused by a new requirement introduced by our unlocking, or
|
126
|
-
# 2) caused by an old requirement that prohibits the update.
|
127
|
-
# Hence, we look at the beginning and end of the requirement trees
|
128
|
-
error.cause.conflicts.values.
|
129
|
-
select do |conflict|
|
130
|
-
conflict.requirement_trees.any? do |t|
|
131
|
-
names.include?(t.last.name) || names.include?(t.first.name)
|
132
|
-
end
|
133
|
-
end
|
134
|
-
end
|
135
|
-
|
136
|
-
def raise_unresolvable_error(error)
|
137
|
-
msg = error.error_class + " with message: " + error.error_message
|
62
|
+
rescue SharedHelpers::HelperSubprocessFailed => e
|
63
|
+
msg = e.error_class + " with message: " + e.message
|
138
64
|
raise Dependabot::DependencyFileNotResolvable, msg
|
139
65
|
end
|
140
66
|
|
141
|
-
def build_definition(other_updates:)
|
142
|
-
gems_to_unlock = other_updates.map(&:name) + [dependency.name]
|
143
|
-
definition = ::Bundler::Definition.build(
|
144
|
-
gemfile.name,
|
145
|
-
lockfile&.name,
|
146
|
-
gems: gems_to_unlock + subdependencies,
|
147
|
-
lock_shared_dependencies: true
|
148
|
-
)
|
149
|
-
|
150
|
-
# Remove the Gemfile / gemspec requirements on the gems we're
|
151
|
-
# unlocking (i.e., completely unlock them)
|
152
|
-
gems_to_unlock.each do |gem_name|
|
153
|
-
unlock_gem(definition: definition, gem_name: gem_name)
|
154
|
-
end
|
155
|
-
|
156
|
-
# Set the requirement for the gem we're forcing an update of
|
157
|
-
new_req = Gem::Requirement.create("= #{target_version}")
|
158
|
-
definition.dependencies.
|
159
|
-
find { |d| d.name == dependency.name }.
|
160
|
-
tap do |dep|
|
161
|
-
dep.instance_variable_set(:@requirement, new_req)
|
162
|
-
dep.source = nil if dep.source.is_a?(::Bundler::Source::Git)
|
163
|
-
end
|
164
|
-
|
165
|
-
definition
|
166
|
-
end
|
167
|
-
|
168
|
-
def subdependencies
|
169
|
-
# If there's no lockfile we don't need to worry about
|
170
|
-
# subdependencies
|
171
|
-
return [] unless lockfile
|
172
|
-
|
173
|
-
all_deps = ::Bundler::LockfileParser.new(sanitized_lockfile_body).
|
174
|
-
specs.map(&:name).map(&:to_s)
|
175
|
-
top_level = ::Bundler::Definition.
|
176
|
-
build(gemfile.name, lockfile.name, {}).
|
177
|
-
dependencies.map(&:name).map(&:to_s)
|
178
|
-
|
179
|
-
all_deps - top_level
|
180
|
-
end
|
181
|
-
|
182
|
-
def unlock_gem(definition:, gem_name:)
|
183
|
-
dep = definition.dependencies.find { |d| d.name == gem_name }
|
184
|
-
version = definition.locked_gems.specs.
|
185
|
-
find { |d| d.name == gem_name }.version
|
186
|
-
|
187
|
-
dep&.instance_variable_set(
|
188
|
-
:@requirement,
|
189
|
-
Gem::Requirement.create(">= #{version}")
|
190
|
-
)
|
191
|
-
end
|
192
|
-
|
193
67
|
def original_dependencies
|
194
68
|
@original_dependencies ||=
|
195
69
|
FileParser.new(
|
@@ -209,10 +83,10 @@ module Dependabot
|
|
209
83
|
# but resolving it won't necessarily be easy.
|
210
84
|
updated_deps.map do |dep|
|
211
85
|
original_dep =
|
212
|
-
original_dependencies.find { |d| d.name == dep.name }
|
213
|
-
spec = specs.find { |d| d.name == dep.name }
|
86
|
+
original_dependencies.find { |d| d.name == dep.fetch("name") }
|
87
|
+
spec = specs.find { |d| d.fetch("name") == dep.fetch("name") }
|
214
88
|
|
215
|
-
next if spec.version
|
89
|
+
next if spec.fetch("version") == original_dep.version
|
216
90
|
|
217
91
|
build_dependency(original_dep, spec)
|
218
92
|
end.compact
|
@@ -220,15 +94,15 @@ module Dependabot
|
|
220
94
|
|
221
95
|
def build_dependency(original_dep, updated_spec)
|
222
96
|
Dependency.new(
|
223
|
-
name: updated_spec.name,
|
224
|
-
version: updated_spec.version
|
97
|
+
name: updated_spec.fetch("name"),
|
98
|
+
version: updated_spec.fetch("version"),
|
225
99
|
requirements:
|
226
100
|
RequirementsUpdater.new(
|
227
101
|
requirements: original_dep.requirements,
|
228
102
|
update_strategy: requirements_update_strategy,
|
229
103
|
updated_source: source_for(original_dep),
|
230
|
-
latest_version: updated_spec.version
|
231
|
-
latest_resolvable_version: updated_spec.version
|
104
|
+
latest_version: updated_spec.fetch("version"),
|
105
|
+
latest_resolvable_version: updated_spec.fetch("version")
|
232
106
|
).updated_requirements,
|
233
107
|
previous_version: original_dep.version,
|
234
108
|
previous_requirements: original_dep.requirements,
|
@@ -267,34 +141,6 @@ module Dependabot
|
|
267
141
|
File.write(lockfile.name, sanitized_lockfile_body) if lockfile
|
268
142
|
end
|
269
143
|
|
270
|
-
def set_bundler_flags_and_credentials
|
271
|
-
# Set auth details
|
272
|
-
relevant_credentials.each do |cred|
|
273
|
-
token = cred["token"] ||
|
274
|
-
"#{cred['username']}:#{cred['password']}"
|
275
|
-
|
276
|
-
::Bundler.settings.set_command_option(
|
277
|
-
cred.fetch("host"),
|
278
|
-
token.gsub("@", "%40F").gsub("?", "%3F")
|
279
|
-
)
|
280
|
-
end
|
281
|
-
|
282
|
-
# Only allow upgrades. Otherwise it's unlikely that this
|
283
|
-
# resolution will be found by the FileUpdater
|
284
|
-
::Bundler.settings.set_command_option(
|
285
|
-
"only_update_to_newer_versions",
|
286
|
-
true
|
287
|
-
)
|
288
|
-
|
289
|
-
# Use HTTPS for GitHub if lockfile was generated by Bundler 2
|
290
|
-
set_bundler_2_flags if using_bundler_2?
|
291
|
-
end
|
292
|
-
|
293
|
-
def set_bundler_2_flags
|
294
|
-
::Bundler.settings.set_command_option("forget_cli_options", "true")
|
295
|
-
::Bundler.settings.set_command_option("github.https", "true")
|
296
|
-
end
|
297
|
-
|
298
144
|
def relevant_credentials
|
299
145
|
credentials.
|
300
146
|
select { |cred| cred["password"] || cred["token"] }.
|
@@ -1,9 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "dependabot/monkey_patches/bundler/definition_ruby_version_patch"
|
4
|
-
require "dependabot/monkey_patches/bundler/definition_bundler_version_patch"
|
5
|
-
require "dependabot/monkey_patches/bundler/git_source_patch"
|
6
|
-
|
7
3
|
require "excon"
|
8
4
|
|
9
5
|
require "dependabot/bundler/update_checker"
|
@@ -47,27 +47,26 @@ module Dependabot
|
|
47
47
|
def latest_git_version_details
|
48
48
|
return unless git?
|
49
49
|
|
50
|
-
|
50
|
+
source_details =
|
51
51
|
dependency.requirements.map { |r| r.fetch(:source) }.
|
52
52
|
uniq.compact.first
|
53
53
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
"
|
59
|
-
|
60
|
-
|
61
|
-
|
54
|
+
SharedHelpers.with_git_configured(credentials: credentials) do
|
55
|
+
in_a_native_bundler_context do |tmp_dir|
|
56
|
+
SharedHelpers.run_helper_subprocess(
|
57
|
+
command: NativeHelpers.helper_path,
|
58
|
+
function: "depencency_source_latest_git_version",
|
59
|
+
args: {
|
60
|
+
dir: tmp_dir,
|
61
|
+
gemfile_name: gemfile.name,
|
62
|
+
dependency_name: dependency.name,
|
63
|
+
credentials: credentials,
|
64
|
+
dependency_source_url: source_details[:url],
|
65
|
+
dependency_source_branch: source_details[:branch]
|
66
|
+
}
|
62
67
|
)
|
63
|
-
|
64
|
-
# Tell Bundler we're fine with fetching the source remotely
|
65
|
-
source.instance_variable_set(:@allow_remote, true)
|
66
|
-
|
67
|
-
spec = source.specs.first
|
68
|
-
{ version: spec.version, commit_sha: spec.source.revision }
|
69
68
|
end
|
70
|
-
end
|
69
|
+
end.transform_keys(&:to_sym)
|
71
70
|
end
|
72
71
|
|
73
72
|
def git?
|
@@ -98,46 +97,38 @@ module Dependabot
|
|
98
97
|
|
99
98
|
def private_registry_versions
|
100
99
|
@private_registry_versions ||=
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
@bundler_source ||=
|
116
|
-
in_a_temporary_bundler_context do
|
117
|
-
definition = ::Bundler::Definition.build(gemfile.name, nil, {})
|
118
|
-
|
119
|
-
specified_source =
|
120
|
-
definition.dependencies.
|
121
|
-
find { |dep| dep.name == dependency.name }&.source
|
122
|
-
|
123
|
-
specified_source || definition.send(:sources).default_source
|
100
|
+
in_a_native_bundler_context do |tmp_dir|
|
101
|
+
SharedHelpers.run_helper_subprocess(
|
102
|
+
command: NativeHelpers.helper_path,
|
103
|
+
function: "private_registry_versions",
|
104
|
+
args: {
|
105
|
+
dir: tmp_dir,
|
106
|
+
gemfile_name: gemfile.name,
|
107
|
+
dependency_name: dependency.name,
|
108
|
+
credentials: credentials
|
109
|
+
}
|
110
|
+
).map do |version_string|
|
111
|
+
Gem::Version.new(version_string)
|
112
|
+
end
|
124
113
|
end
|
125
114
|
end
|
126
115
|
|
127
116
|
def source_type
|
128
|
-
@source_type
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
117
|
+
return @source_type if defined? @source_type
|
118
|
+
return @source_type = RUBYGEMS unless gemfile
|
119
|
+
|
120
|
+
@source_type = in_a_native_bundler_context do |tmp_dir|
|
121
|
+
SharedHelpers.run_helper_subprocess(
|
122
|
+
command: NativeHelpers.helper_path,
|
123
|
+
function: "dependency_source_type",
|
124
|
+
args: {
|
125
|
+
dir: tmp_dir,
|
126
|
+
gemfile_name: gemfile.name,
|
127
|
+
dependency_name: dependency.name,
|
128
|
+
credentials: credentials
|
129
|
+
}
|
130
|
+
)
|
131
|
+
end
|
141
132
|
end
|
142
133
|
|
143
134
|
def gemfile
|
@@ -1,12 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "dependabot/monkey_patches/bundler/definition_ruby_version_patch"
|
4
|
-
require "dependabot/monkey_patches/bundler/definition_bundler_version_patch"
|
5
|
-
require "dependabot/monkey_patches/bundler/git_source_patch"
|
6
|
-
|
7
3
|
require "excon"
|
8
4
|
|
9
5
|
require "dependabot/bundler/update_checker"
|
6
|
+
require "dependabot/bundler/native_helpers"
|
10
7
|
require "dependabot/shared_helpers"
|
11
8
|
require "dependabot/errors"
|
12
9
|
|
@@ -17,6 +14,18 @@ module Dependabot
|
|
17
14
|
GIT_REGEX = /reset --hard [^\s]*` in directory (?<path>[^\s]*)/.freeze
|
18
15
|
GIT_REF_REGEX = /not exist in the repository (?<path>[^\s]*)\./.freeze
|
19
16
|
PATH_REGEX = /The path `(?<path>.*)` does not exist/.freeze
|
17
|
+
|
18
|
+
module BundlerErrorPatterns
|
19
|
+
MISSING_AUTH_REGEX =
|
20
|
+
/bundle config (?<source>.*) username:password/.freeze
|
21
|
+
BAD_AUTH_REGEX =
|
22
|
+
/Bad username or password for (?<source>.*)\.$/.freeze
|
23
|
+
BAD_CERT_REGEX =
|
24
|
+
/verify the SSL certificate for (?<source>.*)\.$/.freeze
|
25
|
+
HTTP_ERR_REGEX =
|
26
|
+
/Could not fetch specs from (?<source>.*)$/.freeze
|
27
|
+
end
|
28
|
+
|
20
29
|
RETRYABLE_ERRORS = %w(
|
21
30
|
Bundler::HTTPError
|
22
31
|
Bundler::Fetcher::FallbackError
|
@@ -35,27 +44,15 @@ module Dependabot
|
|
35
44
|
# Bundler context setup #
|
36
45
|
#########################
|
37
46
|
|
38
|
-
def
|
47
|
+
def in_a_native_bundler_context(error_handling: true)
|
39
48
|
SharedHelpers.
|
40
49
|
in_a_temporary_repo_directory(base_directory,
|
41
50
|
repo_contents_path) do |tmp_dir|
|
42
51
|
write_temporary_dependency_files
|
43
52
|
|
44
|
-
|
45
|
-
# Set the path for path gemspec correctly
|
46
|
-
::Bundler.instance_variable_set(:@root, tmp_dir)
|
47
|
-
|
48
|
-
# Remove installed gems from the default Rubygems index
|
49
|
-
::Gem::Specification.all =
|
50
|
-
::Gem::Specification.send(:default_stubs, "*.gemspec")
|
51
|
-
|
52
|
-
# Set flags and credentials
|
53
|
-
set_bundler_flags_and_credentials
|
54
|
-
|
55
|
-
yield
|
56
|
-
end
|
53
|
+
yield(tmp_dir)
|
57
54
|
end
|
58
|
-
rescue SharedHelpers::
|
55
|
+
rescue SharedHelpers::HelperSubprocessFailed => e
|
59
56
|
retry_count ||= 0
|
60
57
|
retry_count += 1
|
61
58
|
if retryable_error?(e) && retry_count <= 2
|
@@ -70,8 +67,7 @@ module Dependabot
|
|
70
67
|
end
|
71
68
|
|
72
69
|
def retryable_error?(error)
|
73
|
-
return true if error.
|
74
|
-
return false if error.is_a?(ArgumentError)
|
70
|
+
return true if error.error_class == "JSON::ParserError"
|
75
71
|
return true if RETRYABLE_ERRORS.include?(error.error_class)
|
76
72
|
|
77
73
|
unless RETRYABLE_PRIVATE_REGISTRY_ERRORS.include?(error.error_class)
|
@@ -86,13 +82,12 @@ module Dependabot
|
|
86
82
|
# rubocop:disable Metrics/AbcSize
|
87
83
|
# rubocop:disable Metrics/MethodLength
|
88
84
|
def handle_bundler_errors(error)
|
89
|
-
if error.
|
85
|
+
if error.error_class == "JSON::ParserError"
|
90
86
|
msg = "Error evaluating your dependency files: #{error.message}"
|
91
87
|
raise Dependabot::DependencyFileNotEvaluatable, msg
|
92
88
|
end
|
93
|
-
raise if error.is_a?(ArgumentError)
|
94
89
|
|
95
|
-
msg = error.error_class + " with message: " + error.
|
90
|
+
msg = error.error_class + " with message: " + error.message
|
96
91
|
|
97
92
|
case error.error_class
|
98
93
|
when "Bundler::Dsl::DSLError", "Bundler::GemspecError"
|
@@ -100,28 +95,30 @@ module Dependabot
|
|
100
95
|
raise Dependabot::DependencyFileNotEvaluatable, msg
|
101
96
|
when "Bundler::Source::Git::MissingGitRevisionError"
|
102
97
|
gem_name =
|
103
|
-
error.
|
98
|
+
error.message.match(GIT_REF_REGEX).
|
104
99
|
named_captures["path"].
|
105
100
|
split("/").last
|
106
101
|
raise GitDependencyReferenceNotFound, gem_name
|
107
102
|
when "Bundler::PathError"
|
108
103
|
gem_name =
|
109
|
-
error.
|
104
|
+
error.message.match(PATH_REGEX).
|
110
105
|
named_captures["path"].
|
111
106
|
split("/").last.split("-")[0..-2].join
|
112
107
|
raise Dependabot::PathDependenciesNotReachable, [gem_name]
|
113
108
|
when "Bundler::Source::Git::GitCommandError"
|
114
|
-
if error.
|
109
|
+
if error.message.match?(GIT_REGEX)
|
115
110
|
# We couldn't find the specified branch / commit (or the two
|
116
111
|
# weren't compatible).
|
117
112
|
gem_name =
|
118
|
-
error.
|
113
|
+
error.message.match(GIT_REGEX).
|
119
114
|
named_captures["path"].
|
120
115
|
split("/").last.split("-")[0..-2].join
|
121
116
|
raise GitDependencyReferenceNotFound, gem_name
|
122
117
|
end
|
123
118
|
|
124
|
-
bad_uris = inaccessible_git_dependencies.map
|
119
|
+
bad_uris = inaccessible_git_dependencies.map do |spec|
|
120
|
+
spec.fetch("uri")
|
121
|
+
end
|
125
122
|
raise unless bad_uris.any?
|
126
123
|
|
127
124
|
# We don't have access to one of repos required
|
@@ -134,21 +131,21 @@ module Dependabot
|
|
134
131
|
# - the gem was specified at an incompatible version
|
135
132
|
raise Dependabot::DependencyFileNotResolvable, msg
|
136
133
|
when "Bundler::Fetcher::AuthenticationRequiredError"
|
137
|
-
regex =
|
138
|
-
source = error.
|
134
|
+
regex = BundlerErrorPatterns::MISSING_AUTH_REGEX
|
135
|
+
source = error.message.match(regex)[:source]
|
139
136
|
raise Dependabot::PrivateSourceAuthenticationFailure, source
|
140
137
|
when "Bundler::Fetcher::BadAuthenticationError"
|
141
|
-
regex =
|
142
|
-
source = error.
|
138
|
+
regex = BundlerErrorPatterns::BAD_AUTH_REGEX
|
139
|
+
source = error.message.match(regex)[:source]
|
143
140
|
raise Dependabot::PrivateSourceAuthenticationFailure, source
|
144
141
|
when "Bundler::Fetcher::CertificateFailureError"
|
145
|
-
regex =
|
146
|
-
source = error.
|
142
|
+
regex = BundlerErrorPatterns::BAD_CERT_REGEX
|
143
|
+
source = error.message.match(regex)[:source]
|
147
144
|
raise Dependabot::PrivateSourceCertificateFailure, source
|
148
145
|
when "Bundler::HTTPError"
|
149
|
-
regex =
|
150
|
-
if error.
|
151
|
-
source = error.
|
146
|
+
regex = BundlerErrorPatterns::HTTP_ERR_REGEX
|
147
|
+
if error.message.match?(regex)
|
148
|
+
source = error.message.match(regex)[:source]
|
152
149
|
raise if source.end_with?("rubygems.org/")
|
153
150
|
|
154
151
|
raise Dependabot::PrivateSourceTimedOut, source
|
@@ -156,7 +153,7 @@ module Dependabot
|
|
156
153
|
|
157
154
|
# JFrog can serve a 403 if the credentials provided are good but
|
158
155
|
# don't have access to a particular gem.
|
159
|
-
raise unless error.
|
156
|
+
raise unless error.message.include?("permitted to deploy")
|
160
157
|
raise unless jfrog_source
|
161
158
|
|
162
159
|
raise Dependabot::PrivateSourceAuthenticationFailure, jfrog_source
|
@@ -169,39 +166,41 @@ module Dependabot
|
|
169
166
|
# rubocop:enable Metrics/MethodLength
|
170
167
|
|
171
168
|
def inaccessible_git_dependencies
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
false
|
193
|
-
end
|
194
|
-
end
|
169
|
+
in_a_native_bundler_context(error_handling: false) do |tmp_dir|
|
170
|
+
git_specs = SharedHelpers.run_helper_subprocess(
|
171
|
+
command: NativeHelpers.helper_path,
|
172
|
+
function: "git_specs",
|
173
|
+
args: {
|
174
|
+
dir: tmp_dir,
|
175
|
+
gemfile_name: gemfile.name,
|
176
|
+
credentials: relevant_credentials,
|
177
|
+
using_bundler_2: using_bundler_2?
|
178
|
+
}
|
179
|
+
)
|
180
|
+
git_specs.reject do |spec|
|
181
|
+
Excon.get(
|
182
|
+
spec.fetch("auth_uri"),
|
183
|
+
idempotent: true,
|
184
|
+
**SharedHelpers.excon_defaults
|
185
|
+
).status == 200
|
186
|
+
rescue Excon::Error::Socket, Excon::Error::Timeout
|
187
|
+
false
|
188
|
+
end
|
195
189
|
end
|
196
190
|
end
|
197
191
|
|
198
192
|
def jfrog_source
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
193
|
+
in_a_native_bundler_context(error_handling: false) do |dir|
|
194
|
+
SharedHelpers.run_helper_subprocess(
|
195
|
+
command: NativeHelpers.helper_path,
|
196
|
+
function: "jfrog_source",
|
197
|
+
args: {
|
198
|
+
dir: dir,
|
199
|
+
gemfile_name: gemfile.name,
|
200
|
+
credentials: relevant_credentials,
|
201
|
+
using_bundler_2: using_bundler_2?
|
202
|
+
}
|
203
|
+
)
|
205
204
|
end
|
206
205
|
end
|
207
206
|
|
@@ -215,27 +214,6 @@ module Dependabot
|
|
215
214
|
File.write(lockfile.name, sanitized_lockfile_body) if lockfile
|
216
215
|
end
|
217
216
|
|
218
|
-
def set_bundler_flags_and_credentials
|
219
|
-
# Set auth details
|
220
|
-
relevant_credentials.each do |cred|
|
221
|
-
token = cred["token"] ||
|
222
|
-
"#{cred['username']}:#{cred['password']}"
|
223
|
-
|
224
|
-
::Bundler.settings.set_command_option(
|
225
|
-
cred.fetch("host"),
|
226
|
-
token.gsub("@", "%40F").gsub("?", "%3F")
|
227
|
-
)
|
228
|
-
end
|
229
|
-
|
230
|
-
# Use HTTPS for GitHub if lockfile was generated by Bundler 2
|
231
|
-
set_bundler_2_flags if using_bundler_2?
|
232
|
-
end
|
233
|
-
|
234
|
-
def set_bundler_2_flags
|
235
|
-
::Bundler.settings.set_command_option("forget_cli_options", "true")
|
236
|
-
::Bundler.settings.set_command_option("github.https", "true")
|
237
|
-
end
|
238
|
-
|
239
217
|
def relevant_credentials
|
240
218
|
[
|
241
219
|
*git_source_credentials,
|
@@ -264,6 +242,7 @@ module Dependabot
|
|
264
242
|
dependency_files.find { |f| f.name == "gems.locked" }
|
265
243
|
end
|
266
244
|
|
245
|
+
# TODO: Stop sanitizing the lockfile once we have bundler 2 installed
|
267
246
|
def sanitized_lockfile_body
|
268
247
|
re = FileUpdater::LockfileUpdater::LOCKFILE_ENDING
|
269
248
|
lockfile.content.gsub(re, "")
|