dependabot-github_actions 0.318.0 → 0.319.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/github_actions/helpers.rb +80 -0
- data/lib/dependabot/github_actions/package/package_details_fetcher.rb +237 -0
- data/lib/dependabot/github_actions/update_checker/latest_version_finder.rb +230 -0
- data/lib/dependabot/github_actions/update_checker.rb +36 -158
- metadata +7 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fc4883bf917e6eb180ff085886dff4548085a8b49cb364c6c0e670a04e722283
|
4
|
+
data.tar.gz: 723663decd469822de084aeee604bdef7aa6b3cf0e0f86f4fb38a80c52753363
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 247ff7c4c4219bd38c373e81b7150a7696667db8f9ec152c74d3de49957efc13074498bcb3d26a175832fac41a2f6d07949feb45ab50ad0e4377e8692a9ebfe8
|
7
|
+
data.tar.gz: 7e0c4f1b2f8a61471c20f9d77e690bde837d9eb317eba956f6676e1c8ed63d4fa3821290fc152683269e277cf98d5074beaf5194fb715dc154084160e242f7ee
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# typed: strong
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "dependabot/dependency"
|
5
|
+
require "dependabot/errors"
|
6
|
+
require "dependabot/file_fetchers"
|
7
|
+
require "dependabot/file_fetchers/base"
|
8
|
+
require "dependabot/github_actions/constants"
|
9
|
+
require "dependabot/github_actions/requirement"
|
10
|
+
require "dependabot/github_actions/version"
|
11
|
+
require "dependabot/update_checkers"
|
12
|
+
require "dependabot/update_checkers/base"
|
13
|
+
require "dependabot/update_checkers/version_filters"
|
14
|
+
require "sorbet-runtime"
|
15
|
+
|
16
|
+
module Dependabot
|
17
|
+
module GithubActions
|
18
|
+
module Helpers
|
19
|
+
class Githelper
|
20
|
+
extend T::Sig
|
21
|
+
|
22
|
+
sig do
|
23
|
+
params(
|
24
|
+
dependency: Dependabot::Dependency,
|
25
|
+
credentials: T::Array[Dependabot::Credential],
|
26
|
+
ignored_versions: T::Array[String],
|
27
|
+
raise_on_ignored: T::Boolean,
|
28
|
+
consider_version_branches_pinned: T::Boolean,
|
29
|
+
dependency_source_details: T.nilable(T::Hash[Symbol, String])
|
30
|
+
)
|
31
|
+
.void
|
32
|
+
end
|
33
|
+
def initialize(dependency:, credentials:,
|
34
|
+
ignored_versions: [], raise_on_ignored: false,
|
35
|
+
consider_version_branches_pinned: false, dependency_source_details: nil)
|
36
|
+
@dependency = dependency
|
37
|
+
@credentials = credentials
|
38
|
+
@ignored_versions = ignored_versions
|
39
|
+
@raise_on_ignored = raise_on_ignored
|
40
|
+
@consider_version_branches_pinned = consider_version_branches_pinned
|
41
|
+
@dependency_source_details = dependency_source_details
|
42
|
+
end
|
43
|
+
|
44
|
+
sig { returns(Dependabot::Dependency) }
|
45
|
+
attr_reader :dependency
|
46
|
+
sig { returns(T::Array[Dependabot::Credential]) }
|
47
|
+
attr_reader :credentials
|
48
|
+
sig { returns(T::Array[String]) }
|
49
|
+
attr_reader :ignored_versions
|
50
|
+
sig { returns(T::Boolean) }
|
51
|
+
attr_reader :raise_on_ignored
|
52
|
+
|
53
|
+
sig { returns(Dependabot::GitCommitChecker) }
|
54
|
+
def git_commit_checker
|
55
|
+
@git_commit_checker ||= T.let(
|
56
|
+
git_commit_checker_for(nil),
|
57
|
+
T.nilable(Dependabot::GitCommitChecker)
|
58
|
+
)
|
59
|
+
end
|
60
|
+
|
61
|
+
sig { params(source: T.nilable(T::Hash[Symbol, String])).returns(Dependabot::GitCommitChecker) }
|
62
|
+
def git_commit_checker_for(source)
|
63
|
+
@git_commit_checkers ||= T.let(
|
64
|
+
{},
|
65
|
+
T.nilable(T::Hash[T.nilable(T::Hash[Symbol, String]), Dependabot::GitCommitChecker])
|
66
|
+
)
|
67
|
+
|
68
|
+
@git_commit_checkers[source] ||= Dependabot::GitCommitChecker.new(
|
69
|
+
dependency: dependency,
|
70
|
+
credentials: credentials,
|
71
|
+
ignored_versions: ignored_versions,
|
72
|
+
raise_on_ignored: raise_on_ignored,
|
73
|
+
consider_version_branches_pinned: true,
|
74
|
+
dependency_source_details: source
|
75
|
+
)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,237 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "cgi"
|
5
|
+
require "json"
|
6
|
+
require "nokogiri"
|
7
|
+
require "sorbet-runtime"
|
8
|
+
require "time"
|
9
|
+
|
10
|
+
require "dependabot/errors"
|
11
|
+
require "dependabot/github_actions/helpers"
|
12
|
+
require "dependabot/github_actions/requirement"
|
13
|
+
require "dependabot/github_actions/update_checker"
|
14
|
+
require "dependabot/github_actions/version"
|
15
|
+
require "dependabot/package/package_details"
|
16
|
+
require "dependabot/package/package_release"
|
17
|
+
require "dependabot/registry_client"
|
18
|
+
require "dependabot/shared_helpers"
|
19
|
+
|
20
|
+
module Dependabot
|
21
|
+
module GithubActions
|
22
|
+
module Package
|
23
|
+
class PackageDetailsFetcher
|
24
|
+
extend T::Sig
|
25
|
+
|
26
|
+
sig do
|
27
|
+
params(
|
28
|
+
dependency: Dependabot::Dependency,
|
29
|
+
credentials: T::Array[Dependabot::Credential],
|
30
|
+
ignored_versions: T::Array[String],
|
31
|
+
raise_on_ignored: T::Boolean,
|
32
|
+
security_advisories: T::Array[Dependabot::SecurityAdvisory]
|
33
|
+
).void
|
34
|
+
end
|
35
|
+
def initialize(dependency:,
|
36
|
+
credentials:,
|
37
|
+
ignored_versions: [],
|
38
|
+
raise_on_ignored: false,
|
39
|
+
security_advisories: [])
|
40
|
+
@dependency = dependency
|
41
|
+
@credentials = credentials
|
42
|
+
@raise_on_ignored = raise_on_ignored
|
43
|
+
@ignored_versions = ignored_versions
|
44
|
+
@security_advisories = security_advisories
|
45
|
+
|
46
|
+
@git_helper = T.let(git_helper, Dependabot::GithubActions::Helpers::Githelper)
|
47
|
+
end
|
48
|
+
|
49
|
+
sig { returns(Dependabot::Dependency) }
|
50
|
+
attr_reader :dependency
|
51
|
+
sig { returns(T::Array[Dependabot::Credential]) }
|
52
|
+
attr_reader :credentials
|
53
|
+
sig { returns(T::Array[String]) }
|
54
|
+
attr_reader :ignored_versions
|
55
|
+
sig { returns(T::Boolean) }
|
56
|
+
attr_reader :raise_on_ignored
|
57
|
+
sig { returns(T::Array[Dependabot::SecurityAdvisory]) }
|
58
|
+
attr_reader :security_advisories
|
59
|
+
|
60
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
61
|
+
sig { returns(T.nilable(T.any(Dependabot::Version, String))) }
|
62
|
+
def release_list_for_git_dependency
|
63
|
+
# TODO: Support Docker sources
|
64
|
+
return unless git_dependency?
|
65
|
+
return current_commit unless git_commit_checker.pinned?
|
66
|
+
|
67
|
+
# If the dependency is pinned to a tag that looks like a version then
|
68
|
+
# we want to update that tag.
|
69
|
+
if git_commit_checker.pinned_ref_looks_like_version? && latest_version_tag
|
70
|
+
latest_version = latest_version_tag&.fetch(:version)
|
71
|
+
return current_version if shortened_semver_eq?(dependency.version, latest_version.to_s)
|
72
|
+
|
73
|
+
return latest_version
|
74
|
+
end
|
75
|
+
|
76
|
+
if git_commit_checker.pinned_ref_looks_like_commit_sha? && latest_version_tag
|
77
|
+
latest_version = latest_version_tag&.fetch(:version)
|
78
|
+
return latest_commit_for_pinned_ref unless git_commit_checker.local_tag_for_pinned_sha
|
79
|
+
|
80
|
+
return latest_version
|
81
|
+
end
|
82
|
+
|
83
|
+
# If the dependency is pinned to a tag that doesn't look like a
|
84
|
+
# version or a commit SHA then there's nothing we can do.
|
85
|
+
nil
|
86
|
+
end
|
87
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
88
|
+
|
89
|
+
sig { returns(T.nilable(T::Hash[Symbol, T.untyped])) }
|
90
|
+
def lowest_security_fix_version_tag
|
91
|
+
# TODO: Support Docker sources
|
92
|
+
return unless git_dependency?
|
93
|
+
|
94
|
+
@lowest_security_fix_version_tag ||= T.let(
|
95
|
+
begin
|
96
|
+
tags_matching_precision = git_commit_checker.local_tags_for_allowed_versions_matching_existing_precision
|
97
|
+
lowest_fixed_version = find_lowest_secure_version(tags_matching_precision)
|
98
|
+
if lowest_fixed_version
|
99
|
+
lowest_fixed_version
|
100
|
+
else
|
101
|
+
tags = git_commit_checker.local_tags_for_allowed_versions
|
102
|
+
find_lowest_secure_version(tags)
|
103
|
+
end
|
104
|
+
end,
|
105
|
+
T.nilable(T::Hash[Symbol, String])
|
106
|
+
)
|
107
|
+
end
|
108
|
+
|
109
|
+
sig { returns(T.nilable(T::Hash[Symbol, T.untyped])) }
|
110
|
+
def latest_version_tag
|
111
|
+
@latest_version_tag ||= T.let(
|
112
|
+
begin
|
113
|
+
return git_commit_checker.local_tag_for_latest_version if dependency.version.nil?
|
114
|
+
|
115
|
+
ref = git_commit_checker.local_ref_for_latest_version_matching_existing_precision
|
116
|
+
return ref if ref && ref.fetch(:version) > current_version
|
117
|
+
|
118
|
+
git_commit_checker.local_ref_for_latest_version_lower_precision
|
119
|
+
end,
|
120
|
+
T.nilable(T::Hash[Symbol, T.untyped])
|
121
|
+
)
|
122
|
+
end
|
123
|
+
|
124
|
+
private
|
125
|
+
|
126
|
+
sig { returns(Dependabot::GitCommitChecker) }
|
127
|
+
def git_commit_checker
|
128
|
+
@git_commit_checker ||= T.let(
|
129
|
+
@git_helper.git_commit_checker,
|
130
|
+
T.nilable(Dependabot::GitCommitChecker)
|
131
|
+
)
|
132
|
+
end
|
133
|
+
|
134
|
+
sig { returns(T.nilable(String)) }
|
135
|
+
def current_commit
|
136
|
+
git_commit_checker.head_commit_for_current_branch
|
137
|
+
end
|
138
|
+
|
139
|
+
sig { params(base: T.nilable(String), other: String).returns(T::Boolean) }
|
140
|
+
def shortened_semver_eq?(base, other)
|
141
|
+
return false unless base
|
142
|
+
|
143
|
+
base_split = base.split(".")
|
144
|
+
other_split = other.split(".")
|
145
|
+
return false unless base_split.length <= other_split.length
|
146
|
+
|
147
|
+
other_split[0..base_split.length - 1] == base_split
|
148
|
+
end
|
149
|
+
|
150
|
+
sig { returns(T.nilable(Dependabot::Version)) }
|
151
|
+
def current_version
|
152
|
+
@current_version ||= T.let(dependency.numeric_version, T.nilable(Dependabot::Version))
|
153
|
+
end
|
154
|
+
|
155
|
+
sig { returns(T.nilable(String)) }
|
156
|
+
def latest_commit_for_pinned_ref
|
157
|
+
@latest_commit_for_pinned_ref ||= T.let(
|
158
|
+
begin
|
159
|
+
head_commit_for_ref_sha = git_commit_checker.head_commit_for_pinned_ref
|
160
|
+
if head_commit_for_ref_sha
|
161
|
+
head_commit_for_ref_sha
|
162
|
+
else
|
163
|
+
url = git_commit_checker.dependency_source_details&.fetch(:url)
|
164
|
+
source = T.must(Source.from_url(url))
|
165
|
+
|
166
|
+
SharedHelpers.in_a_temporary_directory(File.dirname(source.repo)) do |temp_dir|
|
167
|
+
repo_contents_path = File.join(temp_dir, File.basename(source.repo))
|
168
|
+
|
169
|
+
SharedHelpers.run_shell_command("git clone --no-recurse-submodules #{url} #{repo_contents_path}")
|
170
|
+
|
171
|
+
Dir.chdir(repo_contents_path) do
|
172
|
+
ref_branch = find_container_branch(git_commit_checker.dependency_source_details&.fetch(:ref))
|
173
|
+
git_commit_checker.head_commit_for_local_branch(ref_branch) if ref_branch
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end,
|
178
|
+
T.nilable(String)
|
179
|
+
)
|
180
|
+
end
|
181
|
+
|
182
|
+
sig { params(sha: String).returns(T.nilable(String)) }
|
183
|
+
def find_container_branch(sha)
|
184
|
+
branches_including_ref = SharedHelpers.run_shell_command(
|
185
|
+
"git branch --remotes --contains #{sha}",
|
186
|
+
fingerprint: "git branch --remotes --contains <sha>"
|
187
|
+
).split("\n").map { |branch| branch.strip.gsub("origin/", "") }
|
188
|
+
return if branches_including_ref.empty?
|
189
|
+
|
190
|
+
current_branch = branches_including_ref.find { |branch| branch.start_with?("HEAD -> ") }
|
191
|
+
|
192
|
+
if current_branch
|
193
|
+
current_branch.delete_prefix("HEAD -> ")
|
194
|
+
elsif branches_including_ref.size > 1
|
195
|
+
# If there are multiple non default branches including the pinned SHA,
|
196
|
+
# then it's unclear how we should proceed
|
197
|
+
raise "Multiple ambiguous branches (#{branches_including_ref.join(', ')}) include #{sha}!"
|
198
|
+
else
|
199
|
+
branches_including_ref.first
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
sig do
|
204
|
+
params(tags: T::Array[T::Hash[Symbol, T.untyped]]).returns(T.nilable(T::Hash[Symbol, T.untyped]))
|
205
|
+
end
|
206
|
+
def find_lowest_secure_version(tags)
|
207
|
+
relevant_tags = Dependabot::UpdateCheckers::VersionFilters
|
208
|
+
.filter_vulnerable_versions(tags, security_advisories)
|
209
|
+
|
210
|
+
relevant_tags = filter_lower_tags(relevant_tags)
|
211
|
+
relevant_tags.min_by { |tag| tag.fetch(:version) }
|
212
|
+
end
|
213
|
+
|
214
|
+
sig do
|
215
|
+
params(tags_array: T::Array[T::Hash[Symbol, T.untyped]]).returns(T::Array[T::Hash[Symbol, T.untyped]])
|
216
|
+
end
|
217
|
+
def filter_lower_tags(tags_array)
|
218
|
+
return tags_array unless current_version
|
219
|
+
|
220
|
+
tags_array.select { |tag| tag.fetch(:version) > current_version }
|
221
|
+
end
|
222
|
+
|
223
|
+
sig { returns(T::Boolean) }
|
224
|
+
def git_dependency?
|
225
|
+
git_commit_checker.git_dependency?
|
226
|
+
end
|
227
|
+
|
228
|
+
sig { returns(Dependabot::GithubActions::Helpers::Githelper) }
|
229
|
+
def git_helper
|
230
|
+
Helpers::Githelper.new(dependency: dependency, credentials: credentials,
|
231
|
+
ignored_versions: ignored_versions, raise_on_ignored: raise_on_ignored,
|
232
|
+
consider_version_branches_pinned: false, dependency_source_details: nil)
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
@@ -0,0 +1,230 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "excon"
|
5
|
+
require "sorbet-runtime"
|
6
|
+
|
7
|
+
require "dependabot/errors"
|
8
|
+
require "dependabot/github_actions/file_parser"
|
9
|
+
require "dependabot/github_actions/package/package_details_fetcher"
|
10
|
+
require "dependabot/github_actions/requirement"
|
11
|
+
require "dependabot/github_actions/update_checker"
|
12
|
+
require "dependabot/github_actions/helpers"
|
13
|
+
require "dependabot/package/package_latest_version_finder"
|
14
|
+
require "dependabot/shared_helpers"
|
15
|
+
require "dependabot/update_checkers/version_filters"
|
16
|
+
|
17
|
+
module Dependabot
|
18
|
+
module GithubActions
|
19
|
+
class UpdateChecker
|
20
|
+
class LatestVersionFinder < Dependabot::Package::PackageLatestVersionFinder
|
21
|
+
extend T::Sig
|
22
|
+
|
23
|
+
sig do
|
24
|
+
params(
|
25
|
+
dependency: Dependabot::Dependency,
|
26
|
+
dependency_files: T::Array[Dependabot::DependencyFile],
|
27
|
+
credentials: T::Array[Dependabot::Credential],
|
28
|
+
ignored_versions: T::Array[String],
|
29
|
+
security_advisories: T::Array[Dependabot::SecurityAdvisory],
|
30
|
+
raise_on_ignored: T::Boolean,
|
31
|
+
options: T::Hash[Symbol, T.untyped],
|
32
|
+
cooldown_options: T.nilable(Dependabot::Package::ReleaseCooldownOptions)
|
33
|
+
).void
|
34
|
+
end
|
35
|
+
def initialize(
|
36
|
+
dependency:,
|
37
|
+
dependency_files:,
|
38
|
+
credentials:,
|
39
|
+
ignored_versions:,
|
40
|
+
security_advisories:,
|
41
|
+
raise_on_ignored:,
|
42
|
+
options: {},
|
43
|
+
cooldown_options: nil
|
44
|
+
)
|
45
|
+
@dependency = dependency
|
46
|
+
@dependency_files = dependency_files
|
47
|
+
@credentials = credentials
|
48
|
+
@ignored_versions = ignored_versions
|
49
|
+
@security_advisories = security_advisories
|
50
|
+
@raise_on_ignored = raise_on_ignored
|
51
|
+
@options = options
|
52
|
+
@cooldown_options = cooldown_options
|
53
|
+
|
54
|
+
@git_helper = T.let(git_helper, Dependabot::GithubActions::Helpers::Githelper)
|
55
|
+
super
|
56
|
+
end
|
57
|
+
|
58
|
+
sig { returns(Dependabot::Dependency) }
|
59
|
+
attr_reader :dependency
|
60
|
+
sig { returns(T::Array[Dependabot::Credential]) }
|
61
|
+
attr_reader :credentials
|
62
|
+
sig { returns(T.nilable(Dependabot::Package::ReleaseCooldownOptions)) }
|
63
|
+
attr_reader :cooldown_options
|
64
|
+
sig { returns(T::Array[String]) }
|
65
|
+
attr_reader :ignored_versions
|
66
|
+
sig { returns(T::Array[Dependabot::SecurityAdvisory]) }
|
67
|
+
attr_reader :security_advisories
|
68
|
+
sig { returns(T::Boolean) }
|
69
|
+
attr_reader :raise_on_ignored
|
70
|
+
|
71
|
+
sig { override.returns(T.nilable(Dependabot::Package::PackageDetails)) }
|
72
|
+
def package_details; end
|
73
|
+
|
74
|
+
sig { returns(T.nilable(T.any(Dependabot::Version, String))) }
|
75
|
+
def latest_release
|
76
|
+
release = available_release
|
77
|
+
return nil unless release
|
78
|
+
|
79
|
+
Dependabot.logger.info("Available release version/ref is #{release}")
|
80
|
+
|
81
|
+
release = cooldown_filter(release)
|
82
|
+
if release.nil?
|
83
|
+
Dependabot.logger.info("Returning current version/ref (no viable filtered release) #{current_version}")
|
84
|
+
return current_version
|
85
|
+
end
|
86
|
+
|
87
|
+
release
|
88
|
+
end
|
89
|
+
|
90
|
+
sig { returns(T.nilable(T::Hash[Symbol, T.untyped])) }
|
91
|
+
def lowest_security_fix_release
|
92
|
+
available_security_fix_releases
|
93
|
+
end
|
94
|
+
|
95
|
+
sig { returns(T.nilable(T::Hash[Symbol, T.untyped])) }
|
96
|
+
def latest_version_tag
|
97
|
+
available_latest_version_tag
|
98
|
+
end
|
99
|
+
|
100
|
+
private
|
101
|
+
|
102
|
+
sig { returns(T.nilable(Dependabot::GithubActions::Package::PackageDetailsFetcher)) }
|
103
|
+
def package_details_fetcher
|
104
|
+
@package_details_fetcher = T.let(Dependabot::GithubActions::Package::PackageDetailsFetcher
|
105
|
+
.new(
|
106
|
+
dependency: dependency,
|
107
|
+
credentials: credentials,
|
108
|
+
ignored_versions: ignored_versions,
|
109
|
+
raise_on_ignored: raise_on_ignored,
|
110
|
+
security_advisories: security_advisories
|
111
|
+
), T.nilable(Dependabot::GithubActions::Package::PackageDetailsFetcher))
|
112
|
+
end
|
113
|
+
|
114
|
+
sig { returns(T.nilable(T.any(Dependabot::Version, String))) }
|
115
|
+
def available_release
|
116
|
+
@available_release = T.let(T.must(package_details_fetcher).release_list_for_git_dependency,
|
117
|
+
T.nilable(T.any(Dependabot::Version, String)))
|
118
|
+
end
|
119
|
+
|
120
|
+
sig { returns(T.nilable(T::Hash[Symbol, T.untyped])) }
|
121
|
+
def available_security_fix_releases
|
122
|
+
@available_security_fix_releases = T.let(T.must(package_details_fetcher).lowest_security_fix_version_tag,
|
123
|
+
T.nilable(T::Hash[Symbol, T.untyped]))
|
124
|
+
end
|
125
|
+
|
126
|
+
sig { returns(T.nilable(T::Hash[Symbol, T.untyped])) }
|
127
|
+
def available_latest_version_tag
|
128
|
+
@latest_version_tag = T.let(T.must(package_details_fetcher).latest_version_tag,
|
129
|
+
T.nilable(T::Hash[Symbol, T.untyped]))
|
130
|
+
end
|
131
|
+
|
132
|
+
sig { override.returns(T::Boolean) }
|
133
|
+
def cooldown_enabled?
|
134
|
+
Dependabot::Experiments.enabled?(:enable_cooldown_for_github_actions)
|
135
|
+
end
|
136
|
+
|
137
|
+
sig do
|
138
|
+
params(release: T.nilable(T.any(Dependabot::Version, String)))
|
139
|
+
.returns(T.nilable(T.any(Dependabot::Version, String)))
|
140
|
+
end
|
141
|
+
def cooldown_filter(release)
|
142
|
+
return release unless cooldown_enabled?
|
143
|
+
return release unless cooldown_options
|
144
|
+
|
145
|
+
Dependabot.logger.info("Initializing cooldown filter")
|
146
|
+
release_date = commit_metadata_details
|
147
|
+
|
148
|
+
unless release_date
|
149
|
+
Dependabot.logger.info("No release date found, skipping cooldown filtering")
|
150
|
+
return release
|
151
|
+
end
|
152
|
+
|
153
|
+
if release_in_cooldown_period?(Time.parse(release_date))
|
154
|
+
Dependabot.logger.info("Filtered out (cooldown) #{dependency.name}, #{release}")
|
155
|
+
return nil
|
156
|
+
end
|
157
|
+
|
158
|
+
release
|
159
|
+
end
|
160
|
+
|
161
|
+
sig { returns(T.nilable(String)) }
|
162
|
+
def commit_metadata_details
|
163
|
+
@commit_metadata_details ||= T.let(
|
164
|
+
begin
|
165
|
+
url = @git_helper.git_commit_checker.dependency_source_details&.fetch(:url)
|
166
|
+
source = T.must(Source.from_url(url))
|
167
|
+
|
168
|
+
SharedHelpers.in_a_temporary_directory(File.dirname(source.repo)) do |temp_dir|
|
169
|
+
repo_contents_path = File.join(temp_dir, File.basename(source.repo))
|
170
|
+
|
171
|
+
SharedHelpers.run_shell_command("git clone --bare --no-recurse-submodules #{url} #{repo_contents_path}")
|
172
|
+
Dir.chdir(repo_contents_path) do
|
173
|
+
date = SharedHelpers.run_shell_command("git show --no-patch --format=\"%cd\" " \
|
174
|
+
"--date=iso #{commit_ref}")
|
175
|
+
Dependabot.logger.info("Found release date : #{Time.parse(date)}")
|
176
|
+
return date
|
177
|
+
end
|
178
|
+
end
|
179
|
+
rescue StandardError => e
|
180
|
+
Dependabot.logger.error("Error (github actions) while checking release date for #{dependency.name}")
|
181
|
+
Dependabot.logger.error(e.message)
|
182
|
+
|
183
|
+
nil
|
184
|
+
end,
|
185
|
+
T.nilable(String)
|
186
|
+
)
|
187
|
+
end
|
188
|
+
|
189
|
+
sig { params(release_date: Time).returns(T::Boolean) }
|
190
|
+
def release_in_cooldown_period?(release_date)
|
191
|
+
cooldown = @cooldown_options
|
192
|
+
|
193
|
+
return false unless T.must(cooldown).included?(dependency.name)
|
194
|
+
|
195
|
+
days = T.must(cooldown).default_days
|
196
|
+
passed_seconds = Time.now.to_i - release_date.to_i
|
197
|
+
|
198
|
+
Dependabot.logger.info("Days since release : #{passed_seconds / (3600 * 24)} " \
|
199
|
+
"(cooldown days #{T.must(cooldown_options).default_days})")
|
200
|
+
|
201
|
+
passed_seconds < days * DAY_IN_SECONDS
|
202
|
+
end
|
203
|
+
|
204
|
+
sig { returns(String) }
|
205
|
+
def commit_ref
|
206
|
+
latest_version_tag&.fetch(:commit_sha)
|
207
|
+
end
|
208
|
+
|
209
|
+
sig { returns(T.nilable(T.any(Dependabot::Version, String))) }
|
210
|
+
def current_version
|
211
|
+
return dependency.source_details(allowed_types: ["git"])&.fetch(:ref) if release_type_sha?
|
212
|
+
|
213
|
+
T.let(dependency.numeric_version, T.nilable(Dependabot::Version))
|
214
|
+
end
|
215
|
+
|
216
|
+
sig { returns(T::Boolean) }
|
217
|
+
def release_type_sha?
|
218
|
+
available_release.is_a?(String)
|
219
|
+
end
|
220
|
+
|
221
|
+
sig { returns(Dependabot::GithubActions::Helpers::Githelper) }
|
222
|
+
def git_helper
|
223
|
+
Helpers::Githelper.new(dependency: dependency, credentials: credentials,
|
224
|
+
ignored_versions: ignored_versions, raise_on_ignored: raise_on_ignored,
|
225
|
+
consider_version_branches_pinned: false, dependency_source_details: nil)
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
@@ -16,10 +16,12 @@ module Dependabot
|
|
16
16
|
class UpdateChecker < Dependabot::UpdateCheckers::Base
|
17
17
|
extend T::Sig
|
18
18
|
|
19
|
+
require_relative "update_checker/latest_version_finder"
|
20
|
+
|
19
21
|
sig { override.returns(T.nilable(T.any(String, Gem::Version))) }
|
20
22
|
def latest_version
|
21
23
|
@latest_version ||= T.let(
|
22
|
-
|
24
|
+
T.must(latest_version_finder).latest_release,
|
23
25
|
T.nilable(T.any(String, Gem::Version))
|
24
26
|
)
|
25
27
|
end
|
@@ -36,20 +38,20 @@ module Dependabot
|
|
36
38
|
dependency.version
|
37
39
|
end
|
38
40
|
|
41
|
+
sig { override.returns(T.nilable(Dependabot::Version)) }
|
42
|
+
def lowest_resolvable_security_fix_version
|
43
|
+
# Resolvability isn't an issue for GitHub Actions.
|
44
|
+
lowest_security_fix_version
|
45
|
+
end
|
46
|
+
|
39
47
|
sig { override.returns(T.nilable(Dependabot::Version)) }
|
40
48
|
def lowest_security_fix_version
|
41
49
|
@lowest_security_fix_version ||= T.let(
|
42
|
-
|
50
|
+
T.must(latest_version_finder).lowest_security_fix_release&.fetch(:version),
|
43
51
|
T.nilable(Dependabot::Version)
|
44
52
|
)
|
45
53
|
end
|
46
54
|
|
47
|
-
sig { override.returns(T.nilable(Dependabot::Version)) }
|
48
|
-
def lowest_resolvable_security_fix_version
|
49
|
-
# Resolvability isn't an issue for GitHub Actions.
|
50
|
-
lowest_security_fix_version
|
51
|
-
end
|
52
|
-
|
53
55
|
sig { override.returns(T::Array[T::Hash[Symbol, T.untyped]]) }
|
54
56
|
def updated_requirements
|
55
57
|
dependency.requirements.map do |req|
|
@@ -74,6 +76,21 @@ module Dependabot
|
|
74
76
|
|
75
77
|
private
|
76
78
|
|
79
|
+
sig { returns(T.nilable(Dependabot::GithubActions::UpdateChecker::LatestVersionFinder)) }
|
80
|
+
def latest_version_finder
|
81
|
+
@latest_version_finder ||=
|
82
|
+
T.let(LatestVersionFinder.new(
|
83
|
+
dependency: dependency,
|
84
|
+
credentials: credentials,
|
85
|
+
dependency_files: dependency_files,
|
86
|
+
security_advisories: security_advisories,
|
87
|
+
ignored_versions: ignored_versions,
|
88
|
+
raise_on_ignored: raise_on_ignored,
|
89
|
+
cooldown_options: update_cooldown
|
90
|
+
),
|
91
|
+
T.nilable(Dependabot::GithubActions::UpdateChecker::LatestVersionFinder))
|
92
|
+
end
|
93
|
+
|
77
94
|
sig { returns(T::Array[Dependabot::SecurityAdvisory]) }
|
78
95
|
def active_advisories
|
79
96
|
security_advisories.select do |advisory|
|
@@ -93,82 +110,6 @@ module Dependabot
|
|
93
110
|
raise NotImplementedError
|
94
111
|
end
|
95
112
|
|
96
|
-
sig { returns(T.nilable(T.any(Dependabot::Version, String))) }
|
97
|
-
def fetch_latest_version
|
98
|
-
# TODO: Support Docker sources
|
99
|
-
return unless git_dependency?
|
100
|
-
|
101
|
-
fetch_latest_version_for_git_dependency
|
102
|
-
end
|
103
|
-
|
104
|
-
sig { returns(T.nilable(T.any(Dependabot::Version, String))) }
|
105
|
-
def fetch_latest_version_for_git_dependency
|
106
|
-
return current_commit unless git_commit_checker.pinned?
|
107
|
-
|
108
|
-
# If the dependency is pinned to a tag that looks like a version then
|
109
|
-
# we want to update that tag.
|
110
|
-
if git_commit_checker.pinned_ref_looks_like_version? && latest_version_tag
|
111
|
-
latest_version = latest_version_tag&.fetch(:version)
|
112
|
-
return current_version if shortened_semver_eq?(dependency.version, latest_version.to_s)
|
113
|
-
|
114
|
-
return latest_version
|
115
|
-
end
|
116
|
-
|
117
|
-
if git_commit_checker.pinned_ref_looks_like_commit_sha? && latest_version_tag
|
118
|
-
latest_version = latest_version_tag&.fetch(:version)
|
119
|
-
return latest_commit_for_pinned_ref unless git_commit_checker.local_tag_for_pinned_sha
|
120
|
-
|
121
|
-
return latest_version
|
122
|
-
end
|
123
|
-
|
124
|
-
# If the dependency is pinned to a tag that doesn't look like a
|
125
|
-
# version or a commit SHA then there's nothing we can do.
|
126
|
-
nil
|
127
|
-
end
|
128
|
-
|
129
|
-
sig { returns(T.nilable(Dependabot::Version)) }
|
130
|
-
def fetch_lowest_security_fix_version
|
131
|
-
# TODO: Support Docker sources
|
132
|
-
return unless git_dependency?
|
133
|
-
|
134
|
-
fetch_lowest_security_fix_version_for_git_dependency
|
135
|
-
end
|
136
|
-
|
137
|
-
sig { returns(T.nilable(Dependabot::Version)) }
|
138
|
-
def fetch_lowest_security_fix_version_for_git_dependency
|
139
|
-
lowest_security_fix_version_tag&.fetch(:version)
|
140
|
-
end
|
141
|
-
|
142
|
-
sig { returns(T.nilable(T::Hash[Symbol, T.untyped])) }
|
143
|
-
def lowest_security_fix_version_tag
|
144
|
-
@lowest_security_fix_version_tag ||= T.let(
|
145
|
-
begin
|
146
|
-
tags_matching_precision = git_commit_checker.local_tags_for_allowed_versions_matching_existing_precision
|
147
|
-
lowest_fixed_version = find_lowest_secure_version(tags_matching_precision)
|
148
|
-
if lowest_fixed_version
|
149
|
-
lowest_fixed_version
|
150
|
-
else
|
151
|
-
tags = git_commit_checker.local_tags_for_allowed_versions
|
152
|
-
find_lowest_secure_version(tags)
|
153
|
-
end
|
154
|
-
end,
|
155
|
-
T.nilable(T::Hash[Symbol, String])
|
156
|
-
)
|
157
|
-
end
|
158
|
-
|
159
|
-
sig do
|
160
|
-
params(
|
161
|
-
tags: T::Array[T::Hash[Symbol, T.untyped]]
|
162
|
-
)
|
163
|
-
.returns(T.nilable(T::Hash[Symbol, T.untyped]))
|
164
|
-
end
|
165
|
-
def find_lowest_secure_version(tags)
|
166
|
-
relevant_tags = Dependabot::UpdateCheckers::VersionFilters.filter_vulnerable_versions(tags, security_advisories)
|
167
|
-
relevant_tags = filter_lower_tags(relevant_tags)
|
168
|
-
|
169
|
-
relevant_tags.min_by { |tag| tag.fetch(:version) }
|
170
|
-
end
|
171
|
-
|
172
113
|
sig { returns(T.nilable(String)) }
|
173
114
|
def latest_commit_for_pinned_ref
|
174
115
|
@latest_commit_for_pinned_ref ||= T.let(
|
@@ -196,49 +137,20 @@ module Dependabot
|
|
196
137
|
)
|
197
138
|
end
|
198
139
|
|
199
|
-
sig { returns(T.nilable(T::Hash[Symbol, T.untyped])) }
|
200
|
-
def latest_version_tag
|
201
|
-
@latest_version_tag ||= T.let(
|
202
|
-
begin
|
203
|
-
return git_commit_checker.local_tag_for_latest_version if dependency.version.nil?
|
204
|
-
|
205
|
-
ref = git_commit_checker.local_ref_for_latest_version_matching_existing_precision
|
206
|
-
return ref if ref && ref.fetch(:version) > current_version
|
207
|
-
|
208
|
-
git_commit_checker.local_ref_for_latest_version_lower_precision
|
209
|
-
end,
|
210
|
-
T.nilable(T::Hash[Symbol, T.untyped])
|
211
|
-
)
|
212
|
-
end
|
213
|
-
|
214
|
-
sig do
|
215
|
-
params(
|
216
|
-
tags_array: T::Array[T::Hash[Symbol, T.untyped]]
|
217
|
-
)
|
218
|
-
.returns(T::Array[T::Hash[Symbol, T.untyped]])
|
219
|
-
end
|
220
|
-
def filter_lower_tags(tags_array)
|
221
|
-
return tags_array unless current_version
|
222
|
-
|
223
|
-
tags_array
|
224
|
-
.select { |tag| tag.fetch(:version) > current_version }
|
225
|
-
end
|
226
|
-
|
227
140
|
sig { params(source: T.nilable(T::Hash[Symbol, String])).returns(T.nilable(String)) }
|
228
141
|
def updated_ref(source)
|
229
142
|
# TODO: Support Docker sources
|
230
|
-
return unless git_dependency?
|
143
|
+
return unless git_commit_checker.git_dependency?
|
231
144
|
|
232
|
-
if vulnerable? &&
|
233
|
-
(new_tag = lowest_security_fix_version_tag)
|
145
|
+
if vulnerable? && (new_tag = T.must(latest_version_finder).lowest_security_fix_release)
|
234
146
|
return new_tag.fetch(:tag)
|
235
147
|
end
|
236
148
|
|
237
|
-
source_git_commit_checker = git_commit_checker_for(source)
|
149
|
+
source_git_commit_checker = git_helper.git_commit_checker_for(source)
|
238
150
|
|
239
151
|
# Return the git tag if updating a pinned version
|
240
152
|
if source_git_commit_checker.pinned_ref_looks_like_version? &&
|
241
|
-
(new_tag = latest_version_tag)
|
153
|
+
(new_tag = T.must(latest_version_finder).latest_version_tag)
|
242
154
|
return new_tag.fetch(:tag)
|
243
155
|
end
|
244
156
|
|
@@ -254,7 +166,7 @@ module Dependabot
|
|
254
166
|
|
255
167
|
sig { returns(T.nilable(String)) }
|
256
168
|
def latest_commit_sha
|
257
|
-
new_tag = latest_version_tag
|
169
|
+
new_tag = T.must(latest_version_finder).latest_version_tag
|
258
170
|
return unless new_tag
|
259
171
|
|
260
172
|
if git_commit_checker.local_tag_for_pinned_sha
|
@@ -264,50 +176,16 @@ module Dependabot
|
|
264
176
|
end
|
265
177
|
end
|
266
178
|
|
267
|
-
sig { returns(T.nilable(String)) }
|
268
|
-
def current_commit
|
269
|
-
git_commit_checker.head_commit_for_current_branch
|
270
|
-
end
|
271
|
-
|
272
|
-
sig { returns(T::Boolean) }
|
273
|
-
def git_dependency?
|
274
|
-
git_commit_checker.git_dependency?
|
275
|
-
end
|
276
|
-
|
277
179
|
sig { returns(Dependabot::GitCommitChecker) }
|
278
180
|
def git_commit_checker
|
279
|
-
@git_commit_checker ||= T.let(
|
280
|
-
git_commit_checker_for(nil),
|
281
|
-
T.nilable(Dependabot::GitCommitChecker)
|
282
|
-
)
|
181
|
+
@git_commit_checker ||= T.let(git_helper.git_commit_checker, T.nilable(Dependabot::GitCommitChecker))
|
283
182
|
end
|
284
183
|
|
285
|
-
sig {
|
286
|
-
def
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
)
|
291
|
-
|
292
|
-
@git_commit_checkers[source] ||= Dependabot::GitCommitChecker.new(
|
293
|
-
dependency: dependency,
|
294
|
-
credentials: credentials,
|
295
|
-
ignored_versions: ignored_versions,
|
296
|
-
raise_on_ignored: raise_on_ignored,
|
297
|
-
consider_version_branches_pinned: true,
|
298
|
-
dependency_source_details: source
|
299
|
-
)
|
300
|
-
end
|
301
|
-
|
302
|
-
sig { params(base: T.nilable(String), other: String).returns(T::Boolean) }
|
303
|
-
def shortened_semver_eq?(base, other)
|
304
|
-
return false unless base
|
305
|
-
|
306
|
-
base_split = base.split(".")
|
307
|
-
other_split = other.split(".")
|
308
|
-
return false unless base_split.length <= other_split.length
|
309
|
-
|
310
|
-
other_split[0..base_split.length - 1] == base_split
|
184
|
+
sig { returns(Dependabot::GithubActions::Helpers::Githelper) }
|
185
|
+
def git_helper
|
186
|
+
Helpers::Githelper.new(dependency: dependency, credentials: credentials,
|
187
|
+
ignored_versions: ignored_versions, raise_on_ignored: raise_on_ignored,
|
188
|
+
consider_version_branches_pinned: false, dependency_source_details: nil)
|
311
189
|
end
|
312
190
|
|
313
191
|
sig { params(sha: String).returns(T.nilable(String)) }
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dependabot-github_actions
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.319.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.319.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.319.0
|
26
26
|
- !ruby/object:Gem::Dependency
|
27
27
|
name: debug
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
@@ -246,17 +246,20 @@ files:
|
|
246
246
|
- lib/dependabot/github_actions/file_fetcher.rb
|
247
247
|
- lib/dependabot/github_actions/file_parser.rb
|
248
248
|
- lib/dependabot/github_actions/file_updater.rb
|
249
|
+
- lib/dependabot/github_actions/helpers.rb
|
249
250
|
- lib/dependabot/github_actions/metadata_finder.rb
|
251
|
+
- lib/dependabot/github_actions/package/package_details_fetcher.rb
|
250
252
|
- lib/dependabot/github_actions/package_manager.rb
|
251
253
|
- lib/dependabot/github_actions/requirement.rb
|
252
254
|
- lib/dependabot/github_actions/update_checker.rb
|
255
|
+
- lib/dependabot/github_actions/update_checker/latest_version_finder.rb
|
253
256
|
- lib/dependabot/github_actions/version.rb
|
254
257
|
homepage: https://github.com/dependabot/dependabot-core
|
255
258
|
licenses:
|
256
259
|
- MIT
|
257
260
|
metadata:
|
258
261
|
bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
|
259
|
-
changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.
|
262
|
+
changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.319.0
|
260
263
|
rdoc_options: []
|
261
264
|
require_paths:
|
262
265
|
- lib
|