Module: Dependabot::GoModules::ResolvabilityErrors

Extended by:
T::Sig
Defined in:
lib/dependabot/go_modules/resolvability_errors.rb

Constant Summary collapse

GITHUB_REPO_REGEX =
T.let(%r{github.com/[^:@ '\n]*}, Regexp)
INSECURE_PROTOCOL_REPOSITORY_REGEX =
T.let(
  /go(?: get)?: .*: no secure protocol found for repository/m,
  Regexp
)
GO_MODULE_WITH_VERSION_REGEX =
T.let(/go(?: get)?:\s*(?<module>[^\s@]+)@/, Regexp)
GO_PREFIXED_HOSTED_REPO_REGEX =
T.let(
  %r{(?:^|\n)\s*go(?: get)?:\s*(?<repo>[a-z0-9.-]+\.[a-z]{2,}/[^:@\s]+)(?:[:\s]|$)}i,
  Regexp
)
REACHABILITY_CHECK_HINTS =
T.let(
  [
    /If this is a private repository/i,
    /Write access to repository not granted/i,
    /Authentication failed/i
  ].freeze,
  T::Array[Regexp]
)

Class Method Summary collapse

Class Method Details

.extract_module_path(message) ⇒ Object



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/dependabot/go_modules/resolvability_errors.rb', line 55

def self.extract_module_path(message)
  github_repo_paths = T.let(
    message.scan(GITHUB_REPO_REGEX).filter_map do |match|
      next match if match.is_a?(String)

      match.first
    end,
    T::Array[String]
  )
  return github_repo_paths.last&.delete_suffix("/") if github_repo_paths.any?

  module_with_version_match = message.match(GO_MODULE_WITH_VERSION_REGEX)
  return module_with_version_match[:module] if module_with_version_match

  hosted_repo_match = message.match(GO_PREFIXED_HOSTED_REPO_REGEX)
  return hosted_repo_match[:repo] if hosted_repo_match

  nil
end

.handle(message) ⇒ Object

Raises:

  • (Dependabot::DependencyFileNotResolvable)


31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/dependabot/go_modules/resolvability_errors.rb', line 31

def self.handle(message)
  mod_path = extract_module_path(message)

  if mod_path && insecure_protocol_repo_error?(message)
    raise Dependabot::GitDependenciesNotReachable, [repo_path_for(mod_path)]
  end

  raise Dependabot::DependencyFileNotResolvable, message unless mod_path && requires_reachability_check?(message)

  # Module not found in the module repository (e.g., GitHub, Gerrit) - query for _any_ version
  # to know if it doesn't exist (or is private) or we were just given a bad revision by this manifest
  SharedHelpers.in_a_temporary_directory do
    File.write("go.mod", "module dummy\n")

    repo_path = repo_path_for(mod_path)

    _, _, status = Open3.capture3(SharedHelpers.escape_command("go list -m -versions #{repo_path}"))
    raise Dependabot::DependencyFileNotResolvable, message if status.success?

    raise Dependabot::GitDependenciesNotReachable, [repo_path]
  end
end

.insecure_protocol_repo_error?(message) ⇒ Boolean

Returns:

  • (Boolean)


81
82
83
# File 'lib/dependabot/go_modules/resolvability_errors.rb', line 81

def self.insecure_protocol_repo_error?(message)
  message.match?(INSECURE_PROTOCOL_REPOSITORY_REGEX)
end

.repo_path_for(mod_path) ⇒ Object



86
87
88
89
90
91
92
# File 'lib/dependabot/go_modules/resolvability_errors.rb', line 86

def self.repo_path_for(mod_path)
  normalized_mod_path = mod_path.delete_suffix("/")
  mod_split = normalized_mod_path.split("/")
  return normalized_mod_path unless mod_split.first == "github.com" && mod_split.size > 3

  T.must(mod_split[0..2]).join("/")
end

.requires_reachability_check?(message) ⇒ Boolean

Returns:

  • (Boolean)


76
77
78
# File 'lib/dependabot/go_modules/resolvability_errors.rb', line 76

def self.requires_reachability_check?(message)
  REACHABILITY_CHECK_HINTS.any? { |regex| message.match?(regex) }
end