dependabot-bundler 0.235.0 → 0.237.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 38176c3434d5010be520cb43bc4c56a9932269422551b38ccd6e37dabd23e3d6
4
- data.tar.gz: bfd86e1e458314109a1694c60c663d0f487696400d8b7f69b8cd14e873b8ab78
3
+ metadata.gz: be50dcf437b4b6c5a4570e0c34f106900f8f8ba0ffd7e270b8fdef2a503859e6
4
+ data.tar.gz: fbaf4ba7a14c4c709cb669ecbd48268e51ba9ee82710edf4fdf6304fb114224d
5
5
  SHA512:
6
- metadata.gz: 1d347d3d714957801878e9953f21dfe1607bf870cb4dca6954e18f5a10bbcd115784ba2a3544b5007917ac02c212b50a1aea94426066826116e2c7673e015a4e
7
- data.tar.gz: 1d6fbeb3dbd3adf3fa5731aa49bd3efdf24dee0c6c985bb07646ff0b55a15b5d4de8bf8aa5be5d6be9979ce7a7f3b077e9f330308686bac2b312980fbbb85c75
6
+ metadata.gz: 26af90911a7dec4e6179c4b58d0504ce47f08e0e34583ed9d5c105e128c4b9c24608abb343f46c42ebc5204112968d394c8bd6b44d14cf02828bb4534270bd09
7
+ data.tar.gz: '0099faad52d13445a1c946ed9f66391278f062ae90bee7cfe6253d72b9a5dbce1c7f59972edaef4f8a99c1762b9447788146bafccb1f9537fdfec93684790ec3'
@@ -148,6 +148,9 @@ module Functions
148
148
 
149
149
  # Use HTTPS for GitHub if lockfile
150
150
  Bundler.settings.set_command_option("github.https", "true")
151
+
152
+ # Native helpers rely on dependency unlocking, so Bundler should never be frozen
153
+ Bundler.settings.set_command_option("frozen", "false")
151
154
  end
152
155
 
153
156
  def self.relevant_credentials(credentials)
@@ -42,9 +42,8 @@ module Functions
42
42
  .fetchers.flat_map do |fetcher|
43
43
  fetcher
44
44
  .specs([dependency_name], bundler_source)
45
- .search_all(dependency_name)
45
+ .search_all(dependency_name).map(&:version)
46
46
  end
47
- .map(&:version)
48
47
  end
49
48
 
50
49
  private
@@ -4,6 +4,7 @@
4
4
  module Functions
5
5
  class ForceUpdater
6
6
  class TransitiveDependencyError < StandardError; end
7
+ class TopLevelDependencyDowngradedError < StandardError; end
7
8
 
8
9
  def initialize(dependency_name:, target_version:, gemfile_name:,
9
10
  lockfile_name:, update_multiple_dependencies:)
@@ -21,13 +22,21 @@ module Functions
21
22
  definition = build_definition(dependencies_to_unlock: dependencies_to_unlock)
22
23
  definition.resolve_remotely!
23
24
  specs = definition.resolve
24
- updates = ([dependency_name, *dependencies_to_unlock] - subdependencies).uniq.map { |name| { name: name } }
25
+ updates = ([dependency_name, *dependencies_to_unlock] - subdependencies + extra_top_level_deps(specs)).uniq
26
+
27
+ updates = updates.map do |name|
28
+ {
29
+ name: name
30
+ }
31
+ end
32
+
25
33
  specs = specs.map do |dep|
26
34
  {
27
35
  name: dep.name,
28
36
  version: dep.version
29
37
  }
30
38
  end
39
+
31
40
  [updates, specs]
32
41
  rescue Bundler::SolveFailure => e
33
42
  raise unless update_multiple_dependencies?
@@ -53,6 +62,24 @@ module Functions
53
62
  :update_multiple_dependencies
54
63
  alias update_multiple_dependencies? update_multiple_dependencies
55
64
 
65
+ def extra_top_level_deps(specs)
66
+ top_level_dep_names.reject do |name|
67
+ original_version = original_specs.find { |s| s.name == name }&.version
68
+ new_version = specs[name].first&.version
69
+
70
+ if original_version == new_version
71
+ true
72
+ else
73
+ original_version = Gem::Version.new(original_version)
74
+ new_version = Gem::Version.new(new_version)
75
+
76
+ raise TopLevelDependencyDowngradedError if new_version < original_version
77
+
78
+ false
79
+ end
80
+ end
81
+ end
82
+
56
83
  def new_dependencies_to_unlock_from(error:, already_unlocked:)
57
84
  names = [*already_unlocked, dependency_name]
58
85
  extra_names_to_unlock = []
@@ -118,13 +145,15 @@ module Functions
118
145
  # subdependencies
119
146
  return [] unless lockfile
120
147
 
121
- all_deps = Bundler::LockfileParser.new(lockfile)
122
- .specs.map(&:name)
123
- top_level = Bundler::Definition
124
- .build(gemfile_name, lockfile_name, {})
125
- .dependencies.map(&:name)
148
+ original_specs.map(&:name) - top_level_dep_names
149
+ end
150
+
151
+ def top_level_dep_names
152
+ @top_level_dep_names ||= Bundler::Definition.build(gemfile_name, lockfile_name, {}).dependencies.map(&:name)
153
+ end
126
154
 
127
- all_deps - top_level
155
+ def original_specs
156
+ @original_specs ||= Bundler::LockfileParser.new(lockfile).specs
128
157
  end
129
158
 
130
159
  def unlock_gem(definition:, gem_name:)
@@ -127,7 +127,7 @@ module Functions
127
127
  def fetcher_class(dep)
128
128
  return unless dep.source.is_a?(::Bundler::Source::Rubygems)
129
129
 
130
- dep.source.fetchers.first.fetchers.first.class.to_s
130
+ dep.source.fetchers.first.send(:fetchers).first.class.to_s
131
131
  end
132
132
 
133
133
  def ruby_version
@@ -152,6 +152,9 @@ module Functions
152
152
  Bundler.ui = Bundler::UI::Silent.new
153
153
 
154
154
  Bundler.settings.set_command_option("forget_cli_options", "true")
155
+
156
+ # Native helpers rely on dependency unlocking, so Bundler should never be frozen
157
+ Bundler.settings.set_command_option("frozen", "false")
155
158
  end
156
159
 
157
160
  def self.relevant_credentials(credentials)
@@ -96,11 +96,11 @@ RSpec.describe Functions::DependencySource do
96
96
  end
97
97
 
98
98
  it "blows up with a useful error" do
99
- error_class = Bundler::Fetcher::BadAuthenticationError
99
+ error_class = Bundler::Fetcher::AuthenticationForbiddenError
100
100
  expect { private_registry_versions }
101
101
  .to raise_error do |error|
102
102
  expect(error).to be_a(error_class)
103
- expect(error.message).to include("Bad username or password for")
103
+ expect(error.message).to include("Access token could not be authenticated for")
104
104
  end
105
105
  end
106
106
  end
@@ -126,7 +126,7 @@ RSpec.describe Functions::DependencySource do
126
126
  .to raise_error do |error|
127
127
  expect(error).to be_a(Bundler::HTTPError)
128
128
  expect(error.message)
129
- .to include("Could not fetch specs from")
129
+ .to include("Could not fetch specs from #{registry_url} due to underlying error")
130
130
  end
131
131
  end
132
132
  end
@@ -1,6 +1,7 @@
1
1
  # typed: false
2
2
  # frozen_string_literal: true
3
3
 
4
+ require "sorbet-runtime"
4
5
  require "dependabot/file_fetchers"
5
6
  require "dependabot/file_fetchers/base"
6
7
  require "dependabot/bundler/file_updater/lockfile_updater"
@@ -9,6 +10,9 @@ require "dependabot/errors"
9
10
  module Dependabot
10
11
  module Bundler
11
12
  class FileFetcher < Dependabot::FileFetchers::Base
13
+ extend T::Sig
14
+ extend T::Helpers
15
+
12
16
  require "dependabot/bundler/file_fetcher/gemspec_finder"
13
17
  require "dependabot/bundler/file_fetcher/path_gemspec_finder"
14
18
  require "dependabot/bundler/file_fetcher/child_gemfile_finder"
@@ -32,8 +36,7 @@ module Dependabot
32
36
  }
33
37
  end
34
38
 
35
- private
36
-
39
+ sig { override.returns(T::Array[DependencyFile]) }
37
40
  def fetch_files
38
41
  fetched_files = []
39
42
  fetched_files << gemfile if gemfile
@@ -55,6 +58,8 @@ module Dependabot
55
58
  fetched_files
56
59
  end
57
60
 
61
+ private
62
+
58
63
  def uniq_files(fetched_files)
59
64
  uniq_files = fetched_files.reject(&:support_file?).uniq
60
65
  uniq_files += fetched_files
@@ -1,32 +1,43 @@
1
- # typed: true
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "bundler"
5
+ require "sorbet-runtime"
5
6
  require "dependabot/shared_helpers"
6
7
 
7
8
  module Dependabot
8
9
  module Bundler
9
10
  module NativeHelpers
11
+ extend T::Sig
12
+ extend T::Generic
13
+
10
14
  class BundleCommand
15
+ extend T::Sig
16
+
11
17
  MAX_SECONDS = 1800
12
18
  MIN_SECONDS = 60
13
19
 
20
+ sig { params(timeout_seconds: T.nilable(Integer)).void }
14
21
  def initialize(timeout_seconds)
15
- @timeout_seconds = clamp(timeout_seconds)
22
+ @timeout_seconds = T.let(clamp(timeout_seconds), Integer)
16
23
  end
17
24
 
25
+ sig { params(script: String).returns(String) }
18
26
  def build(script)
19
27
  [timeout_command, :ruby, script].compact.join(" ")
20
28
  end
21
29
 
22
30
  private
23
31
 
32
+ sig { returns(Integer) }
24
33
  attr_reader :timeout_seconds
25
34
 
35
+ sig { returns(T.nilable(String)) }
26
36
  def timeout_command
27
37
  "timeout -s HUP #{timeout_seconds}" unless timeout_seconds.zero?
28
38
  end
29
39
 
40
+ sig { params(seconds: T.nilable(Integer)).returns(Integer) }
30
41
  def clamp(seconds)
31
42
  return 0 unless seconds
32
43
 
@@ -34,6 +45,15 @@ module Dependabot
34
45
  end
35
46
  end
36
47
 
48
+ sig do
49
+ params(
50
+ function: String,
51
+ args: T::Hash[Symbol, String],
52
+ bundler_version: String,
53
+ options: T::Hash[Symbol, T.untyped]
54
+ )
55
+ .returns(T.untyped)
56
+ end
37
57
  def self.run_bundler_subprocess(function:, args:, bundler_version:, options: {})
38
58
  # Run helper suprocess with all bundler-related ENV variables removed
39
59
  helpers_path = versioned_helper_path(bundler_version)
@@ -60,10 +80,12 @@ module Dependabot
60
80
  end
61
81
  end
62
82
 
83
+ sig { params(bundler_major_version: String).returns(String) }
63
84
  def self.versioned_helper_path(bundler_major_version)
64
85
  File.join(native_helpers_root, "v#{bundler_major_version}")
65
86
  end
66
87
 
88
+ sig { returns(String) }
67
89
  def self.native_helpers_root
68
90
  helpers_root = ENV.fetch("DEPENDABOT_NATIVE_HELPERS_PATH", nil)
69
91
  return File.join(helpers_root, "bundler") unless helpers_root.nil?
@@ -78,15 +78,6 @@ module Dependabot
78
78
  ).parse
79
79
  end
80
80
 
81
- def top_level_dependencies
82
- @top_level_dependencies ||=
83
- FileParser.new(
84
- dependency_files: dependency_files.reject { |file| file.name == lockfile.name },
85
- credentials: credentials,
86
- source: nil
87
- ).parse
88
- end
89
-
90
81
  def dependencies_from(updated_deps, specs)
91
82
  # You might think we'd want to remove dependencies whose version
92
83
  # hadn't changed from this array. We don't. We still need to unlock
@@ -95,17 +86,14 @@ module Dependabot
95
86
  #
96
87
  # This is kind of a bug in Bundler, and we should try to fix it,
97
88
  # but resolving it won't necessarily be easy.
89
+ updated_deps.filter_map do |dep|
90
+ original_dep =
91
+ original_dependencies.find { |d| d.name == dep.fetch("name") }
92
+ spec = specs.find { |d| d.fetch("name") == dep.fetch("name") }
98
93
 
99
- # put the lead dependency first
100
- index = specs.index { |dep| dep["name"] == updated_deps.first["name"] }
101
- specs.unshift(specs.delete_at(index))
102
- specs.filter_map do |dep|
103
- next unless top_level_dependencies.find { |d| d.name == dep.fetch("name") }
104
-
105
- original_dep = original_dependencies.find { |d| d.name == dep.fetch("name") }
106
- next if dep.fetch("version") == original_dep.version
94
+ next if spec.fetch("version") == original_dep.version
107
95
 
108
- build_dependency(original_dep, dep)
96
+ build_dependency(original_dep, spec)
109
97
  end
110
98
  end
111
99
 
@@ -24,8 +24,9 @@ module Dependabot
24
24
  MISSING_AUTH_REGEX = /bundle config (?:set --global )?(?<source>.*) username:password/
25
25
 
26
26
  BAD_AUTH_REGEX = /Bad username or password for (?<source>.*)\.$/
27
+ FORBIDDEN_AUTH_REGEX = /Access token could not be authenticated for (?<source>.*)\.$/
27
28
  BAD_CERT_REGEX = /verify the SSL certificate for (?<source>.*)\.$/
28
- HTTP_ERR_REGEX = /Could not fetch specs from (?<source>.*)$/
29
+ HTTP_ERR_REGEX = /Could not fetch specs from (?<source>\S+)/
29
30
  end
30
31
 
31
32
  RETRYABLE_ERRORS = %w(
@@ -133,6 +134,10 @@ module Dependabot
133
134
  regex = BundlerErrorPatterns::MISSING_AUTH_REGEX
134
135
  source = error.message.match(regex)[:source]
135
136
  raise Dependabot::PrivateSourceAuthenticationFailure, source
137
+ when "Bundler::Fetcher::AuthenticationForbiddenError"
138
+ regex = BundlerErrorPatterns::FORBIDDEN_AUTH_REGEX
139
+ source = error.message.match(regex)[:source]
140
+ raise Dependabot::PrivateSourceAuthenticationFailure, source
136
141
  when "Bundler::Fetcher::BadAuthenticationError"
137
142
  regex = BundlerErrorPatterns::BAD_AUTH_REGEX
138
143
  source = error.message.match(regex)[:source]
@@ -1,4 +1,4 @@
1
- # typed: true
1
+ # typed: strong
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "dependabot/version"
@@ -1,4 +1,4 @@
1
- # typed: true
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
4
  # These all need to be required so the various classes can be registered in a
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dependabot-bundler
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.235.0
4
+ version: 0.237.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dependabot
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-10-19 00:00:00.000000000 Z
11
+ date: 2023-11-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dependabot-common
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - '='
18
18
  - !ruby/object:Gem::Version
19
- version: 0.235.0
19
+ version: 0.237.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - '='
25
25
  - !ruby/object:Gem::Version
26
- version: 0.235.0
26
+ version: 0.237.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: debug
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -94,20 +94,34 @@ dependencies:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
96
  version: '1.3'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rspec-sorbet
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: 1.9.2
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: 1.9.2
97
111
  - !ruby/object:Gem::Dependency
98
112
  name: rubocop
99
113
  requirement: !ruby/object:Gem::Requirement
100
114
  requirements:
101
115
  - - "~>"
102
116
  - !ruby/object:Gem::Version
103
- version: 1.56.0
117
+ version: 1.57.2
104
118
  type: :development
105
119
  prerelease: false
106
120
  version_requirements: !ruby/object:Gem::Requirement
107
121
  requirements:
108
122
  - - "~>"
109
123
  - !ruby/object:Gem::Version
110
- version: 1.56.0
124
+ version: 1.57.2
111
125
  - !ruby/object:Gem::Dependency
112
126
  name: rubocop-performance
113
127
  requirement: !ruby/object:Gem::Requirement
@@ -282,7 +296,7 @@ licenses:
282
296
  - Nonstandard
283
297
  metadata:
284
298
  bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
285
- changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.235.0
299
+ changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.237.0
286
300
  post_install_message:
287
301
  rdoc_options: []
288
302
  require_paths: