dependabot-hex 0.213.0 → 0.214.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: 30d16ac35f7e452a754f78329c9ef9ba1fd65758264be8220338a721e66dbcb6
4
- data.tar.gz: 94a09051bf06589fe462aa33ab4440d1c5207069a23d8d45aea8517aeb16427e
3
+ metadata.gz: 66e2212df8486009a3da3b280dc0c36e342556e4765760c0c3dc38a71e034a00
4
+ data.tar.gz: d3a62fc111e0e50212cb617bc19f8e86077bf681b3b1d82d1950e16fc283a67a
5
5
  SHA512:
6
- metadata.gz: b9461aa63f1f9a7f6184b29659bbf2a006642fb70eb402787ecbe9a747251c6ae2bf0dd6b484f4e80fa9a0b4b5db42fc2d9eb838aa84c8277a261ce8c03113c8
7
- data.tar.gz: 4a9453c6d17e8af0037c637041726c0c5e12fdcb9e061eaf208051fecf644ac6a54b2d6dcfbed7ed423b6593f6d7ad1c331a1cba796a113c89c0f4570ceb16c4
6
+ metadata.gz: 9233d16f7d684b4e79ed18914d2512c7c2f72d9ae5a6b23d86298f7ac01088d0b43caac63367339974337d36b448ff037906c49867bc1a4f12ebf5a65c052bfa
7
+ data.tar.gz: 564a484640d7135729f86dbe931debabda0c14255c5098a4e1041ec97b2f8dfe69f4fe86ba5bf1bea86223037a7e335de6621feec39e6429ca464549bd76e591
data/helpers/build CHANGED
@@ -10,7 +10,14 @@ fi
10
10
  install_dir="$DEPENDABOT_NATIVE_HELPERS_PATH/hex"
11
11
  mkdir -p "$install_dir"
12
12
 
13
- mix local.hex --force
13
+ # Initial Hex install - will always be the latest available version
14
+ mix local.hex --force --if-missing
15
+ # Annoyingly, a specific Hex version cannot be specified during the initial install.
16
+ # The only way to pin is to re-install.
17
+ if [ -n "$HEX_VERSION" ]; then
18
+ mix hex.install "$HEX_VERSION"
19
+ fi
20
+
14
21
  mix archive.install hex nerves_bootstrap --force
15
22
 
16
23
  helpers_dir="$(dirname "${BASH_SOURCE[0]}")"
@@ -1,9 +1,8 @@
1
1
  defmodule UpdateChecker do
2
- def run(dependency_name, credentials) do
3
- set_credentials(credentials)
4
-
2
+ def run(dependency_name) do
5
3
  # Update the lockfile in a session that we can time out
6
4
  task = Task.async(fn -> do_resolution(dependency_name) end)
5
+
7
6
  case Task.yield(task, 30000) || Task.shutdown(task) do
8
7
  {:ok, {:ok, :resolution_successful}} ->
9
8
  # Read the new lock
@@ -15,43 +14,20 @@ defmodule UpdateChecker do
15
14
  updated_lock
16
15
  |> Map.get(String.to_atom(dependency_name))
17
16
  |> elem(2)
17
+
18
18
  {:ok, version}
19
19
 
20
- {:ok, {:error, error}} -> {:error, error}
20
+ {:ok, {:error, error}} ->
21
+ {:error, error}
21
22
 
22
- nil -> {:error, :dependency_resolution_timed_out}
23
+ nil ->
24
+ {:error, :dependency_resolution_timed_out}
23
25
 
24
- {:exit, reason} -> {:error, reason}
26
+ {:exit, reason} ->
27
+ {:error, reason}
25
28
  end
26
29
  end
27
30
 
28
- defp set_credentials(credentials) do
29
- credentials
30
- |> Enum.reduce([], fn cred, acc ->
31
- if List.last(acc) == nil || List.last(acc)[:token] do
32
- List.insert_at(acc, -1, %{organization: cred})
33
- else
34
- {item, acc} = List.pop_at(acc, -1)
35
- item = Map.put(item, :token, cred)
36
- List.insert_at(acc, -1, item)
37
- end
38
- end)
39
- |> Enum.each(fn cred ->
40
- hexpm = Hex.Repo.get_repo("hexpm")
41
-
42
- repo = %{
43
- url: hexpm.url <> "/repos/#{cred.organization}",
44
- public_key: nil,
45
- auth_key: cred.token
46
- }
47
-
48
- Hex.Config.read()
49
- |> Hex.Config.read_repos()
50
- |> Map.put("hexpm:#{cred.organization}", repo)
51
- |> Hex.Config.update_repos()
52
- end)
53
- end
54
-
55
31
  defp do_resolution(dependency_name) do
56
32
  # Fetch dependencies that needs updating
57
33
  {dependency_lock, rest_lock} =
@@ -59,6 +35,7 @@ defmodule UpdateChecker do
59
35
 
60
36
  try do
61
37
  Mix.Dep.Fetcher.by_name([dependency_name], dependency_lock, rest_lock, [])
38
+
62
39
  {:ok, :resolution_successful}
63
40
  rescue
64
41
  error -> {:error, error}
@@ -66,15 +43,14 @@ defmodule UpdateChecker do
66
43
  end
67
44
  end
68
45
 
69
- [dependency_name | credentials] = System.argv()
70
-
46
+ [dependency_name] = System.argv()
71
47
 
72
- case UpdateChecker.run(dependency_name, credentials) do
48
+ case UpdateChecker.run(dependency_name) do
73
49
  {:ok, version} ->
74
50
  version = :erlang.term_to_binary({:ok, version})
75
51
  IO.write(:stdio, version)
76
52
 
77
- {:error, %Hex.Version.InvalidRequirementError{} = error} ->
53
+ {:error, %Version.InvalidRequirementError{} = error} ->
78
54
  result = :erlang.term_to_binary({:error, "Invalid requirement: #{error.requirement}"})
79
55
  IO.write(:stdio, result)
80
56
 
@@ -1,35 +1,11 @@
1
- [dependency_name | credentials] = System.argv()
2
-
3
- grouped_creds = Enum.reduce credentials, [], fn cred, acc ->
4
- if List.last(acc) == nil || List.last(acc)[:token] do
5
- List.insert_at(acc, -1, %{ organization: cred })
6
- else
7
- { item, acc } = List.pop_at(acc, -1)
8
- item = Map.put(item, :token, cred)
9
- List.insert_at(acc, -1, item)
10
- end
11
- end
12
-
13
- Enum.each grouped_creds, fn cred ->
14
- hexpm = Hex.Repo.get_repo("hexpm")
15
- repo = %{
16
- url: hexpm.url <> "/repos/#{cred.organization}",
17
- public_key: nil,
18
- auth_key: cred.token
19
- }
20
-
21
- Hex.Config.read()
22
- |> Hex.Config.read_repos()
23
- |> Map.put("hexpm:#{cred.organization}", repo)
24
- |> Hex.Config.update_repos()
25
- end
26
-
27
- # dependency atom
28
- dependency = String.to_atom(dependency_name)
1
+ dependency =
2
+ System.argv()
3
+ |> List.first()
4
+ |> String.to_atom()
29
5
 
30
6
  # Fetch dependencies that needs updating
31
7
  {dependency_lock, rest_lock} = Map.split(Mix.Dep.Lock.read(), [dependency])
32
- Mix.Dep.Fetcher.by_name([dependency_name], dependency_lock, rest_lock, [])
8
+ Mix.Dep.Fetcher.by_name([dependency], dependency_lock, rest_lock, [])
33
9
 
34
10
  System.cmd(
35
11
  "mix",
data/helpers/lib/run.exs CHANGED
@@ -11,7 +11,8 @@ defmodule DependencyHelper do
11
11
  {:ok, :erlang.binary_to_term(output)}
12
12
  end
13
13
 
14
- {error, 1} -> {:error, error}
14
+ {error, 1} ->
15
+ {:error, error}
15
16
  end
16
17
  |> handle_result()
17
18
  end
@@ -40,37 +41,115 @@ defmodule DependencyHelper do
40
41
  run_script("parse_deps.exs", dir)
41
42
  end
42
43
 
43
- defp run(%{"function" => "get_latest_resolvable_version", "args" => [dir, dependency_name, credentials]}) do
44
- run_script("check_update.exs", dir, [dependency_name] ++ credentials)
44
+ defp run(%{
45
+ "function" => "get_latest_resolvable_version",
46
+ "args" => [dir, dependency_name, credentials]
47
+ }) do
48
+ set_credentials(credentials)
49
+
50
+ run_script("check_update.exs", dir, [dependency_name])
45
51
  end
46
52
 
47
53
  defp run(%{"function" => "get_updated_lockfile", "args" => [dir, dependency_name, credentials]}) do
48
- run_script("do_update.exs", dir, [dependency_name] ++ credentials)
54
+ set_credentials(credentials)
55
+
56
+ run_script("do_update.exs", dir, [dependency_name])
49
57
  end
50
58
 
51
59
  defp run_script(script, dir, args \\ []) do
52
- args = [
53
- "run",
54
- "--no-deps-check",
55
- "--no-start",
56
- "--no-compile",
57
- "--no-elixir-version-check",
58
- script
59
- ] ++ args
60
+ args =
61
+ [
62
+ "run",
63
+ "--no-deps-check",
64
+ "--no-start",
65
+ "--no-compile",
66
+ "--no-elixir-version-check",
67
+ script
68
+ ] ++ args
60
69
 
61
70
  System.cmd(
62
71
  "mix",
63
72
  args,
64
- [
65
- cd: dir,
66
- env: %{
67
- "MIX_EXS" => nil,
68
- "MIX_LOCK" => nil,
69
- "MIX_DEPS" => nil
70
- }
71
- ]
73
+ cd: dir,
74
+ env: %{
75
+ "MIX_EXS" => nil,
76
+ "MIX_LOCK" => nil,
77
+ "MIX_DEPS" => nil
78
+ }
72
79
  )
73
80
  end
81
+
82
+ defp set_credentials([]), do: :ok
83
+
84
+ defp set_credentials(["hex_organization", organization, token | tail]) do
85
+ url =
86
+ "hexpm"
87
+ |> Hex.Repo.get_repo()
88
+ |> Map.fetch!(:url)
89
+ |> URI.merge("/repos/#{organization}")
90
+ |> to_string()
91
+
92
+ update_repos("hexpm:#{organization}", %{url: url, public_key: nil, auth_key: token})
93
+
94
+ set_credentials(tail)
95
+ end
96
+
97
+ defp set_credentials(["hex_repository", repo, url, auth_key, fingerprint | tail]) do
98
+ case fetch_public_key(repo, url, auth_key, fingerprint) do
99
+ {:ok, public_key} ->
100
+ update_repos(repo, %{auth_key: auth_key, public_key: public_key, url: url})
101
+
102
+ set_credentials(tail)
103
+
104
+ error ->
105
+ handle_result(error)
106
+ end
107
+ end
108
+
109
+ defp set_credentials([_mode, org_or_url | _]) do
110
+ handle_result({:error, "Missing credentials for \"#{org_or_url}\""})
111
+ end
112
+
113
+ defp update_repos(name, opts) do
114
+ Hex.Config.read()
115
+ |> Hex.Config.read_repos()
116
+ |> Map.put(name, opts)
117
+ |> Hex.Config.update_repos()
118
+ end
119
+
120
+ defp fetch_public_key(repo, repo_url, auth_key, fingerprint) do
121
+ case Hex.Repo.get_public_key(repo_url, auth_key) do
122
+ {:ok, {200, key, _}} ->
123
+ if public_key_matches?(key, fingerprint) do
124
+ {:ok, key}
125
+ else
126
+ {:error, "Public key fingerprint mismatch for repo \"#{repo}\""}
127
+ end
128
+
129
+ {:ok, {code, _, _}} ->
130
+ {:error, "Downloading public key for repo \"#{repo}\" failed with code: #{inspect(code)}"}
131
+
132
+ other ->
133
+ {:error, "Downloading public key for repo \"#{repo}\" failed: #{inspect(other)}"}
134
+ end
135
+ end
136
+
137
+ defp public_key_matches?(_public_key, _fingerprint = ""), do: true
138
+
139
+ defp public_key_matches?(public_key, fingerprint) do
140
+ public_key =
141
+ public_key
142
+ |> :public_key.pem_decode()
143
+ |> List.first()
144
+ |> :public_key.pem_entry_decode()
145
+
146
+ decoded_fingerprint =
147
+ :sha256
148
+ |> :ssh.hostkey_fingerprint(public_key)
149
+ |> List.to_string()
150
+
151
+ decoded_fingerprint == fingerprint
152
+ end
74
153
  end
75
154
 
76
155
  DependencyHelper.main()
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dependabot
4
+ module Hex
5
+ module CredentialHelpers
6
+ def self.hex_credentials(credentials)
7
+ organization_credentials(credentials) + repo_credentials(credentials)
8
+ end
9
+
10
+ def self.organization_credentials(credentials)
11
+ defaults = { "organization" => "", "token" => "" }
12
+ keys = %w(type organization token)
13
+
14
+ credentials.
15
+ select { |cred| cred["type"] == "hex_organization" }.
16
+ flat_map { |cred| defaults.merge(cred).slice(*keys).values }
17
+ end
18
+
19
+ def self.repo_credentials(credentials)
20
+ # Credentials are serialized as an array that may not have optional fields. Using a
21
+ # default ensures that the array is always the same length, even if values are empty.
22
+ defaults = { "url" => "", "auth_key" => "", "public_key_fingerprint" => "" }
23
+ keys = %w(type repo url auth_key public_key_fingerprint)
24
+
25
+ credentials.
26
+ select { |cred| cred["type"] == "hex_repository" }.
27
+ flat_map { |cred| defaults.merge(cred).slice(*keys).values }
28
+ end
29
+ end
30
+ end
31
+ end
@@ -4,8 +4,9 @@ require "dependabot/hex/file_updater"
4
4
  require "dependabot/hex/file_updater/mixfile_updater"
5
5
  require "dependabot/hex/file_updater/mixfile_sanitizer"
6
6
  require "dependabot/hex/file_updater/mixfile_requirement_updater"
7
- require "dependabot/hex/version"
7
+ require "dependabot/hex/credential_helpers"
8
8
  require "dependabot/hex/native_helpers"
9
+ require "dependabot/hex/version"
9
10
  require "dependabot/shared_helpers"
10
11
 
11
12
  module Dependabot
@@ -29,7 +30,7 @@ module Dependabot
29
30
  env: mix_env,
30
31
  command: "mix run #{elixir_helper_path}",
31
32
  function: "get_updated_lockfile",
32
- args: [Dir.pwd, dependency.name, organization_credentials]
33
+ args: [Dir.pwd, dependency.name, CredentialHelpers.hex_credentials(credentials)]
33
34
  )
34
35
  end
35
36
  end
@@ -131,11 +132,6 @@ module Dependabot
131
132
  def lockfile
132
133
  @lockfile ||= dependency_files.find { |f| f.name == "mix.lock" }
133
134
  end
134
-
135
- def organization_credentials
136
- credentials.select { |cred| cred["type"] == "hex_organization" }.
137
- flat_map { |cred| [cred["organization"], cred.fetch("token", "")] }
138
- end
139
135
  end
140
136
  end
141
137
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "dependabot/hex/version"
4
4
  require "dependabot/hex/update_checker"
5
+ require "dependabot/hex/credential_helpers"
5
6
  require "dependabot/hex/native_helpers"
6
7
  require "dependabot/hex/file_updater/mixfile_sanitizer"
7
8
  require "dependabot/shared_helpers"
@@ -32,10 +33,7 @@ module Dependabot
32
33
  latest_resolvable_version =
33
34
  SharedHelpers.in_a_temporary_directory do
34
35
  write_temporary_sanitized_dependency_files
35
- FileUtils.cp(
36
- elixir_helper_check_update_path,
37
- "check_update.exs"
38
- )
36
+ FileUtils.cp(elixir_helper_check_update_path, "check_update.exs")
39
37
 
40
38
  SharedHelpers.with_git_configured(credentials: credentials) do
41
39
  run_elixir_update_checker
@@ -55,23 +53,31 @@ module Dependabot
55
53
  env: mix_env,
56
54
  command: "mix run #{elixir_helper_path}",
57
55
  function: "get_latest_resolvable_version",
58
- args: [Dir.pwd,
59
- dependency.name,
60
- organization_credentials],
56
+ args: [Dir.pwd, dependency.name, CredentialHelpers.hex_credentials(credentials)],
61
57
  stderr_to_stdout: true
62
58
  )
63
59
  end
64
60
 
65
61
  def handle_hex_errors(error)
66
- if error.message.include?("No authenticated organization found")
67
- org = error.message.match(/found for ([a-z_]+)\./).captures.first
68
- raise Dependabot::PrivateSourceAuthenticationFailure, org
62
+ if (match = error.message.match(/No authenticated organization found for (?<repo>[a-z_]+)\./))
63
+ raise Dependabot::PrivateSourceAuthenticationFailure, match[:repo]
69
64
  end
70
65
 
71
- if error.message.include?("Failed to fetch record for")
72
- org_match = error.message.match(%r{for 'hexpm:([a-z_]+)/})
73
- org = org_match&.captures&.first
74
- raise Dependabot::PrivateSourceAuthenticationFailure, org if org
66
+ if (match = error.message.match(/Public key fingerprint mismatch for repo "(?<repo>[a-z_]+)"/))
67
+ raise Dependabot::PrivateSourceAuthenticationFailure, match[:repo]
68
+ end
69
+
70
+ if (match = error.message.match(/Missing credentials for "(?<repo>[a-z_]+)"/))
71
+ raise Dependabot::PrivateSourceAuthenticationFailure, match[:repo]
72
+ end
73
+
74
+ if (match = error.message.match(/Downloading public key for repo "(?<repo>[a-z_]+)"/))
75
+ raise Dependabot::PrivateSourceAuthenticationFailure, match[:repo]
76
+ end
77
+
78
+ if (match = error.message.match(/Failed to fetch record for '(?<repo>[a-z_]+)(?::(?<org>[a-z_]+))?/))
79
+ name = match[:org] || match[:repo]
80
+ raise Dependabot::PrivateSourceAuthenticationFailure, name
75
81
  end
76
82
 
77
83
  # TODO: Catch the warnings as part of the Elixir module. This happens
@@ -171,12 +177,6 @@ module Dependabot
171
177
  def elixir_helper_check_update_path
172
178
  File.join(NativeHelpers.hex_helpers_dir, "lib/check_update.exs")
173
179
  end
174
-
175
- def organization_credentials
176
- credentials.
177
- select { |cred| cred["type"] == "hex_organization" }.
178
- flat_map { |cred| [cred["organization"], cred.fetch("token", "")] }
179
- end
180
180
  end
181
181
  end
182
182
  end
@@ -231,7 +231,7 @@ module Dependabot
231
231
  # rubocop:enable Metrics/PerceivedComplexity
232
232
 
233
233
  def filter_lower_versions(versions_array)
234
- return versions_array unless current_version && version_class.correct?(current_version)
234
+ return versions_array unless current_version
235
235
 
236
236
  versions_array.select do |version|
237
237
  version > current_version
@@ -251,12 +251,6 @@ module Dependabot
251
251
  nil
252
252
  end
253
253
 
254
- def current_version
255
- return unless dependency.version && version_class.correct?(dependency.version)
256
-
257
- version_class.new(dependency.version)
258
- end
259
-
260
254
  def wants_prerelease?
261
255
  return true if current_version&.prerelease?
262
256
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dependabot-hex
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.213.0
4
+ version: 0.214.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dependabot
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-10-31 00:00:00.000000000 Z
11
+ date: 2022-12-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dependabot-common
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - '='
18
18
  - !ruby/object:Gem::Version
19
- version: 0.213.0
19
+ version: 0.214.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - '='
25
25
  - !ruby/object:Gem::Version
26
- version: 0.213.0
26
+ version: 0.214.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: debug
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -58,14 +58,14 @@ dependencies:
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: 3.13.0
61
+ version: 4.0.0
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: 3.13.0
68
+ version: 4.0.0
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rake
71
71
  requirement: !ruby/object:Gem::Requirement
@@ -114,14 +114,14 @@ dependencies:
114
114
  requirements:
115
115
  - - "~>"
116
116
  - !ruby/object:Gem::Version
117
- version: 1.37.1
117
+ version: 1.39.0
118
118
  type: :development
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
122
  - - "~>"
123
123
  - !ruby/object:Gem::Version
124
- version: 1.37.1
124
+ version: 1.39.0
125
125
  - !ruby/object:Gem::Dependency
126
126
  name: rubocop-performance
127
127
  requirement: !ruby/object:Gem::Requirement
@@ -221,6 +221,7 @@ files:
221
221
  - helpers/mix.exs
222
222
  - helpers/mix.lock
223
223
  - lib/dependabot/hex.rb
224
+ - lib/dependabot/hex/credential_helpers.rb
224
225
  - lib/dependabot/hex/file_fetcher.rb
225
226
  - lib/dependabot/hex/file_parser.rb
226
227
  - lib/dependabot/hex/file_updater.rb