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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 250d36ac87750395de567aee349134a7ad7f6ff59700623fb98aaa57585b42db
4
- data.tar.gz: ad35f5f8dba65555fb3597c82a7b508a8ae97f65f54dcad95eaa195c68f1151f
3
+ metadata.gz: fc4883bf917e6eb180ff085886dff4548085a8b49cb364c6c0e670a04e722283
4
+ data.tar.gz: 723663decd469822de084aeee604bdef7aa6b3cf0e0f86f4fb38a80c52753363
5
5
  SHA512:
6
- metadata.gz: b1af3ca6d04cb15f3a11e10993336fa4a837e076ff78a83e2b9c22c4332920835bbb6fb33177946174419dd7fa8565138287cf12bdf9e0acb95495ca06b5ab85
7
- data.tar.gz: 5e9e44ca3c060558381bd68d32b78fef896741b8365171c9172dcf8dc9a0031585dadf4ac0845a1184422b75f1958d402a5583d0896d26664d1d841ee9393003
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
- fetch_latest_version,
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
- fetch_lowest_security_fix_version,
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 { params(source: T.nilable(T::Hash[Symbol, String])).returns(Dependabot::GitCommitChecker) }
286
- def git_commit_checker_for(source)
287
- @git_commit_checkers ||= T.let(
288
- {},
289
- T.nilable(T::Hash[T.nilable(T::Hash[Symbol, String]), Dependabot::GitCommitChecker])
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.318.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.318.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.318.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.318.0
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