Skip to content

fix(hex): handle empty helper output and fix public key response tuple order#14211

Open
thavaahariharangit wants to merge 5 commits intomainfrom
harry/hex-fix-empty-output-and-public-key-response-handling
Open

fix(hex): handle empty helper output and fix public key response tuple order#14211
thavaahariharangit wants to merge 5 commits intomainfrom
harry/hex-fix-empty-output-and-public-key-response-handling

Conversation

@thavaahariharangit
Copy link
Contributor

@thavaahariharangit thavaahariharangit commented Feb 18, 2026

What are you trying to accomplish?

Fixing #14168 - Hex builds fail when fetching the public key from a private registry.

Root cause: Two bugs in the Elixir helper script (run.exs):

  • fetch_public_key destructured the Hex.Repo.get_public_key response tuple as {status, body, headers} when the actual shape is {status, headers, body}, so the public key was never extracted correctly.
  • When the helper subprocess returned empty output (e.g., a registry returning no data), binary_to_term("") crashed instead of producing a clear error.

Changes:

  • run.exs: Fix fetch_public_key tuple pattern from {200, key, _} to {200, _headers, key}. Add an empty-output guard that returns a descriptive error instead of crashing on binary_to_term.
  • lockfile_updater_spec.rb: Add test coverage for public key fingerprint mismatch, public key download failure, and empty helper output error paths.
  • update_checker_spec.rb: Add test coverage for registry verification crash (empty output) and public key download HTTP error scenarios.

Anything you want to highlight for special attention from reviewers?

How will you know you've accomplished your goal?

  1. All existing Hex tests pass — no regressions introduced.
  2. New tests pass for the added error paths: public key fingerprint mismatch, public key download failure, and empty helper output — in both lockfile_updater_spec.rb and update_checker_spec.rb.
  3. Manual verification against a JFrog private Hex registry: when the registry returns a non-200 status for the public key endpoint, the updater now raises a PrivateSourceAuthenticationFailure with the repo name instead of crashing with an opaque binary_to_term error.
updater | 2026/02/18 09:52:56 INFO Started process PID: 4831 with command: {"MIX_EXS" => "/opt/hex/mix.exs", "MIX_QUIET" => "1"} mix run /opt/hex/lib/run.exs
  proxy | 2026/02/18 09:52:58 [014] GET https://jfrogghdemo.jfrog.io:443/artifactory/api/hex/dependabot_hex/public_key
  proxy | 2026/02/18 09:52:59 [014] 501 https://jfrogghdemo.jfrog.io:443/artifactory/api/hex/dependabot_hex/public_key

Checklist

  • I have run the complete test suite to ensure all tests and linters pass.
  • I have thoroughly tested my code changes to ensure they work as expected, including adding additional tests for new functionality.
  • I have written clear and descriptive commit messages.
  • I have provided a detailed description of the changes in the pull request, including the problem it addresses, how it fixes the problem, and any relevant details about the implementation.
  • I have ensured that the code is well-documented and easy to understand.

…e order

- Add empty output check in run.exs to return a clear error instead of
  crashing on binary_to_term with empty data
- Fix fetch_public_key tuple pattern to match {status, headers, body}
  instead of {status, body, headers}
- Add error handling in lockfile_updater for public key fingerprint
  mismatch, public key download failure, empty output, and JSON parse
  errors
- Add corresponding test coverage for new error paths in both
  lockfile_updater and update_checker
@thavaahariharangit thavaahariharangit requested a review from a team as a code owner February 18, 2026 10:33
Copilot AI review requested due to automatic review settings February 18, 2026 10:33
@github-actions github-actions bot added the L: elixir:hex Elixir packages via hex label Feb 18, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes issue #14168 where Hex builds fail when fetching the public key from a private registry. The root cause was a tuple destructuring bug in the Elixir helper script where Hex.Repo.get_public_key returns {status, headers, body} but the code expected {status, body, headers}, causing the public key to never be extracted correctly. Additionally, when helpers returned empty output, binary_to_term("") would crash instead of providing a clear error message.

Changes:

  • Fixed tuple pattern matching in fetch_public_key from {200, key, _} to {200, _headers, key} to correctly extract the public key from HTTP responses
  • Added empty output guard that returns a descriptive error instead of crashing on binary_to_term("")
  • Added comprehensive test coverage for public key errors, download failures, and empty helper output scenarios

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
hex/helpers/lib/run.exs Fixed tuple order bug in fetch_public_key (line 127) and added empty output check (lines 9-15) to prevent binary_to_term crashes
hex/spec/dependabot/hex/file_updater/lockfile_updater_spec.rb Added test coverage for public key fingerprint mismatch, download failure, and empty output errors
hex/spec/dependabot/hex/update_checker_spec.rb Added test coverage for registry verification crashes and public key download HTTP errors

Comment on lines +723 to +739
before do
allow(Dependabot::SharedHelpers).to receive(:run_helper_subprocess)
.with(hash_including(function: "get_latest_resolvable_version"))
.and_raise(
Dependabot::SharedHelpers::HelperSubprocessFailed.new(
message: "No output returned from helper script",
error_context: {}
)
)
end

it "raises a helpful error" do
expect { latest_resolvable_version }
.to raise_error(Dependabot::DependencyFileNotResolvable) do |error|
expect(error.message).to include("No output returned from helper script")
end
end
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm struggling to see the value these tests actually provide. The way they're set up, you could pass any message to HelperSubprocessFailed and just assert that same message comes back out. For example you could set the message to Hello, world! and then check that error.message includes Hello, world! and the test would pass. There are too many things being mocked here so we end up only testing the mock itself rather than any real behaviour

Copy link
Contributor Author

@thavaahariharangit thavaahariharangit Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, you're right that these tests were only verifying the mock itself rather than any real behavior. I've removed both test contexts ("when registry verification crashes with no output" and "when public key download returns HTTP error code") from update_checker_spec.rb in the latest push. The error-handling regex logic is already properly covered by the equivalent tests in lockfile_updater_spec.rb.

defp fetch_public_key(repo, repo_url, auth_key, fingerprint) do
case Hex.Repo.get_public_key(%{trusted: true, url: repo_url, auth_key: auth_key}) do
{:ok, {200, key, _}} ->
{:ok, {200, _headers, key}} ->
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree than this change needs to be made based on the hex docs. But I believe that this will only fix this affect self hosted runners and its possible that you will have to update Dependabot proxy as well

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for confirming the tuple order fix is correct per the hex docs. Good call on the Dependabot proxy — I'll take a look at the proxy repo to check whether it also needs a corresponding update for this to work end-to-end on hosted runners.

The tests for 'registry verification crashes with no output' and 'public
key download returns HTTP error code' only tested the mocks themselves
rather than real behavior. The error-handling regex logic is already
covered by the equivalent tests in lockfile_updater_spec.rb.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

L: elixir:hex Elixir packages via hex

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants