@@ -31,11 +31,6 @@ defmodule Hex.RemoteConverger do
3131
3232 Registry . open ( )
3333
34- # Check and refresh OAuth token before fetching packages
35- # This ensures we only prompt once for authentication instead of
36- # getting multiple prompts during concurrent package fetches
37- check_and_refresh_auth ( )
38-
3934 # We cannot use given lock here, because all deps that are being
4035 # converged have been removed from the lock by Mix
4136 # We need the old lock to get the children of Hex packages
@@ -44,14 +39,20 @@ defmodule Hex.RemoteConverger do
4439 overridden = Hex.Mix . overridden_deps ( deps )
4540 requests = Hex.Mix . deps_to_requests ( deps )
4641
47- [
48- Hex.Mix . packages_from_lock ( lock ) ,
49- Hex.Mix . packages_from_lock ( old_lock ) ,
50- packages_from_requests ( requests )
51- ]
52- |> Enum . concat ( )
53- |> verify_prefetches ( )
54- |> Registry . prefetch ( )
42+ prefetches =
43+ [
44+ Hex.Mix . packages_from_lock ( lock ) ,
45+ Hex.Mix . packages_from_lock ( old_lock ) ,
46+ packages_from_requests ( requests )
47+ ]
48+ |> Enum . concat ( )
49+ |> verify_prefetches ( )
50+
51+ # Only preflight user OAuth when one of the relevant repos would
52+ # actually rely on the stored OAuth token. Public-only deps.get
53+ # should not prompt just because an unrelated token expired.
54+ check_and_refresh_auth ( prefetches )
55+ Registry . prefetch ( prefetches )
5556
5657 locked = prepare_locked ( lock , old_lock , deps )
5758
@@ -734,34 +735,60 @@ defmodule Hex.RemoteConverger do
734735 version1 . major == 0 and version2 . major == 0 and version1 . minor != version2 . minor
735736 end
736737
737- defp check_and_refresh_auth do
738- # Try to get token with authentication prompting enabled
739- # The OnceCache ensures only one process prompts even if multiple processes
740- # detect the expired token concurrently
741- case Hex.OAuth . get_token ( prompt_auth: true ) do
742- { :ok , _access_token } ->
743- # Token is valid, was successfully refreshed, or user authenticated
744- :ok
738+ defp check_and_refresh_auth ( prefetches ) do
739+ if auth_preflight_required? ( prefetches ) do
740+ # Try to get token with authentication prompting enabled
741+ # The OnceCache ensures only one process prompts even if multiple processes
742+ # detect the expired token concurrently
743+ case Hex.OAuth . get_token ( prompt_auth: true ) do
744+ { :ok , _access_token } ->
745+ # Token is valid, was successfully refreshed, or user authenticated
746+ :ok
745747
746- { :error , :auth_failed } ->
747- Hex.Shell . warn (
748- "Authentication failed. Private packages will not be available. " <>
749- "Run `mix hex.user auth` to authenticate."
750- )
748+ { :error , :auth_failed } ->
749+ Hex.Shell . warn (
750+ "Authentication failed. Private packages will not be available. " <>
751+ "Run `mix hex.user auth` to authenticate."
752+ )
751753
752- { :error , :auth_declined } ->
753- Hex.Shell . warn (
754- "Private packages will not be available. " <>
755- "Run `mix hex.user auth` to authenticate."
756- )
754+ { :error , :auth_declined } ->
755+ Hex.Shell . warn (
756+ "Private packages will not be available. " <>
757+ "Run `mix hex.user auth` to authenticate."
758+ )
757759
758- { :error , :no_auth } ->
759- # No OAuth token - this is OK, user might only be fetching public packages
760- :ok
760+ { :error , :no_auth } ->
761+ # No OAuth token - this is OK, user might only be fetching public packages
762+ :ok
761763
762- { :error , _other } ->
763- # Other errors (shouldn't happen with prompt_auth: true, but handle gracefully)
764- :ok
764+ { :error , _other } ->
765+ # Other errors (shouldn't happen with prompt_auth: true, but handle gracefully)
766+ :ok
767+ end
768+ else
769+ :ok
765770 end
766771 end
772+
773+ @ doc false
774+ def auth_preflight_required? ( prefetches ) do
775+ prefetches
776+ |> Enum . map ( fn { repo , _package } -> repo end )
777+ |> Enum . uniq ( )
778+ |> Enum . any? ( & repo_requires_user_oauth? / 1 )
779+ end
780+
781+ defp repo_requires_user_oauth? ( "hexpm:" <> _ = repo ) do
782+ repo
783+ |> Hex.Repo . get_repo ( )
784+ |> repo_uses_user_oauth? ( )
785+ end
786+
787+ defp repo_requires_user_oauth? ( _repo ) do
788+ false
789+ end
790+
791+ defp repo_uses_user_oauth? ( repo_config ) do
792+ Map . get ( repo_config , :trusted , true ) && ! repo_config . auth_key
793+ end
767794end
0 commit comments