Skip to content

Commit fb6423c

Browse files
authored
Restrict global OAuth tokens to Hex.pm repositories (#218)
1 parent 6288cdf commit fb6423c

2 files changed

Lines changed: 42 additions & 4 deletions

File tree

src/hex_cli_auth.erl

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ with_repo(BaseConfig, Fun) ->
271271
%% <li>`repo_key' from `get_auth_config' callback - passthrough</li>
272272
%% <li>`auth_key' from `get_auth_config' when `trusted' is true and `oauth_exchange' is true - exchange for OAuth token</li>
273273
%% <li>`auth_key' from `get_auth_config' when `trusted' is true - use directly</li>
274-
%% <li>Global OAuth token from `get_oauth_tokens' callback</li>
274+
%% <li>Global OAuth token from `get_oauth_tokens' callback for Hex.pm repositories</li>
275275
%% <li>No auth when `optional' is true (with retry on 401)</li>
276276
%% <li>Prompt via `should_authenticate' when `auth_inline' is true</li>
277277
%% </ol>
@@ -473,7 +473,7 @@ resolve_api_auth(_Permission, Config) ->
473473
%% 1. repo_key from get_auth_config => passthrough
474474
%% 2. trusted + auth_key + oauth_exchange => exchange for OAuth token
475475
%% 3. trusted + auth_key => use directly
476-
%% 4. trusted + global OAuth tokens => use those
476+
%% 4. trusted Hex.pm or child repository + global OAuth tokens => use those
477477
%% 5. Fallthrough to no_auth (handled by with_repo/3 for optional/auth_inline)
478478
-spec resolve_repo_auth(hex_core:config()) ->
479479
{ok, binary(), auth_context()} | no_auth | {error, auth_error()}.
@@ -515,15 +515,22 @@ do_resolve_repo_auth(RepoName, LookupRepo, Config) ->
515515
[ParentName, _OrgName] ->
516516
do_resolve_repo_auth(RepoName, ParentName, Config);
517517
_ ->
518-
%% 6. trusted + global OAuth tokens => use those
519-
resolve_global_oauth_for_repo(Config)
518+
%% 6. trusted Hex.pm or child repository + global OAuth tokens => use those
519+
resolve_global_oauth_for_repo(RepoName, Config)
520520
end;
521521
_ ->
522522
%% 7. Not trusted, no auth
523523
no_auth
524524
end.
525525

526526
%% @private
527+
resolve_global_oauth_for_repo(<<"hexpm">>, Config) ->
528+
resolve_global_oauth_for_repo(Config);
529+
resolve_global_oauth_for_repo(<<"hexpm:", _/binary>>, Config) ->
530+
resolve_global_oauth_for_repo(Config);
531+
resolve_global_oauth_for_repo(_RepoName, _Config) ->
532+
no_auth.
533+
527534
resolve_global_oauth_for_repo(Config) ->
528535
case resolve_oauth_token_with_context(Config) of
529536
{ok, Token, AuthContext} ->

test/hex_cli_auth_SUITE.erl

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ all() ->
3636
resolve_repo_auth_trusted_auth_key_test,
3737
resolve_repo_auth_untrusted_ignores_auth_key_test,
3838
resolve_repo_auth_oauth_fallback_test,
39+
resolve_repo_auth_oauth_fallback_child_repo_test,
40+
resolve_repo_auth_oauth_fallback_custom_repo_test,
3941
resolve_repo_auth_no_auth_test,
4042

4143
%% resolve_repo_auth tests - token exchange
@@ -250,6 +252,35 @@ resolve_repo_auth_oauth_fallback_test(_Config) ->
250252
?assertEqual(<<"Bearer global_oauth">>, RepoKey),
251253
ok.
252254

255+
resolve_repo_auth_oauth_fallback_child_repo_test(_Config) ->
256+
Now = erlang:system_time(second),
257+
Config = config_with_callbacks(#{
258+
auth_config => #{},
259+
oauth_tokens =>
260+
{ok, #{
261+
access_token => <<"global_oauth">>,
262+
expires_at => Now + 3600
263+
}}
264+
}),
265+
266+
{ok, RepoKey, _} = hex_cli_auth:resolve_repo_auth(
267+
Config#{repo_organization => <<"myorg">>, trusted => true}
268+
),
269+
?assertEqual(<<"Bearer global_oauth">>, RepoKey),
270+
ok.
271+
272+
resolve_repo_auth_oauth_fallback_custom_repo_test(_Config) ->
273+
Config = config_with_callbacks(#{
274+
auth_config => #{},
275+
get_oauth_tokens => fun() -> error(global_oauth_callback_called) end
276+
}),
277+
278+
Result = hex_cli_auth:resolve_repo_auth(
279+
Config#{repo_name => <<"custom">>, trusted => true}
280+
),
281+
?assertEqual(no_auth, Result),
282+
ok.
283+
253284
resolve_repo_auth_no_auth_test(_Config) ->
254285
%% Test no_auth when untrusted and no credentials
255286
Config = config_with_callbacks(#{

0 commit comments

Comments
 (0)