dependabot-common 0.236.0 → 0.237.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.
@@ -1,7 +1,8 @@
1
- # typed: false
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "stringio"
5
+ require "sorbet-runtime"
5
6
  require "dependabot/config"
6
7
  require "dependabot/dependency_file"
7
8
  require "dependabot/source"
@@ -17,15 +18,33 @@ require "dependabot/shared_helpers"
17
18
  module Dependabot
18
19
  module FileFetchers
19
20
  class Base
20
- attr_reader :source, :credentials, :repo_contents_path, :options
21
+ extend T::Sig
22
+ extend T::Helpers
21
23
 
22
- CLIENT_NOT_FOUND_ERRORS = [
23
- Octokit::NotFound,
24
- Gitlab::Error::NotFound,
25
- Dependabot::Clients::Azure::NotFound,
26
- Dependabot::Clients::Bitbucket::NotFound,
27
- Dependabot::Clients::CodeCommit::NotFound
28
- ].freeze
24
+ abstract!
25
+
26
+ sig { returns(Dependabot::Source) }
27
+ attr_reader :source
28
+
29
+ sig { returns(T::Array[T::Hash[String, String]]) }
30
+ attr_reader :credentials
31
+
32
+ sig { returns(T.nilable(String)) }
33
+ attr_reader :repo_contents_path
34
+
35
+ sig { returns(T::Hash[String, String]) }
36
+ attr_reader :options
37
+
38
+ CLIENT_NOT_FOUND_ERRORS = T.let(
39
+ [
40
+ Octokit::NotFound,
41
+ Gitlab::Error::NotFound,
42
+ Dependabot::Clients::Azure::NotFound,
43
+ Dependabot::Clients::Bitbucket::NotFound,
44
+ Dependabot::Clients::CodeCommit::NotFound
45
+ ].freeze,
46
+ T::Array[T.class_of(StandardError)]
47
+ )
29
48
 
30
49
  GIT_SUBMODULE_INACCESSIBLE_ERROR =
31
50
  /^fatal: unable to access '(?<url>.*)': The requested URL returned error: (?<code>\d+)$/
@@ -33,13 +52,11 @@ module Dependabot
33
52
  /^fatal: clone of '(?<url>.*)' into submodule path '.*' failed$/
34
53
  GIT_SUBMODULE_ERROR_REGEX = /(#{GIT_SUBMODULE_INACCESSIBLE_ERROR})|(#{GIT_SUBMODULE_CLONE_ERROR})/
35
54
 
36
- def self.required_files_in?(_filename_array)
37
- raise NotImplementedError
38
- end
55
+ sig { abstract.params(filenames: T::Array[String]).returns(T::Boolean) }
56
+ def self.required_files_in?(filenames); end
39
57
 
40
- def self.required_files_message
41
- raise NotImplementedError
42
- end
58
+ sig { abstract.returns(String) }
59
+ def self.required_files_message; end
43
60
 
44
61
  # Creates a new FileFetcher for retrieving `DependencyFile`s.
45
62
  #
@@ -52,38 +69,58 @@ module Dependabot
52
69
  # by repo_contents_path and still use an API trip.
53
70
  #
54
71
  # options supports custom feature enablement
72
+ sig do
73
+ params(
74
+ source: Dependabot::Source,
75
+ credentials: T::Array[T::Hash[String, String]],
76
+ repo_contents_path: T.nilable(String),
77
+ options: T::Hash[String, String]
78
+ )
79
+ .void
80
+ end
55
81
  def initialize(source:, credentials:, repo_contents_path: nil, options: {})
56
82
  @source = source
57
83
  @credentials = credentials
58
84
  @repo_contents_path = repo_contents_path
59
- @linked_paths = {}
60
- @submodules = []
85
+ @linked_paths = T.let({}, T::Hash[T.untyped, T.untyped])
86
+ @submodules = T.let([], T::Array[T.untyped])
61
87
  @options = options
62
88
  end
63
89
 
90
+ sig { returns(String) }
64
91
  def repo
65
92
  source.repo
66
93
  end
67
94
 
95
+ sig { returns(String) }
68
96
  def directory
69
97
  Pathname.new(source.directory || "/").cleanpath.to_path
70
98
  end
71
99
 
100
+ sig { returns(T.nilable(String)) }
72
101
  def target_branch
73
102
  source.branch
74
103
  end
75
104
 
105
+ sig { returns(T::Array[DependencyFile]) }
76
106
  def files
77
- @files ||= fetch_files
107
+ @files ||= T.let(
108
+ fetch_files.each { |f| f.job_directory = directory },
109
+ T.nilable(T::Array[DependencyFile])
110
+ )
78
111
  end
79
112
 
113
+ sig { abstract.returns(T::Array[DependencyFile]) }
114
+ def fetch_files; end
115
+
116
+ sig { returns(T.nilable(String)) }
80
117
  def commit
81
- return cloned_commit if cloned_commit
82
- return source.commit if source.commit
118
+ return T.must(cloned_commit) if cloned_commit
119
+ return T.must(source.commit) if source.commit
83
120
 
84
121
  branch = target_branch || default_branch_for_repo
85
122
 
86
- @commit ||= client_for_provider.fetch_commit(repo, branch)
123
+ @commit ||= T.let(T.unsafe(client_for_provider).fetch_commit(repo, branch), T.nilable(String))
87
124
  rescue *CLIENT_NOT_FOUND_ERRORS
88
125
  raise Dependabot::BranchNotFound, branch
89
126
  rescue Octokit::Conflict => e
@@ -91,9 +128,12 @@ module Dependabot
91
128
  end
92
129
 
93
130
  # Returns the path to the cloned repo
131
+ sig { returns(String) }
94
132
  def clone_repo_contents
95
- @clone_repo_contents ||=
96
- _clone_repo_contents(target_directory: repo_contents_path)
133
+ @clone_repo_contents ||= T.let(
134
+ _clone_repo_contents(target_directory: repo_contents_path),
135
+ T.nilable(String)
136
+ )
97
137
  rescue Dependabot::SharedHelpers::HelperSubprocessFailed => e
98
138
  if e.message.include?("fatal: Remote branch #{target_branch} not found in upstream origin")
99
139
  raise Dependabot::BranchNotFound, target_branch
@@ -104,16 +144,17 @@ module Dependabot
104
144
  raise Dependabot::RepoNotFound.new(source, e.message)
105
145
  end
106
146
 
107
- def ecosystem_versions
108
- nil
109
- end
147
+ sig { overridable.returns(T.nilable(T::Hash[Symbol, T.untyped])) }
148
+ def ecosystem_versions; end
110
149
 
111
150
  private
112
151
 
152
+ sig { params(name: String).returns(T.nilable(Dependabot::DependencyFile)) }
113
153
  def fetch_support_file(name)
114
154
  fetch_file_if_present(name)&.tap { |f| f.support_file = true }
115
155
  end
116
156
 
157
+ sig { params(filename: String, fetch_submodules: T::Boolean).returns(T.nilable(DependencyFile)) }
117
158
  def fetch_file_if_present(filename, fetch_submodules: false)
118
159
  unless repo_contents_path.nil?
119
160
  begin
@@ -137,6 +178,7 @@ module Dependabot
137
178
  nil
138
179
  end
139
180
 
181
+ sig { params(filename: T.any(Pathname, String)).returns(Dependabot::DependencyFile) }
140
182
  def load_cloned_file_if_present(filename)
141
183
  path = Pathname.new(File.join(directory, filename)).cleanpath.to_path
142
184
  repo_path = File.join(clone_repo_contents, path)
@@ -160,6 +202,14 @@ module Dependabot
160
202
  )
161
203
  end
162
204
 
205
+ sig do
206
+ params(
207
+ filename: T.any(Pathname, String),
208
+ type: String,
209
+ fetch_submodules: T::Boolean
210
+ )
211
+ .returns(Dependabot::DependencyFile)
212
+ end
163
213
  def fetch_file_from_host(filename, type: "file", fetch_submodules: false)
164
214
  return load_cloned_file_if_present(filename) unless repo_contents_path.nil?
165
215
 
@@ -169,7 +219,7 @@ module Dependabot
169
219
 
170
220
  linked_path = symlinked_subpath(clean_path)
171
221
  type = "symlink" if linked_path
172
- symlink_target = clean_path.sub(linked_path, @linked_paths.dig(linked_path, :path)) if type == "symlink"
222
+ symlink_target = clean_path.sub(T.must(linked_path), @linked_paths.dig(linked_path, :path)) if type == "symlink"
173
223
 
174
224
  DependencyFile.new(
175
225
  name: Pathname.new(filename).cleanpath.to_path,
@@ -183,65 +233,87 @@ module Dependabot
183
233
  end
184
234
 
185
235
  # Finds the first subpath in path that is a symlink
236
+ sig { params(path: String).returns(T.nilable(String)) }
186
237
  def symlinked_subpath(path)
187
238
  subpaths(path).find { |subpath| @linked_paths.key?(subpath) }
188
239
  end
189
240
 
241
+ sig { params(path: String).returns(T::Boolean) }
190
242
  def in_submodule?(path)
191
243
  subpaths(path.delete_prefix("/")).any? { |subpath| @submodules.include?(subpath) }
192
244
  end
193
245
 
194
246
  # Given a "foo/bar/baz" path, returns ["foo", "foo/bar", "foo/bar/baz"]
247
+ sig { params(path: String).returns(T::Array[String]) }
195
248
  def subpaths(path)
196
249
  components = path.split("/")
197
- components.map { |component| components[0..components.index(component)].join("/") }
250
+ components.map { |component| T.must(components[0..components.index(component)]).join("/") }
198
251
  end
199
252
 
253
+ sig do
254
+ params(
255
+ dir: T.any(Pathname, String),
256
+ ignore_base_directory: T::Boolean,
257
+ raise_errors: T::Boolean,
258
+ fetch_submodules: T::Boolean
259
+ )
260
+ .returns(T::Array[T.untyped])
261
+ end
200
262
  def repo_contents(dir: ".", ignore_base_directory: false,
201
263
  raise_errors: true, fetch_submodules: false)
202
264
  dir = File.join(directory, dir) unless ignore_base_directory
203
265
  path = Pathname.new(dir).cleanpath.to_path.gsub(%r{^/*}, "")
204
266
 
205
- @repo_contents ||= {}
206
- @repo_contents[dir] ||= if repo_contents_path
207
- _cloned_repo_contents(path)
208
- else
209
- _fetch_repo_contents(path, raise_errors: raise_errors,
210
- fetch_submodules: fetch_submodules)
211
- end
267
+ @repo_contents ||= T.let({}, T.nilable(T::Hash[String, T::Array[T.untyped]]))
268
+ @repo_contents[dir.to_s] ||= if repo_contents_path
269
+ _cloned_repo_contents(path)
270
+ else
271
+ _fetch_repo_contents(path, raise_errors: raise_errors,
272
+ fetch_submodules: fetch_submodules)
273
+ end
212
274
  end
213
275
 
276
+ sig { returns(T.nilable(String)) }
214
277
  def cloned_commit
215
278
  return if repo_contents_path.nil? || !File.directory?(File.join(repo_contents_path, ".git"))
216
279
 
217
280
  SharedHelpers.with_git_configured(credentials: credentials) do
218
- Dir.chdir(repo_contents_path) do
219
- return SharedHelpers.run_shell_command("git rev-parse HEAD")&.strip
281
+ Dir.chdir(T.must(repo_contents_path)) do
282
+ return SharedHelpers.run_shell_command("git rev-parse HEAD").strip
220
283
  end
221
284
  end
222
285
  end
223
286
 
287
+ sig { returns(String) }
224
288
  def default_branch_for_repo
225
- @default_branch_for_repo ||= client_for_provider
226
- .fetch_default_branch(repo)
289
+ @default_branch_for_repo ||= T.let(T.unsafe(client_for_provider).fetch_default_branch(repo), T.nilable(String))
227
290
  rescue *CLIENT_NOT_FOUND_ERRORS
228
291
  raise Dependabot::RepoNotFound, source
229
292
  end
230
293
 
294
+ sig do
295
+ params(
296
+ repo: String,
297
+ path: String,
298
+ commit: String,
299
+ github_response: Sawyer::Resource
300
+ )
301
+ .returns(T.nilable(T::Hash[String, T.untyped]))
302
+ end
231
303
  def update_linked_paths(repo, path, commit, github_response)
232
- case github_response.type
304
+ case T.unsafe(github_response).type
233
305
  when "submodule"
234
- sub_source = Source.from_url(github_response.submodule_git_url)
306
+ sub_source = Source.from_url(T.unsafe(github_response).submodule_git_url)
235
307
  return unless sub_source
236
308
 
237
309
  @linked_paths[path] = {
238
310
  repo: sub_source.repo,
239
311
  provider: sub_source.provider,
240
- commit: github_response.sha,
312
+ commit: T.unsafe(github_response).sha,
241
313
  path: "/"
242
314
  }
243
315
  when "symlink"
244
- updated_path = File.join(File.dirname(path), github_response.target)
316
+ updated_path = File.join(File.dirname(path), T.unsafe(github_response).target)
245
317
  @linked_paths[path] = {
246
318
  repo: repo,
247
319
  provider: "github",
@@ -251,10 +323,22 @@ module Dependabot
251
323
  end
252
324
  end
253
325
 
326
+ sig { returns(T::Boolean) }
254
327
  def recurse_submodules_when_cloning?
255
328
  false
256
329
  end
257
330
 
331
+ sig do
332
+ returns(
333
+ T.any(
334
+ Dependabot::Clients::GithubWithRetries,
335
+ Dependabot::Clients::GitlabWithRetries,
336
+ Dependabot::Clients::Azure,
337
+ Dependabot::Clients::BitbucketWithRetries,
338
+ Dependabot::Clients::CodeCommit
339
+ )
340
+ )
341
+ end
258
342
  def client_for_provider
259
343
  case source.provider
260
344
  when "github" then github_client
@@ -266,46 +350,75 @@ module Dependabot
266
350
  end
267
351
  end
268
352
 
353
+ sig { returns(Dependabot::Clients::GithubWithRetries) }
269
354
  def github_client
270
355
  @github_client ||=
271
- Dependabot::Clients::GithubWithRetries.for_source(
272
- source: source,
273
- credentials: credentials
356
+ T.let(
357
+ Dependabot::Clients::GithubWithRetries.for_source(
358
+ source: source,
359
+ credentials: credentials
360
+ ),
361
+ T.nilable(Dependabot::Clients::GithubWithRetries)
274
362
  )
275
363
  end
276
364
 
365
+ sig { returns(Dependabot::Clients::GitlabWithRetries) }
277
366
  def gitlab_client
278
367
  @gitlab_client ||=
279
- Dependabot::Clients::GitlabWithRetries.for_source(
280
- source: source,
281
- credentials: credentials
368
+ T.let(
369
+ Dependabot::Clients::GitlabWithRetries.for_source(
370
+ source: source,
371
+ credentials: credentials
372
+ ),
373
+ T.nilable(Dependabot::Clients::GitlabWithRetries)
282
374
  )
283
375
  end
284
376
 
377
+ sig { returns(Dependabot::Clients::Azure) }
285
378
  def azure_client
286
379
  @azure_client ||=
287
- Dependabot::Clients::Azure
288
- .for_source(source: source, credentials: credentials)
380
+ T.let(
381
+ Dependabot::Clients::Azure.for_source(
382
+ source: source,
383
+ credentials: credentials
384
+ ),
385
+ T.nilable(Dependabot::Clients::Azure)
386
+ )
289
387
  end
290
388
 
389
+ sig { returns(Dependabot::Clients::BitbucketWithRetries) }
291
390
  def bitbucket_client
292
391
  # TODO: When self-hosted Bitbucket is supported this should use
293
392
  # `Bitbucket.for_source`
294
393
  @bitbucket_client ||=
295
- Dependabot::Clients::BitbucketWithRetries
296
- .for_bitbucket_dot_org(credentials: credentials)
394
+ T.let(
395
+ Dependabot::Clients::BitbucketWithRetries.for_bitbucket_dot_org(
396
+ credentials: credentials
397
+ ),
398
+ T.nilable(Dependabot::Clients::BitbucketWithRetries)
399
+ )
297
400
  end
298
401
 
402
+ sig { returns(Dependabot::Clients::CodeCommit) }
299
403
  def codecommit_client
300
404
  @codecommit_client ||=
301
- Dependabot::Clients::CodeCommit
302
- .for_source(source: source, credentials: credentials)
405
+ T.let(
406
+ Dependabot::Clients::CodeCommit.for_source(
407
+ source: source,
408
+ credentials: credentials
409
+ ),
410
+ T.nilable(Dependabot::Clients::CodeCommit)
411
+ )
303
412
  end
304
413
 
305
414
  #################################################
306
415
  # INTERNAL METHODS (not for use by sub-classes) #
307
416
  #################################################
308
417
 
418
+ sig do
419
+ params(path: String, fetch_submodules: T::Boolean, raise_errors: T::Boolean)
420
+ .returns(T::Array[OpenStruct])
421
+ end
309
422
  def _fetch_repo_contents(path, fetch_submodules: false,
310
423
  raise_errors: true)
311
424
  path = path.gsub(" ", "%20")
@@ -337,6 +450,10 @@ module Dependabot
337
450
  retry
338
451
  end
339
452
 
453
+ sig do
454
+ params(provider: String, repo: String, path: String, commit: String)
455
+ .returns(T::Array[OpenStruct])
456
+ end
340
457
  def _fetch_repo_contents_fully_specified(provider, repo, path, commit)
341
458
  case provider
342
459
  when "github"
@@ -353,9 +470,10 @@ module Dependabot
353
470
  end
354
471
  end
355
472
 
473
+ sig { params(repo: String, path: String, commit: String).returns(T::Array[OpenStruct]) }
356
474
  def _github_repo_contents(repo, path, commit)
357
475
  path = path.gsub(" ", "%20")
358
- github_response = github_client.contents(repo, path: path, ref: commit)
476
+ github_response = T.unsafe(github_client).contents(repo, path: path, ref: commit)
359
477
 
360
478
  if github_response.respond_to?(:type)
361
479
  update_linked_paths(repo, path, commit, github_response)
@@ -365,6 +483,7 @@ module Dependabot
365
483
  github_response.map { |f| _build_github_file_struct(f) }
366
484
  end
367
485
 
486
+ sig { params(relative_path: String).returns(T::Array[OpenStruct]) }
368
487
  def _cloned_repo_contents(relative_path)
369
488
  repo_path = File.join(clone_repo_contents, relative_path)
370
489
  return [] unless Dir.exist?(repo_path)
@@ -390,37 +509,40 @@ module Dependabot
390
509
  end
391
510
  end
392
511
 
512
+ sig { params(file: Sawyer::Resource).returns(OpenStruct) }
393
513
  def _build_github_file_struct(file)
394
514
  OpenStruct.new(
395
- name: file.name,
396
- path: file.path,
397
- type: file.type,
398
- sha: file.sha,
399
- size: file.size
515
+ name: T.unsafe(file).name,
516
+ path: T.unsafe(file).path,
517
+ type: T.unsafe(file).type,
518
+ sha: T.unsafe(file).sha,
519
+ size: T.unsafe(file).size
400
520
  )
401
521
  end
402
522
 
523
+ sig { params(repo: String, path: String, commit: String).returns(T::Array[OpenStruct]) }
403
524
  def _gitlab_repo_contents(repo, path, commit)
404
- gitlab_client
405
- .repo_tree(repo, path: path, ref: commit, per_page: 100)
406
- .map do |file|
407
- # GitLab API essentially returns the output from `git ls-tree`
408
- type = case file.type
409
- when "blob" then "file"
410
- when "tree" then "dir"
411
- when "commit" then "submodule"
412
- else file.fetch("type")
413
- end
414
-
415
- OpenStruct.new(
416
- name: file.name,
417
- path: file.path,
418
- type: type,
419
- size: 0 # GitLab doesn't return file size
420
- )
421
- end
525
+ T.unsafe(gitlab_client)
526
+ .repo_tree(repo, path: path, ref: commit, per_page: 100)
527
+ .map do |file|
528
+ # GitLab API essentially returns the output from `git ls-tree`
529
+ type = case file.type
530
+ when "blob" then "file"
531
+ when "tree" then "dir"
532
+ when "commit" then "submodule"
533
+ else file.fetch("type")
534
+ end
535
+
536
+ OpenStruct.new(
537
+ name: file.name,
538
+ path: file.path,
539
+ type: type,
540
+ size: 0 # GitLab doesn't return file size
541
+ )
542
+ end
422
543
  end
423
544
 
545
+ sig { params(path: String, commit: String).returns(T::Array[OpenStruct]) }
424
546
  def _azure_repo_contents(path, commit)
425
547
  response = azure_client.fetch_repo_contents(commit, path)
426
548
 
@@ -440,12 +562,14 @@ module Dependabot
440
562
  end
441
563
  end
442
564
 
565
+ sig { params(repo: String, path: String, commit: String).returns(T::Array[OpenStruct]) }
443
566
  def _bitbucket_repo_contents(repo, path, commit)
444
- response = bitbucket_client.fetch_repo_contents(
445
- repo,
446
- commit,
447
- path
448
- )
567
+ response = T.unsafe(bitbucket_client)
568
+ .fetch_repo_contents(
569
+ repo,
570
+ commit,
571
+ path
572
+ )
449
573
 
450
574
  response.map do |file|
451
575
  type = case file.fetch("type")
@@ -463,6 +587,7 @@ module Dependabot
463
587
  end
464
588
  end
465
589
 
590
+ sig { params(repo: String, path: String, commit: String).returns(T::Array[OpenStruct]) }
466
591
  def _codecommit_repo_contents(repo, path, commit)
467
592
  response = codecommit_client.fetch_repo_contents(
468
593
  repo,
@@ -480,11 +605,12 @@ module Dependabot
480
605
  end
481
606
  end
482
607
 
608
+ sig { params(path: String, fetch_submodules: T::Boolean).returns(T::Hash[Symbol, T.untyped]) }
483
609
  def _full_specification_for(path, fetch_submodules:)
484
610
  if fetch_submodules && _linked_dir_for(path)
485
611
  linked_dir_details = @linked_paths[_linked_dir_for(path)]
486
612
  sub_path =
487
- path.gsub(%r{^#{Regexp.quote(_linked_dir_for(path))}(/|$)}, "")
613
+ path.gsub(%r{^#{Regexp.quote(T.must(_linked_dir_for(path)))}(/|$)}, "")
488
614
  new_path =
489
615
  Pathname.new(File.join(linked_dir_details.fetch(:path), sub_path))
490
616
  .cleanpath.to_path
@@ -505,6 +631,7 @@ module Dependabot
505
631
  end
506
632
  end
507
633
 
634
+ sig { params(path: String, fetch_submodules: T::Boolean).returns(String) }
508
635
  def _fetch_file_content(path, fetch_submodules: false)
509
636
  path = path.gsub(%r{^/*}, "")
510
637
 
@@ -525,17 +652,18 @@ module Dependabot
525
652
  retry
526
653
  end
527
654
 
655
+ sig { params(provider: String, repo: String, path: String, commit: String).returns(String) }
528
656
  def _fetch_file_content_fully_specified(provider, repo, path, commit)
529
657
  case provider
530
658
  when "github"
531
659
  _fetch_file_content_from_github(path, repo, commit)
532
660
  when "gitlab"
533
- tmp = gitlab_client.get_file(repo, path, commit).content
661
+ tmp = T.unsafe(gitlab_client).get_file(repo, path, commit).content
534
662
  decode_binary_string(tmp)
535
663
  when "azure"
536
664
  azure_client.fetch_file_contents(commit, path)
537
665
  when "bitbucket"
538
- bitbucket_client.fetch_file_contents(repo, commit, path)
666
+ T.unsafe(bitbucket_client).fetch_file_contents(repo, commit, path)
539
667
  when "codecommit"
540
668
  codecommit_client.fetch_file_contents(repo, commit, path)
541
669
  else raise "Unsupported provider '#{source.provider}'."
@@ -543,8 +671,9 @@ module Dependabot
543
671
  end
544
672
 
545
673
  # rubocop:disable Metrics/AbcSize
674
+ sig { params(path: String, repo: String, commit: String).returns(String) }
546
675
  def _fetch_file_content_from_github(path, repo, commit)
547
- tmp = github_client.contents(repo, path: path, ref: commit)
676
+ tmp = T.unsafe(github_client).contents(repo, path: path, ref: commit)
548
677
 
549
678
  raise Octokit::NotFound if tmp.is_a?(Array)
550
679
 
@@ -555,7 +684,7 @@ module Dependabot
555
684
  commit: commit,
556
685
  path: Pathname.new(tmp.target).cleanpath.to_path
557
686
  }
558
- tmp = github_client.contents(
687
+ tmp = T.unsafe(github_client).contents(
559
688
  repo,
560
689
  path: Pathname.new(tmp.target).cleanpath.to_path,
561
690
  ref: commit
@@ -565,7 +694,7 @@ module Dependabot
565
694
  if tmp.content == ""
566
695
  # The file may have exceeded the 1MB limit
567
696
  # see https://github.blog/changelog/2022-05-03-increased-file-size-limit-when-retrieving-file-contents-via-rest-api/
568
- github_client.contents(repo, path: path, ref: commit, accept: "application/vnd.github.v3.raw")
697
+ T.unsafe(github_client).contents(repo, path: path, ref: commit, accept: "application/vnd.github.v3.raw")
569
698
  else
570
699
  decode_binary_string(tmp.content)
571
700
  end
@@ -579,7 +708,7 @@ module Dependabot
579
708
  file_details = repo_contents(dir: dir).find { |f| f.name == basename }
580
709
  raise unless file_details
581
710
 
582
- tmp = github_client.blob(repo, file_details.sha)
711
+ tmp = T.unsafe(github_client).blob(repo, file_details.sha)
583
712
  return tmp.content if tmp.encoding == "utf-8"
584
713
 
585
714
  decode_binary_string(tmp.content)
@@ -589,6 +718,7 @@ module Dependabot
589
718
  # Update the @linked_paths hash by exploiting a side-effect of
590
719
  # recursively calling `repo_contents` for each directory up the tree
591
720
  # until a submodule or symlink is found
721
+ sig { params(path: String).returns(T.nilable(T::Array[T.untyped])) }
592
722
  def _find_linked_dirs(path)
593
723
  path = Pathname.new(path).cleanpath.to_path.gsub(%r{^/*}, "")
594
724
  dir = File.dirname(path)
@@ -603,6 +733,7 @@ module Dependabot
603
733
  )
604
734
  end
605
735
 
736
+ sig { params(path: String).returns(T.nilable(String)) }
606
737
  def _linked_dir_for(path)
607
738
  linked_dirs = @linked_paths.keys
608
739
  linked_dirs
@@ -614,6 +745,7 @@ module Dependabot
614
745
  # rubocop:disable Metrics/MethodLength
615
746
  # rubocop:disable Metrics/PerceivedComplexity
616
747
  # rubocop:disable Metrics/BlockLength
748
+ sig { params(target_directory: T.nilable(String)).returns(String) }
617
749
  def _clone_repo_contents(target_directory:)
618
750
  SharedHelpers.with_git_configured(credentials: credentials) do
619
751
  path = target_directory || File.join("tmp", source.repo)
@@ -645,7 +777,7 @@ module Dependabot
645
777
  raise unless e.message.match(GIT_SUBMODULE_ERROR_REGEX) && e.message.downcase.include?("submodule")
646
778
 
647
779
  submodule_cloning_failed = true
648
- match = e.message.match(GIT_SUBMODULE_ERROR_REGEX)
780
+ match = T.must(e.message.match(GIT_SUBMODULE_ERROR_REGEX))
649
781
  url = match.named_captures["url"]
650
782
  code = match.named_captures["code"]
651
783
 
@@ -688,11 +820,13 @@ module Dependabot
688
820
  # rubocop:enable Metrics/PerceivedComplexity
689
821
  # rubocop:enable Metrics/BlockLength
690
822
 
823
+ sig { params(str: String).returns(String) }
691
824
  def decode_binary_string(str)
692
825
  bom = (+"\xEF\xBB\xBF").force_encoding(Encoding::BINARY)
693
826
  Base64.decode64(str).delete_prefix(bom).force_encoding("UTF-8").encode
694
827
  end
695
828
 
829
+ sig { params(path: String).returns(T::Array[String]) }
696
830
  def find_submodules(path)
697
831
  SharedHelpers.run_shell_command(
698
832
  <<~CMD
@@ -702,7 +836,7 @@ module Dependabot
702
836
  info = line.split
703
837
 
704
838
  type = info.first
705
- path = info.last
839
+ path = T.must(info.last)
706
840
 
707
841
  next path if type == DependencyFile::Mode::SUBMODULE
708
842
  end