dependabot-bundler 0.387.0 → 0.388.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
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 30d3868144d5663052459e012960b20f211b97ce0f097a2971c50b8d351c4176
|
|
4
|
+
data.tar.gz: bada129a0da00144bdd4f600ce5dee62a90ef73943cfb7b75e4f55f0c94d28f7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5d7cbe81d255cac2f4c6c4709ee68446f060703ff23c9a1286250327b6db5717e1a9fbc1b3058eecc928eec9881576b04a7d161db3c95a8488ca072306dfb072
|
|
7
|
+
data.tar.gz: 232bd45a635a8ad61404d957776977d25a1cf342fbe42025eeb14b629f0ff694ffd3a08bf47c059cb4a6e2ac60588d3261271c5af888076b92a9a22ba7229d3d
|
|
@@ -65,12 +65,7 @@ module Dependabot
|
|
|
65
65
|
command: command,
|
|
66
66
|
function: function,
|
|
67
67
|
args: args,
|
|
68
|
-
env:
|
|
69
|
-
# Set BUNDLE_PATH to a thread-safe location
|
|
70
|
-
"BUNDLE_PATH" => File.join(Dependabot::Utils::BUMP_TMP_DIR_PATH, ".bundle"),
|
|
71
|
-
# Set GEM_HOME to where the proper version of Bundler is installed
|
|
72
|
-
"GEM_HOME" => File.join(helpers_path, ".bundle")
|
|
73
|
-
}
|
|
68
|
+
env: subprocess_env(helpers_path, options)
|
|
74
69
|
)
|
|
75
70
|
rescue SharedHelpers::HelperSubprocessFailed => e
|
|
76
71
|
# TODO: Remove once we stop stubbing out the V2 native helper
|
|
@@ -85,6 +80,28 @@ module Dependabot
|
|
|
85
80
|
File.join(native_helpers_root, "v#{bundler_major_version}")
|
|
86
81
|
end
|
|
87
82
|
|
|
83
|
+
sig do
|
|
84
|
+
params(helpers_path: String, options: T::Hash[Symbol, T.untyped])
|
|
85
|
+
.returns(T::Hash[String, String])
|
|
86
|
+
end
|
|
87
|
+
def self.subprocess_env(helpers_path, options)
|
|
88
|
+
env = {
|
|
89
|
+
# Set BUNDLE_PATH to a thread-safe location
|
|
90
|
+
"BUNDLE_PATH" => File.join(Dependabot::Utils::BUMP_TMP_DIR_PATH, ".bundle"),
|
|
91
|
+
# Set GEM_HOME to where the proper version of Bundler is installed
|
|
92
|
+
"GEM_HOME" => File.join(helpers_path, ".bundle")
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
# Bundler 4+ enforces the Gemfile `source cooldown:` window natively, holding
|
|
96
|
+
# back releases (including transitive dependencies) younger than the configured
|
|
97
|
+
# number of days. Disable it only for security updates so vulnerability
|
|
98
|
+
# remediation is never blocked; normal runs keep native enforcement as the
|
|
99
|
+
# per-source source of truth.
|
|
100
|
+
env["BUNDLE_COOLDOWN"] = "0" if options.fetch(:security_updates_only, false)
|
|
101
|
+
|
|
102
|
+
env
|
|
103
|
+
end
|
|
104
|
+
|
|
88
105
|
sig { returns(String) }
|
|
89
106
|
def self.native_helpers_root
|
|
90
107
|
helpers_root = ENV.fetch("DEPENDABOT_NATIVE_HELPERS_PATH", nil)
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# typed: strong
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require "dependabot/dependency_file"
|
|
5
|
+
require "dependabot/security_advisory"
|
|
6
|
+
require "dependabot/package/release_cooldown_options"
|
|
7
|
+
require "dependabot/bundler/update_checker"
|
|
8
|
+
|
|
9
|
+
module Dependabot
|
|
10
|
+
module Bundler
|
|
11
|
+
class UpdateChecker < UpdateCheckers::Base
|
|
12
|
+
# Owns the cooldown policy for Bundler updates: it derives the effective
|
|
13
|
+
# `ReleaseCooldownOptions` from an optional `cooldown:` declared on a Gemfile
|
|
14
|
+
# `source` line and decides when Bundler's native cooldown must be disabled.
|
|
15
|
+
#
|
|
16
|
+
# Extraction is best-effort: it reads the manifest text rather than Bundler's
|
|
17
|
+
# evaluated source config, so uncommon declarations (see SOURCE_COOLDOWN_REGEX
|
|
18
|
+
# and #manifest_files) may be missed or understated. For regular updates
|
|
19
|
+
# Bundler's native cooldown stays enabled as the authoritative backstop, so the
|
|
20
|
+
# worst case is a missed update, never selecting a version native resolution
|
|
21
|
+
# rejects.
|
|
22
|
+
class CooldownOptionsBuilder
|
|
23
|
+
extend T::Sig
|
|
24
|
+
|
|
25
|
+
# Matches the common inline `source "<url>", cooldown: <days>` form. Uncommon
|
|
26
|
+
# forms are not handled: a dynamic URL, `cooldown:` on a wrapped line, or a
|
|
27
|
+
# non-literal/underscored value (e.g. `cooldown: 14_000` reads as `14`). Those
|
|
28
|
+
# Gemfiles fall back to Bundler's native cooldown during resolution, so a
|
|
29
|
+
# too-new release is rejected rather than selected — a missed update at worst,
|
|
30
|
+
# never an incorrect version.
|
|
31
|
+
SOURCE_COOLDOWN_REGEX =
|
|
32
|
+
/^\s*source\s*(?:\(\s*)?["'][^"']+["']\s*,[^\n#]*?\bcooldown:\s*(\d+)/
|
|
33
|
+
|
|
34
|
+
sig do
|
|
35
|
+
params(
|
|
36
|
+
dependency_files: T::Array[Dependabot::DependencyFile],
|
|
37
|
+
security_advisories: T::Array[Dependabot::SecurityAdvisory]
|
|
38
|
+
).void
|
|
39
|
+
end
|
|
40
|
+
def initialize(dependency_files:, security_advisories:)
|
|
41
|
+
@dependency_files = dependency_files
|
|
42
|
+
@security_advisories = security_advisories
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Effective cooldown for target-dependency version selection. Target versions
|
|
46
|
+
# are fetched from the RubyGems API, which Bundler's native cooldown does not
|
|
47
|
+
# gate, so Dependabot applies the source cooldown here. Security updates must
|
|
48
|
+
# never be blocked, so the base config is returned unchanged.
|
|
49
|
+
sig do
|
|
50
|
+
params(base_cooldown: T.nilable(Dependabot::Package::ReleaseCooldownOptions))
|
|
51
|
+
.returns(T.nilable(Dependabot::Package::ReleaseCooldownOptions))
|
|
52
|
+
end
|
|
53
|
+
def release_cooldown_options(base_cooldown)
|
|
54
|
+
return base_cooldown if security_update?
|
|
55
|
+
|
|
56
|
+
source_days = source_cooldown_days
|
|
57
|
+
return base_cooldown if source_days.nil? || !source_days.positive?
|
|
58
|
+
return Dependabot::Package::ReleaseCooldownOptions.new(default_days: source_days) if base_cooldown.nil?
|
|
59
|
+
|
|
60
|
+
# The Gemfile `source cooldown:` applies uniformly to every candidate version,
|
|
61
|
+
# so treat it as a global floor: max every semver tier with it and drop
|
|
62
|
+
# include/exclude so no dependency can bypass it. Mirrors npm_and_yarn's
|
|
63
|
+
# `merge_cooldown_with_npmrc_floor`.
|
|
64
|
+
Dependabot::Package::ReleaseCooldownOptions.new(
|
|
65
|
+
default_days: [base_cooldown.default_days, source_days].max,
|
|
66
|
+
semver_major_days: [base_cooldown.semver_major_days, source_days].max,
|
|
67
|
+
semver_minor_days: [base_cooldown.semver_minor_days, source_days].max,
|
|
68
|
+
semver_patch_days: [base_cooldown.semver_patch_days, source_days].max,
|
|
69
|
+
include: [],
|
|
70
|
+
exclude: []
|
|
71
|
+
)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Options for the native Bundler subprocess. Native cooldown stays enabled for
|
|
75
|
+
# regular updates (per-source, transitive-aware enforcement) and is disabled
|
|
76
|
+
# for security updates so remediation is never blocked.
|
|
77
|
+
sig { params(options: T::Hash[Symbol, T.anything]).returns(T::Hash[Symbol, T.anything]) }
|
|
78
|
+
def native_helper_options(options)
|
|
79
|
+
options.merge(security_updates_only: security_update?)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
private
|
|
83
|
+
|
|
84
|
+
sig { returns(T::Array[Dependabot::DependencyFile]) }
|
|
85
|
+
attr_reader :dependency_files
|
|
86
|
+
|
|
87
|
+
sig { returns(T::Boolean) }
|
|
88
|
+
def security_update?
|
|
89
|
+
@security_advisories.any?
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
sig { returns(T.nilable(Integer)) }
|
|
93
|
+
def source_cooldown_days
|
|
94
|
+
manifest_files.flat_map do |file|
|
|
95
|
+
T.must(file.content).scan(SOURCE_COOLDOWN_REGEX).flatten.map { |value| Integer(value, 10) }
|
|
96
|
+
end.max
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Support files (e.g. child Gemfiles fetched for `eval_gemfile`) and lockfiles
|
|
100
|
+
# are skipped, so a `cooldown:` declared only in an evaluated Gemfile is not seen
|
|
101
|
+
# here; Bundler's native cooldown still enforces it during resolution.
|
|
102
|
+
sig { returns(T::Array[Dependabot::DependencyFile]) }
|
|
103
|
+
def manifest_files
|
|
104
|
+
dependency_files.reject(&:support_file?)
|
|
105
|
+
.reject { |file| file.name.end_with?(".lock", ".locked", ".gemspec", ".specification") }
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
@@ -10,13 +10,19 @@ require "dependabot/update_checkers/base"
|
|
|
10
10
|
|
|
11
11
|
module Dependabot
|
|
12
12
|
module Bundler
|
|
13
|
-
|
|
13
|
+
# The cooldown/native-option policy lives in CooldownOptionsBuilder, but this
|
|
14
|
+
# orchestrator still exceeds the class-length threshold because of its git and
|
|
15
|
+
# resolution surface. Splitting that further is out of scope here, and the other
|
|
16
|
+
# ecosystem update checkers (npm_and_yarn, bun, docker, python) disable this cop
|
|
17
|
+
# for the same reason, so the exception is retained deliberately.
|
|
18
|
+
class UpdateChecker < Dependabot::UpdateCheckers::Base # rubocop:disable Metrics/ClassLength
|
|
14
19
|
require_relative "update_checker/force_updater"
|
|
15
20
|
require_relative "update_checker/file_preparer"
|
|
16
21
|
require_relative "update_checker/requirements_updater"
|
|
17
22
|
require_relative "update_checker/version_resolver"
|
|
18
23
|
require_relative "update_checker/latest_version_finder"
|
|
19
24
|
require_relative "update_checker/conflicting_dependency_resolver"
|
|
25
|
+
require_relative "update_checker/cooldown_options_builder"
|
|
20
26
|
extend T::Sig
|
|
21
27
|
|
|
22
28
|
sig { override.returns(T.nilable(T.any(String, Dependabot::Bundler::Version))) }
|
|
@@ -120,13 +126,18 @@ module Dependabot
|
|
|
120
126
|
end
|
|
121
127
|
end
|
|
122
128
|
|
|
129
|
+
sig { returns(T.nilable(Dependabot::Package::ReleaseCooldownOptions)) }
|
|
130
|
+
def update_cooldown
|
|
131
|
+
cooldown_options_builder.release_cooldown_options(@update_cooldown)
|
|
132
|
+
end
|
|
133
|
+
|
|
123
134
|
sig { override.returns(T::Array[T::Hash[String, String]]) }
|
|
124
135
|
def conflicting_dependencies
|
|
125
136
|
ConflictingDependencyResolver.new(
|
|
126
137
|
dependency_files: dependency_files,
|
|
127
138
|
repo_contents_path: repo_contents_path,
|
|
128
139
|
credentials: credentials,
|
|
129
|
-
options:
|
|
140
|
+
options: native_bundler_options
|
|
130
141
|
).conflicting_dependencies(
|
|
131
142
|
dependency: dependency,
|
|
132
143
|
target_version: lowest_security_fix_version.to_s # Convert Version to String
|
|
@@ -135,6 +146,36 @@ module Dependabot
|
|
|
135
146
|
|
|
136
147
|
private
|
|
137
148
|
|
|
149
|
+
# Options passed to the native Bundler subprocess. The security-update signal is
|
|
150
|
+
# derived from the advisories so native cooldown is disabled only for security
|
|
151
|
+
# remediation; see CooldownOptionsBuilder for the policy.
|
|
152
|
+
sig { returns(T::Hash[Symbol, T.anything]) }
|
|
153
|
+
def native_bundler_options
|
|
154
|
+
@native_bundler_options ||= T.let(
|
|
155
|
+
cooldown_options_builder.native_helper_options(options),
|
|
156
|
+
T.nilable(T::Hash[Symbol, T.anything])
|
|
157
|
+
)
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
sig { returns(CooldownOptionsBuilder) }
|
|
161
|
+
def cooldown_options_builder
|
|
162
|
+
@cooldown_options_builder ||= T.let(
|
|
163
|
+
CooldownOptionsBuilder.new(
|
|
164
|
+
dependency_files: dependency_files,
|
|
165
|
+
security_advisories: security_advisories
|
|
166
|
+
),
|
|
167
|
+
T.nilable(CooldownOptionsBuilder)
|
|
168
|
+
)
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
# Bundler's Gemfile `source cooldown:` applies only to RubyGems remotes, so a
|
|
172
|
+
# git dependency's tag selection/resolvability must use the user-configured
|
|
173
|
+
# cooldown without the RubyGems source floor added by CooldownOptionsBuilder.
|
|
174
|
+
sig { returns(T.nilable(Dependabot::Package::ReleaseCooldownOptions)) }
|
|
175
|
+
def git_dependency_cooldown
|
|
176
|
+
@update_cooldown
|
|
177
|
+
end
|
|
178
|
+
|
|
138
179
|
sig { returns(T::Boolean) }
|
|
139
180
|
def requirements_unlocked?
|
|
140
181
|
dependency.specific_requirements.none?
|
|
@@ -190,7 +231,7 @@ module Dependabot
|
|
|
190
231
|
target_version: version,
|
|
191
232
|
requirements_update_strategy: T.must(requirements_update_strategy),
|
|
192
233
|
update_multiple_dependencies: false,
|
|
193
|
-
options:
|
|
234
|
+
options: native_bundler_options
|
|
194
235
|
).updated_dependencies
|
|
195
236
|
true
|
|
196
237
|
rescue Dependabot::DependencyFileNotResolvable
|
|
@@ -213,8 +254,8 @@ module Dependabot
|
|
|
213
254
|
ignored_versions: ignored_versions,
|
|
214
255
|
raise_on_ignored: raise_on_ignored,
|
|
215
256
|
replacement_git_pin: tag,
|
|
216
|
-
cooldown_options:
|
|
217
|
-
options:
|
|
257
|
+
cooldown_options: git_dependency_cooldown,
|
|
258
|
+
options: native_bundler_options
|
|
218
259
|
).latest_resolvable_version_details
|
|
219
260
|
true
|
|
220
261
|
rescue Dependabot::DependencyFileNotResolvable
|
|
@@ -255,7 +296,7 @@ module Dependabot
|
|
|
255
296
|
# If the dependency is pinned to a tag that looks like a version then
|
|
256
297
|
# we want to update that tag. The latest version will then be the SHA
|
|
257
298
|
# of the latest tag that looks like a version.
|
|
258
|
-
latest_tag = git_commit_checker.local_tag_for_pinned_version_ref(
|
|
299
|
+
latest_tag = git_commit_checker.local_tag_for_pinned_version_ref(git_dependency_cooldown)
|
|
259
300
|
return latest_tag.fetch(:tag_sha) || dependency.version if latest_tag
|
|
260
301
|
|
|
261
302
|
# If the dependency is pinned to a tag that doesn't look like a
|
|
@@ -279,7 +320,7 @@ module Dependabot
|
|
|
279
320
|
# we want to update that tag. The latest version will then be the SHA
|
|
280
321
|
# of the latest tag that looks like a version.
|
|
281
322
|
if latest_git_tag_is_resolvable?
|
|
282
|
-
new_tag = git_commit_checker.local_tag_for_pinned_version_ref(
|
|
323
|
+
new_tag = git_commit_checker.local_tag_for_pinned_version_ref(git_dependency_cooldown)
|
|
283
324
|
return new_tag&.fetch(:tag_sha)
|
|
284
325
|
end
|
|
285
326
|
|
|
@@ -314,7 +355,7 @@ module Dependabot
|
|
|
314
355
|
|
|
315
356
|
sig { returns(T::Boolean) }
|
|
316
357
|
def latest_git_tag_is_resolvable?
|
|
317
|
-
latest_tag_details = git_commit_checker.local_tag_for_pinned_version_ref(
|
|
358
|
+
latest_tag_details = git_commit_checker.local_tag_for_pinned_version_ref(git_dependency_cooldown)
|
|
318
359
|
return false unless latest_tag_details
|
|
319
360
|
|
|
320
361
|
git_tag_resolvable?(latest_tag_details.fetch(:tag))
|
|
@@ -334,7 +375,7 @@ module Dependabot
|
|
|
334
375
|
|
|
335
376
|
# Update the git tag if updating a pinned version
|
|
336
377
|
if latest_git_tag_is_resolvable?
|
|
337
|
-
new_tag = git_commit_checker.local_tag_for_pinned_version_ref(
|
|
378
|
+
new_tag = git_commit_checker.local_tag_for_pinned_version_ref(git_dependency_cooldown)
|
|
338
379
|
return T.must(dependency_source_details).merge(ref: T.must(new_tag).fetch(:tag))
|
|
339
380
|
end
|
|
340
381
|
|
|
@@ -363,7 +404,7 @@ module Dependabot
|
|
|
363
404
|
credentials: credentials,
|
|
364
405
|
target_version: T.cast(latest_version, Dependabot::Version),
|
|
365
406
|
requirements_update_strategy: T.must(requirements_update_strategy),
|
|
366
|
-
options:
|
|
407
|
+
options: native_bundler_options
|
|
367
408
|
)
|
|
368
409
|
end
|
|
369
410
|
|
|
@@ -398,7 +439,7 @@ module Dependabot
|
|
|
398
439
|
unlock_requirement: unlock_requirement,
|
|
399
440
|
latest_allowable_version: latest_version,
|
|
400
441
|
cooldown_options: update_cooldown,
|
|
401
|
-
options:
|
|
442
|
+
options: native_bundler_options
|
|
402
443
|
)
|
|
403
444
|
end
|
|
404
445
|
|
|
@@ -420,7 +461,7 @@ module Dependabot
|
|
|
420
461
|
raise_on_ignored: raise_on_ignored,
|
|
421
462
|
security_advisories: security_advisories,
|
|
422
463
|
cooldown_options: update_cooldown,
|
|
423
|
-
options:
|
|
464
|
+
options: native_bundler_options
|
|
424
465
|
)
|
|
425
466
|
end
|
|
426
467
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: dependabot-bundler
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.388.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Dependabot
|
|
@@ -15,14 +15,14 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - '='
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: 0.
|
|
18
|
+
version: 0.388.0
|
|
19
19
|
type: :runtime
|
|
20
20
|
prerelease: false
|
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
22
|
requirements:
|
|
23
23
|
- - '='
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
|
-
version: 0.
|
|
25
|
+
version: 0.388.0
|
|
26
26
|
- !ruby/object:Gem::Dependency
|
|
27
27
|
name: parallel
|
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -340,6 +340,7 @@ files:
|
|
|
340
340
|
- lib/dependabot/bundler/requirement.rb
|
|
341
341
|
- lib/dependabot/bundler/update_checker.rb
|
|
342
342
|
- lib/dependabot/bundler/update_checker/conflicting_dependency_resolver.rb
|
|
343
|
+
- lib/dependabot/bundler/update_checker/cooldown_options_builder.rb
|
|
343
344
|
- lib/dependabot/bundler/update_checker/file_preparer.rb
|
|
344
345
|
- lib/dependabot/bundler/update_checker/force_updater.rb
|
|
345
346
|
- lib/dependabot/bundler/update_checker/latest_version_finder.rb
|
|
@@ -353,7 +354,7 @@ licenses:
|
|
|
353
354
|
- MIT
|
|
354
355
|
metadata:
|
|
355
356
|
bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
|
|
356
|
-
changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.
|
|
357
|
+
changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.388.0
|
|
357
358
|
rdoc_options: []
|
|
358
359
|
require_paths:
|
|
359
360
|
- lib
|