diff --git a/apps/rebar/src/rebar.app.src.script b/apps/rebar/src/rebar.app.src.script
index 36ae2dd45..afae095c1 100644
--- a/apps/rebar/src/rebar.app.src.script
+++ b/apps/rebar/src/rebar.app.src.script
@@ -17,6 +17,7 @@
common_test,
dialyzer,
public_key,
+ ssh,
edoc,
snmp,
getopt,
diff --git a/apps/rebar/src/rebar_hex_auth.erl b/apps/rebar/src/rebar_hex_auth.erl
new file mode 100644
index 000000000..0a166e037
--- /dev/null
+++ b/apps/rebar/src/rebar_hex_auth.erl
@@ -0,0 +1,211 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
+%% @doc
+%% Authentication wrapper for Hex package manager.
+%%
+%% This module provides rebar3-specific callbacks for r3_hex_cli_auth.
+%% See r3_hex_cli_auth for auth resolution order and details.
+%% @end
+-module(rebar_hex_auth).
+
+-export([with_api/5, with_repo/4]).
+
+%% OAuth utilities
+-export([client_id/0, global_oauth_key/0, persist_tokens/4]).
+
+
+-include("rebar.hrl").
+-include_lib("providers/include/providers.hrl").
+
+-define(GLOBAL_OAUTH_KEY, <<"$oauth">>).
+-define(OAUTH_CLIENT_ID, <<"b9721cf5-be2f-4a65-bfa5-141698b4b9cf">>).
+
+%% @doc Execute an API call with authentication handling.
+%% @see r3_hex_cli_auth:with_api/5
+-spec with_api(Permission, Config, State, Opts, Callback) -> Result when
+ Permission :: r3_hex_cli_auth:permission(),
+ Config :: rebar_hex_repos:repo(),
+ State :: rebar_state:t(),
+ Opts :: r3_hex_cli_auth:opts(),
+ Callback :: fun((rebar_hex_repos:repo()) -> Result),
+ Result :: term().
+with_api(Permission, Config, State, Opts, Callback) when Permission =:= read; Permission =:= write ->
+ Callbacks = make_callbacks(State),
+ HexConfig = to_hex_config(Config),
+ r3_hex_cli_auth:with_api(Callbacks, Permission, HexConfig, Callback, Opts).
+
+%% @doc Execute a repository call with authentication handling.
+%% @see r3_hex_cli_auth:with_repo/4
+-spec with_repo(Config, State, Opts, Callback) -> Result when
+ Config :: rebar_hex_repos:repo(),
+ State :: rebar_state:t(),
+ Opts :: r3_hex_cli_auth:opts(),
+ Callback :: fun((rebar_hex_repos:repo()) -> Result),
+ Result :: term().
+with_repo(Config, State, Opts, Callback) ->
+ Callbacks = make_callbacks(State),
+ HexConfig = to_hex_config(Config),
+ r3_hex_cli_auth:with_repo(Callbacks, HexConfig, Callback, Opts).
+
+%% @private
+%% Strip rebar3-specific fields from repo config before passing to hex_core.
+-spec to_hex_config(rebar_hex_repos:repo()) -> r3_hex_core:config().
+to_hex_config(Config) ->
+ maps:without([name, parent, mirror_of], Config).
+
+%%====================================================================
+%% OAuth utilities
+%%====================================================================
+
+%% @doc Returns the OAuth client ID for Hex.
+-spec client_id() -> binary().
+client_id() -> ?OAUTH_CLIENT_ID.
+
+%% @doc Returns the key used for global OAuth storage in hex.config.
+-spec global_oauth_key() -> binary().
+global_oauth_key() -> ?GLOBAL_OAUTH_KEY.
+
+%% @doc Persist the global OAuth tokens to hex.config.
+-spec persist_tokens(AccessToken, RefreshToken, ExpiresAt, State) -> ok when
+ AccessToken :: binary(),
+ RefreshToken :: binary() | undefined,
+ ExpiresAt :: integer(),
+ State :: rebar_state:t().
+persist_tokens(AccessToken, RefreshToken, ExpiresAt, State) ->
+ Updates = #{
+ ?GLOBAL_OAUTH_KEY => #{
+ access_token => AccessToken,
+ refresh_token => RefreshToken,
+ expires_at => ExpiresAt
+ }
+ },
+ rebar_hex_repos:update_auth_config(Updates, State),
+ ?DEBUG("Updated global OAuth tokens", []),
+ ok.
+
+%%====================================================================
+%% Callbacks builder
+%%====================================================================
+
+%% @private
+%% Build the callbacks map required by r3_hex_cli_auth.
+-spec make_callbacks(rebar_state:t()) -> r3_hex_cli_auth:callbacks().
+make_callbacks(State) ->
+ #{
+ get_auth_config => fun(RepoName) ->
+ get_repo_auth_config(RepoName, State)
+ end,
+
+ get_oauth_tokens => fun() ->
+ get_global_oauth_tokens(State)
+ end,
+
+ persist_oauth_tokens => fun(Scope, AccessToken, RefreshToken, ExpiresAt) ->
+ persist_oauth_tokens(Scope, AccessToken, RefreshToken, ExpiresAt, State)
+ end,
+
+ prompt_otp => fun(Message) ->
+ prompt_otp(Message)
+ end,
+
+ should_authenticate => fun(Reason) ->
+ should_authenticate(Reason)
+ end,
+
+ get_client_id => fun() ->
+ client_id()
+ end
+ }.
+
+%%====================================================================
+%% Helper functions for callbacks
+%%====================================================================
+
+%% @private
+%% Get auth config for a specific repo from hex.config.
+-spec get_repo_auth_config(RepoName, State) -> r3_hex_cli_auth:repo_auth_config() | undefined when
+ RepoName :: unicode:unicode_binary(),
+ State :: rebar_state:t().
+get_repo_auth_config(RepoName, State) ->
+ rebar_hex_repos:get_repo_auth_config(RepoName, State).
+
+%% @private
+%% Get global OAuth tokens from auth config.
+-spec get_global_oauth_tokens(rebar_state:t()) -> {ok, map()} | error.
+get_global_oauth_tokens(State) ->
+ case rebar_hex_repos:get_repo_auth_config(?GLOBAL_OAUTH_KEY, State) of
+ #{access_token := _, expires_at := _} = Tokens ->
+ {ok, Tokens};
+ _ ->
+ error
+ end.
+
+%% @private
+%% Persist OAuth tokens. Scope can be 'global' or a repo name binary.
+-spec persist_oauth_tokens(Scope, AccessToken, RefreshToken, ExpiresAt, State) -> ok when
+ Scope :: global | unicode:unicode_binary(),
+ AccessToken :: binary(),
+ RefreshToken :: binary() | undefined,
+ ExpiresAt :: integer(),
+ State :: rebar_state:t().
+persist_oauth_tokens(global, AccessToken, RefreshToken, ExpiresAt, State) ->
+ OAuthTokens = #{
+ access_token => AccessToken,
+ refresh_token => RefreshToken,
+ expires_at => ExpiresAt
+ },
+ rebar_hex_repos:update_repo_auth_config(OAuthTokens, ?GLOBAL_OAUTH_KEY, State),
+ ?DEBUG("Updated global OAuth tokens", []),
+ ok;
+persist_oauth_tokens(RepoName, AccessToken, RefreshToken, ExpiresAt, State) ->
+ OAuthTokens = #{
+ oauth_token => #{
+ access_token => AccessToken,
+ refresh_token => RefreshToken,
+ expires_at => ExpiresAt
+ }
+ },
+ rebar_hex_repos:update_repo_auth_config(OAuthTokens, RepoName, State),
+ ?DEBUG("Updated OAuth tokens for ~ts", [RepoName]),
+ ok.
+
+%% @private
+%% Prompt user for OTP code.
+-spec prompt_otp(binary()) -> {ok, binary()} | cancelled.
+prompt_otp(Message) ->
+ ?CONSOLE("~ts", [Message]),
+ case io:get_line("OTP code: ") of
+ eof -> cancelled;
+ {error, _} -> cancelled;
+ Line ->
+ case string:trim(Line) of
+ "" -> cancelled;
+ Code -> {ok, list_to_binary(Code)}
+ end
+ end.
+
+%% @private
+%% Ask user if they want to authenticate.
+-spec should_authenticate(r3_hex_cli_auth:auth_prompt_reason()) -> boolean().
+should_authenticate(no_credentials) ->
+ ?CONSOLE("No Hex credentials found. Would you like to authenticate?", []),
+ prompt_yes_no();
+should_authenticate(token_refresh_failed) ->
+ ?CONSOLE("Hex token refresh failed. Would you like to re-authenticate?", []),
+ prompt_yes_no().
+
+%% @private
+-spec prompt_yes_no() -> boolean().
+prompt_yes_no() ->
+ case io:get_line("[Y/n]: ") of
+ eof -> false;
+ {error, _} -> false;
+ Line ->
+ case string:lowercase(string:trim(Line)) of
+ "" -> true; % Default to yes
+ "y" -> true;
+ "yes" -> true;
+ _ -> false
+ end
+ end.
+
diff --git a/apps/rebar/src/rebar_hex_repos.erl b/apps/rebar/src/rebar_hex_repos.erl
index 04cdf6870..35886cf71 100644
--- a/apps/rebar/src/rebar_hex_repos.erl
+++ b/apps/rebar/src/rebar_hex_repos.erl
@@ -3,11 +3,14 @@
-export([from_state/2,
get_repo_config/2,
auth_config/1,
+ get_repo_auth_config/2,
+ update_repo_auth_config/3,
remove_from_auth_config/2,
update_auth_config/2,
format_error/1,
anon_repo_config/1,
- format_repo/1
+ format_repo/1,
+ apply_env_overrides/1
]).
-ifdef(TEST).
@@ -20,16 +23,38 @@
-export_type([repo/0]).
--type repo() :: #{name => unicode:unicode_binary(),
- api_url => binary(),
- api_key => binary(),
- repo_url => binary(),
- repo_key => binary(),
- repo_public_key => binary(),
- repo_verify => binary(),
- repo_verify_origin => binary(),
- mirror_of => _ % legacy field getting stripped
- }.
+%% repo() extends r3_hex_core:config() with rebar3-specific fields
+-type repo() :: #{
+ %% rebar3-specific fields
+ name => unicode:unicode_binary(),
+ repo_name => unicode:unicode_binary(),
+ parent => unicode:unicode_binary(),
+ mirror_of => term(),
+ %% r3_hex_core:config() fields
+ api_key => binary() | undefined,
+ api_otp => binary() | undefined,
+ api_organization => binary() | undefined,
+ api_repository => binary() | undefined,
+ api_url => binary(),
+ http_adapter => {module(), map()},
+ http_etag => binary() | undefined,
+ http_headers => map(),
+ http_user_agent_fragment => binary(),
+ repo_key => binary() | undefined,
+ repo_public_key => binary(),
+ repo_url => binary(),
+ repo_organization => binary() | undefined,
+ repo_verify => boolean(),
+ repo_verify_origin => boolean(),
+ send_100_continue => boolean(),
+ tarball_max_size => pos_integer() | infinity,
+ tarball_max_uncompressed_size => pos_integer() | infinity,
+ docs_tarball_max_size => pos_integer() | infinity,
+ docs_tarball_max_uncompressed_size => pos_integer() | infinity,
+ trusted => boolean(),
+ oauth_exchange => boolean(),
+ oauth_exchange_url => binary() | undefined
+}.
from_state(BaseConfig, State) ->
HexConfig = rebar_state:get(State, hex, []),
@@ -39,22 +64,49 @@ from_state(BaseConfig, State) ->
%% add base config entries that are specific to use by rebar3 and not overridable
Repos1 = merge_with_base_and_auth(Repos, BaseConfig, Auth),
%% merge organizations parent repo options into each oraganization repo
- update_organizations(maybe_override_default_repo_url(Repos1, State)).
+ Repos2 = update_organizations(maybe_override_default_repo_url(Repos1, State)),
+ %% apply environment variable overrides to all repos
+ [apply_env_overrides(Repo) || Repo <- Repos2].
-spec get_repo_config(unicode:unicode_binary(), rebar_state:t() | [repo()])
- -> {ok, repo()} | error.
+ -> {ok, repo()}.
get_repo_config(RepoName, Repos) when is_list(Repos) ->
case ec_lists:find(fun(#{name := N}) -> N =:= RepoName end, Repos) of
- error ->
- throw(?PRV_ERROR({repo_not_found, RepoName}));
{ok, RepoConfig} ->
- {ok, RepoConfig}
+ {ok, RepoConfig};
+ error ->
+ maybe_create_org_config(RepoName, Repos)
end;
get_repo_config(RepoName, State) ->
Resources = rebar_state:resources(State),
#{repos := Repos} = rebar_resource_v2:find_resource_state(pkg, Resources),
get_repo_config(RepoName, Repos).
+%% @private
+%% Create a repo config for "parent:org" format repos.
+%% Only succeeds if parent repo exists, otherwise throws repo_not_found.
+-spec maybe_create_org_config(unicode:unicode_binary(), [repo()]) -> {ok, repo()}.
+maybe_create_org_config(RepoName, Repos) ->
+ case rebar_string:split(RepoName, <<":">>) of
+ [ParentName, Org] ->
+ case ec_lists:find(fun(#{name := N}) -> N =:= ParentName end, Repos) of
+ {ok, ParentConfig} ->
+ OrgConfig = ParentConfig#{
+ name => RepoName,
+ repo_name => ParentName,
+ repo_organization => Org,
+ api_organization => Org,
+ api_repository => Org,
+ parent => ParentName
+ },
+ {ok, apply_env_overrides(OrgConfig)};
+ error ->
+ throw(?PRV_ERROR({repo_not_found, RepoName}))
+ end;
+ _ ->
+ throw(?PRV_ERROR({repo_not_found, RepoName}))
+ end.
+
-spec anon_repo_config(repo()) ->
#{api_url := _, name := _, repo_name => _, repo_organization => _,
repo_url := _, repo_verify => _, repo_verify_origin => _,
@@ -106,7 +158,7 @@ merge_repos(Repos) ->
%% We set the repo_organization and api_organization to org
%% for fetching and publishing private packages.
update_repo_list(R#{name => Name,
- repo_name => Org,
+ repo_name => Repo,
repo_organization => Org,
api_organization => Org,
api_repository => Org,
@@ -193,6 +245,25 @@ auth_config(State) ->
?ABORT("Error found in repos auth config (~ts) at line ~ts", [AuthFile, Reason])
end.
+-spec get_repo_auth_config(unicode:unicode_binary(), rebar_state:t()) -> map() | undefined.
+get_repo_auth_config(RepoName, State) ->
+ AuthConfig = auth_config(State),
+ case maps:find(RepoName, AuthConfig) of
+ {ok, RepoAuth} when is_map(RepoAuth) ->
+ RepoAuth;
+ _ ->
+ undefined
+ end.
+
+-spec update_repo_auth_config(map(), unicode:unicode_binary(), rebar_state:t()) -> ok.
+update_repo_auth_config(Updates, RepoName, State) ->
+ ExistingRepoAuth = case get_repo_auth_config(RepoName, State) of
+ undefined -> #{};
+ Auth -> Auth
+ end,
+ UpdatedRepoAuth = maps:merge(ExistingRepoAuth, Updates),
+ update_auth_config(#{RepoName => UpdatedRepoAuth}, State).
+
-spec remove_from_auth_config(term(), rebar_state:t()) -> ok.
remove_from_auth_config(Key, State) ->
Updated = maps:remove(Key, auth_config(State)),
@@ -209,3 +280,103 @@ write_auth_config(Config, State) ->
NewConfig = iolist_to_binary(["%% coding: utf-8", io_lib:nl(),
io_lib:print(Config), ".", io_lib:nl()]),
ok = file:write_file(AuthConfigFile, NewConfig, [{encoding, utf8}]).
+
+%% Environment variable overrides
+%% These follow the same pattern as the Elixir hex package
+
+-spec apply_env_overrides(repo()) -> repo().
+apply_env_overrides(Config) ->
+ lists:foldl(fun(F, C) -> F(C) end, Config, [
+ fun apply_api_key_override/1,
+ fun apply_api_url_override/1,
+ fun apply_otp_override/1,
+ fun apply_repos_key_override/1,
+ fun apply_unsafe_registry_override/1,
+ fun apply_no_verify_repo_origin_override/1,
+ fun apply_mirror_override/1
+ ]).
+
+apply_api_key_override(Config) ->
+ case os:getenv("HEX_API_KEY") of
+ false -> Config;
+ "" -> Config;
+ ApiKey -> Config#{api_key => list_to_binary(ApiKey)}
+ end.
+
+apply_api_url_override(Config) ->
+ case os:getenv("HEX_API_URL") of
+ false ->
+ case os:getenv("HEX_API") of
+ false -> Config;
+ "" -> Config;
+ ApiUrl -> Config#{api_url => list_to_binary(ApiUrl)}
+ end;
+ "" -> Config;
+ ApiUrl -> Config#{api_url => list_to_binary(ApiUrl)}
+ end.
+
+apply_otp_override(Config) ->
+ case os:getenv("HEX_OTP") of
+ false -> Config;
+ "" -> Config;
+ Otp -> Config#{api_otp => list_to_binary(Otp)}
+ end.
+
+apply_repos_key_override(Config) ->
+ case os:getenv("HEX_REPOS_KEY") of
+ false -> Config;
+ "" -> Config;
+ Key -> Config#{repo_key => list_to_binary(Key)}
+ end.
+
+apply_unsafe_registry_override(Config) ->
+ case os:getenv("HEX_UNSAFE_REGISTRY") of
+ "1" -> Config#{repo_verify => false};
+ "true" -> Config#{repo_verify => false};
+ _ -> Config
+ end.
+
+apply_no_verify_repo_origin_override(Config) ->
+ case os:getenv("HEX_NO_VERIFY_REPO_ORIGIN") of
+ "1" -> Config#{repo_verify_origin => false};
+ "true" -> Config#{repo_verify_origin => false};
+ _ -> Config
+ end.
+
+apply_mirror_override(Config) ->
+ %% HEX_TRUSTED_MIRROR_URL takes precedence (trusted = auth credentials sent)
+ %% HEX_MIRROR_URL is untrusted (no auth credentials sent, no signature verification)
+ case os:getenv("HEX_TRUSTED_MIRROR_URL") of
+ false ->
+ case os:getenv("HEX_TRUSTED_MIRROR") of
+ false -> apply_untrusted_mirror_override(Config);
+ "" -> apply_untrusted_mirror_override(Config);
+ TrustedMirrorUrl ->
+ Config#{repo_url => list_to_binary(TrustedMirrorUrl),
+ trusted => true}
+ end;
+ "" -> apply_untrusted_mirror_override(Config);
+ TrustedMirrorUrl ->
+ Config#{repo_url => list_to_binary(TrustedMirrorUrl),
+ trusted => true}
+ end.
+
+apply_untrusted_mirror_override(Config) ->
+ case os:getenv("HEX_MIRROR_URL") of
+ false ->
+ case os:getenv("HEX_MIRROR") of
+ false -> Config;
+ "" -> Config;
+ MirrorUrl ->
+ Config#{repo_url => list_to_binary(MirrorUrl),
+ trusted => false,
+ repo_verify => false,
+ repo_verify_origin => false}
+ end;
+ "" -> Config;
+ MirrorUrl ->
+ Config#{repo_url => list_to_binary(MirrorUrl),
+ trusted => false,
+ repo_verify => false,
+ repo_verify_origin => false}
+ end.
diff --git a/apps/rebar/src/rebar_packages.erl b/apps/rebar/src/rebar_packages.erl
index 9f47911f6..dc4e9f990 100644
--- a/apps/rebar/src/rebar_packages.erl
+++ b/apps/rebar/src/rebar_packages.erl
@@ -1,6 +1,6 @@
-module(rebar_packages).
--export([get/2
+-export([get/3
,get_all_names/1
,registry_dir/1
,package_dir/2
@@ -29,9 +29,14 @@ format_error({missing_package, Name, Vsn}) ->
format_error({missing_package, Pkg}) ->
io_lib:format("Package not found in any repo: ~p", [Pkg]).
--spec get(rebar_hex_repos:repo(), binary()) -> {ok, map()} | {error, term()}.
-get(Config, Name) ->
- try r3_hex_api_package:get(Config, Name) of
+-spec get(rebar_hex_repos:repo(), binary(), rebar_state:t()) -> {ok, map()} | {error, term()}.
+get(Config, Name, State) ->
+ handle_get_result(rebar_hex_auth:with_api(read, Config, State, [{optional, true}], fun(AuthConfig) ->
+ r3_hex_api_package:get(AuthConfig, Name)
+ end)).
+
+handle_get_result(Result) ->
+ try Result of
{ok, {200, _Headers, PkgInfo}} ->
{ok, PkgInfo};
{ok, {404, _, _}} ->
@@ -227,7 +232,9 @@ update_package(Name, RepoConfig=#{name := Repo}, State) ->
?MODULE:verify_table(State),
?DEBUG("Getting definition for package ~ts from repo ~ts",
[Name, rebar_hex_repos:format_repo(RepoConfig)]),
- try r3_hex_repo:get_package(get_package_repo_config(RepoConfig), Name) of
+ try rebar_hex_auth:with_repo(RepoConfig, State, [], fun(AuthConfig) ->
+ r3_hex_repo:get_package(get_package_repo_config(AuthConfig), Name)
+ end) of
{ok, {200, _Headers, Package}} ->
#{releases := Releases} = Package,
_ = insert_releases(Name, Releases, Repo, ?PACKAGE_TABLE),
diff --git a/apps/rebar/src/rebar_pkg_resource.erl b/apps/rebar/src/rebar_pkg_resource.erl
index d7d4f25a1..594debca7 100644
--- a/apps/rebar/src/rebar_pkg_resource.erl
+++ b/apps/rebar/src/rebar_pkg_resource.erl
@@ -138,11 +138,13 @@ format_error({bad_registry_checksum, Name, Vsn, Expected, Found}) ->
%% {ok, Contents, NewEtag}, otherwise if some error occurred return error.
%% @end
%%------------------------------------------------------------------------------
--spec request(rebar_hex_repos:repo(), binary(), binary(), binary() | undefined)
+-spec request(rebar_hex_repos:repo(), binary(), binary(), binary() | undefined, rebar_state:t())
-> {ok, cached} | {ok, binary(), binary()} | error.
-request(Config, Name, Version, ETag) ->
- Config1 = Config#{http_etag => ETag},
- try r3_hex_repo:get_tarball(Config1, Name, Version) of
+request(Config, Name, Version, ETag, State) ->
+ try rebar_hex_auth:with_repo(Config, State, [], fun(AuthConfig) ->
+ Config1 = AuthConfig#{http_etag => ETag},
+ r3_hex_repo:get_tarball(Config1, Name, Version)
+ end) of
{ok, {200, #{<<"etag">> := ETag1}, Tarball}} ->
{ok, Tarball, ETag1};
{ok, {304, _Headers, _}} ->
@@ -210,11 +212,11 @@ store_etag_in_cache(Path, ETag) ->
UpdateETag :: boolean(),
Res :: ok | {unexpected_hash, integer(), integer()} | {fetch_fail, binary(), binary()}
| {bad_registry_checksum, integer(), integer()} | {error, _}.
-cached_download(TmpDir, CachePath, Pkg={pkg, Name, Vsn, _OldHash, _Hash, RepoConfig}, _State, ETag,
+cached_download(TmpDir, CachePath, Pkg={pkg, Name, Vsn, _OldHash, _Hash, RepoConfig}, State, ETag,
ETagPath, UpdateETag) ->
?DEBUG("Making request to get package ~ts from repo ~ts",
[Name, rebar_hex_repos:format_repo(RepoConfig)]),
- case request(RepoConfig, Name, Vsn, ETag) of
+ case request(RepoConfig, Name, Vsn, ETag, State) of
{ok, cached} ->
?DEBUG("Version cached at ~ts is up to date, reusing it", [CachePath]),
serve_from_cache(TmpDir, CachePath, Pkg);
diff --git a/apps/rebar/src/rebar_prv_packages.erl b/apps/rebar/src/rebar_prv_packages.erl
index a6a2c81b0..4456b48fb 100644
--- a/apps/rebar/src/rebar_prv_packages.erl
+++ b/apps/rebar/src/rebar_prv_packages.erl
@@ -36,7 +36,7 @@ do(State) ->
Name ->
Resources = rebar_state:resources(State),
#{repos := Repos} = rebar_resource_v2:find_resource_state(pkg, Resources),
- Results = get_package(rebar_utils:to_binary(Name), Repos),
+ Results = get_package(rebar_utils:to_binary(Name), Repos, State),
case lists:all(fun({_, {error, not_found}}) -> true; (_) -> false end, Results) of
true ->
?PRV_ERROR({not_found, Name});
@@ -46,10 +46,10 @@ do(State) ->
end
end.
--spec get_package(binary(), [map()]) -> [{binary(), {ok, map()} | {error, term()}}].
-get_package(Name, Repos) ->
+-spec get_package(binary(), [map()], rebar_state:t()) -> [{binary(), {ok, map()} | {error, term()}}].
+get_package(Name, Repos, State) ->
lists:foldl(fun(RepoConfig, Acc) ->
- [{maps:get(name, RepoConfig), rebar_packages:get(RepoConfig, Name)} | Acc]
+ [{maps:get(name, RepoConfig), rebar_packages:get(RepoConfig, Name, State)} | Acc]
end, [], Repos).
diff --git a/apps/rebar/src/vendored/r3_hex_api.erl b/apps/rebar/src/vendored/r3_hex_api.erl
index e99cfb868..73505e47b 100644
--- a/apps/rebar/src/vendored/r3_hex_api.erl
+++ b/apps/rebar/src/vendored/r3_hex_api.erl
@@ -1,4 +1,4 @@
-%% Vendored from hex_core v0.15.0, do not edit manually
+%% Vendored from hex_core v0.17.0, do not edit manually
%% @doc
%% Hex HTTP API
@@ -19,7 +19,8 @@
-export_type([response/0]).
-type response() :: {ok, {r3_hex_http:status(), r3_hex_http:headers(), body() | nil}} | {error, term()}.
--type body() :: [body()] | #{binary() => body() | binary()}.
+-type body() :: #{binary() => value()} | [#{binary() => value()}].
+-type value() :: binary() | boolean() | nil | number() | [value()] | #{binary() => value()}.
%% @private
get(Config, Path) ->
diff --git a/apps/rebar/src/vendored/r3_hex_api_key.erl b/apps/rebar/src/vendored/r3_hex_api_key.erl
index d2147a580..3e9d4d669 100644
--- a/apps/rebar/src/vendored/r3_hex_api_key.erl
+++ b/apps/rebar/src/vendored/r3_hex_api_key.erl
@@ -1,4 +1,4 @@
-%% Vendored from hex_core v0.15.0, do not edit manually
+%% Vendored from hex_core v0.17.0, do not edit manually
%% @doc
%% Hex HTTP API - Keys.
diff --git a/apps/rebar/src/vendored/r3_hex_api_oauth.erl b/apps/rebar/src/vendored/r3_hex_api_oauth.erl
index 9b7dba5e4..cf877b33d 100644
--- a/apps/rebar/src/vendored/r3_hex_api_oauth.erl
+++ b/apps/rebar/src/vendored/r3_hex_api_oauth.erl
@@ -1,4 +1,4 @@
-%% Vendored from hex_core v0.15.0, do not edit manually
+%% Vendored from hex_core v0.17.0, do not edit manually
%% @doc
%% Hex HTTP API - OAuth.
@@ -6,6 +6,8 @@
-export([
device_authorization/3,
device_authorization/4,
+ device_auth_flow/4,
+ device_auth_flow/5,
poll_device_token/3,
refresh_token/3,
revoke_token/3,
@@ -13,6 +15,21 @@
client_credentials_token/5
]).
+-export_type([oauth_tokens/0, device_auth_error/0]).
+
+-type oauth_tokens() :: #{
+ access_token := binary(),
+ refresh_token => binary() | undefined,
+ expires_at := integer()
+}.
+
+-type device_auth_error() ::
+ timeout
+ | {access_denied, Status :: non_neg_integer(), Body :: term()}
+ | {device_auth_failed, Status :: non_neg_integer(), Body :: term()}
+ | {poll_failed, Status :: non_neg_integer(), Body :: term()}
+ | term().
+
%% @doc
%% Initiates the OAuth device authorization flow.
%%
@@ -28,7 +45,7 @@ device_authorization(Config, ClientId, Scope) ->
%% Returns device code, user code, and verification URIs for user authentication.
%%
%% Options:
-%% * `name' - A name to identify the token (e.g., hostname of the device)
+%% * `name' - A name to identify the token (defaults to the machine's hostname)
%%
%% Examples:
%%
@@ -51,17 +68,141 @@ device_authorization(Config, ClientId, Scope) ->
r3_hex_api:response().
device_authorization(Config, ClientId, Scope, Opts) ->
Path = <<"oauth/device_authorization">>,
- Params0 = #{
- <<"client_id">> => ClientId,
- <<"scope">> => Scope
- },
- Params =
+ Name =
case proplists:get_value(name, Opts) of
- undefined -> Params0;
- Name -> Params0#{<<"name">> => Name}
+ undefined -> get_hostname();
+ N -> N
end,
+ Params = #{
+ <<"client_id">> => ClientId,
+ <<"scope">> => Scope,
+ <<"name">> => Name
+ },
r3_hex_api:post(Config, Path, Params).
+%% @doc
+%% Runs the complete OAuth device authorization flow.
+%%
+%% @see device_auth_flow/5
+%% @end
+-spec device_auth_flow(
+ r3_hex_core:config(),
+ ClientId :: binary(),
+ Scope :: binary(),
+ PromptUser :: fun((VerificationUri :: binary(), UserCode :: binary()) -> ok)
+) -> {ok, oauth_tokens()} | {error, device_auth_error()}.
+device_auth_flow(Config, ClientId, Scope, PromptUser) ->
+ device_auth_flow(Config, ClientId, Scope, PromptUser, []).
+
+%% @doc
+%% Runs the complete OAuth device authorization flow with options.
+%%
+%% This function handles the entire device authorization flow:
+%% 1. Requests a device code from the server
+%% 2. Calls `PromptUser' callback with the verification URI and user code
+%% 3. Optionally opens the browser for the user (when `open_browser' is true)
+%% 4. Polls the token endpoint until authorization completes or times out
+%%
+%% The `PromptUser' callback is responsible for displaying the verification URI
+%% and user code to the user (e.g., printing to console).
+%%
+%% Options:
+%% * `name' - A name to identify the token (defaults to the machine's hostname)
+%% * `open_browser' - When `true', automatically opens the browser
+%% to the verification URI. When `false' (default), only the callback is invoked.
+%%
+%% Returns:
+%% - `{ok, Tokens}' - Authorization successful, returns access token and optional refresh token
+%% - `{error, timeout}' - Device code expired before user completed authorization
+%% - `{error, {access_denied, Status, Body}}' - User denied the authorization request
+%% - `{error, {device_auth_failed, Status, Body}}' - Initial device authorization request failed
+%% - `{error, {poll_failed, Status, Body}}' - Unexpected error during polling
+%%
+%% Examples:
+%%
+%% ```
+%% 1> Config = r3_hex_core:default_config().
+%% 2> PromptUser = fun(Uri, Code) ->
+%% io:format("Visit ~s and enter code: ~s~n", [Uri, Code])
+%% end.
+%% 3> r3_hex_api_oauth:device_auth_flow(Config, <<"cli">>, <<"api:write">>, PromptUser).
+%% {ok, #{
+%% access_token => <<"...">>,
+%% refresh_token => <<"...">>,
+%% expires_at => 1234567890
+%% }}
+%% '''
+%% @end
+-spec device_auth_flow(
+ r3_hex_core:config(),
+ ClientId :: binary(),
+ Scope :: binary(),
+ PromptUser :: fun((VerificationUri :: binary(), UserCode :: binary()) -> ok),
+ proplists:proplist()
+) -> {ok, oauth_tokens()} | {error, device_auth_error()}.
+device_auth_flow(Config, ClientId, Scope, PromptUser, Opts) ->
+ case device_authorization(Config, ClientId, Scope, Opts) of
+ {ok, {200, _, DeviceResponse}} when is_map(DeviceResponse) ->
+ #{
+ <<"device_code">> := DeviceCode,
+ <<"user_code">> := UserCode,
+ <<"verification_uri_complete">> := VerificationUri,
+ <<"expires_in">> := ExpiresIn,
+ <<"interval">> := IntervalSeconds
+ } = DeviceResponse,
+ ok = PromptUser(VerificationUri, UserCode),
+ OpenBrowser = proplists:get_value(open_browser, Opts, false),
+ case OpenBrowser of
+ true -> open_browser(VerificationUri);
+ false -> ok
+ end,
+ ExpiresAt = erlang:system_time(second) + ExpiresIn,
+ poll_for_token_loop(Config, ClientId, DeviceCode, IntervalSeconds, ExpiresAt);
+ {ok, {Status, _, Body}} ->
+ {error, {device_auth_failed, Status, Body}};
+ {error, Reason} ->
+ {error, Reason}
+ end.
+
+%% @private
+poll_for_token_loop(Config, ClientId, DeviceCode, IntervalSeconds, ExpiresAt) ->
+ Now = erlang:system_time(second),
+ case Now >= ExpiresAt of
+ true ->
+ {error, timeout};
+ false ->
+ timer:sleep(IntervalSeconds * 1000),
+ case poll_device_token(Config, ClientId, DeviceCode) of
+ {ok, {200, _, TokenResponse}} when is_map(TokenResponse) ->
+ #{
+ <<"access_token">> := AccessToken,
+ <<"expires_in">> := ExpiresIn
+ } = TokenResponse,
+ RefreshToken = maps:get(<<"refresh_token">>, TokenResponse, undefined),
+ TokenExpiresAt = erlang:system_time(second) + ExpiresIn,
+ {ok, #{
+ access_token => AccessToken,
+ refresh_token => RefreshToken,
+ expires_at => TokenExpiresAt
+ }};
+ {ok, {400, _, #{<<"error">> := <<"authorization_pending">>}}} ->
+ poll_for_token_loop(Config, ClientId, DeviceCode, IntervalSeconds, ExpiresAt);
+ {ok, {400, _, #{<<"error">> := <<"slow_down">>}}} ->
+ %% Increase polling interval as requested by server
+ poll_for_token_loop(
+ Config, ClientId, DeviceCode, IntervalSeconds + 5, ExpiresAt
+ );
+ {ok, {400, _, #{<<"error">> := <<"expired_token">>}}} ->
+ {error, timeout};
+ {ok, {Status, _, #{<<"error">> := <<"access_denied">>} = Body}} ->
+ {error, {access_denied, Status, Body}};
+ {ok, {Status, _, Body}} ->
+ {error, {poll_failed, Status, Body}};
+ {error, Reason} ->
+ {error, Reason}
+ end
+ end.
+
%% @doc
%% Polls the OAuth token endpoint for device authorization completion.
%%
@@ -201,3 +342,44 @@ revoke_token(Config, ClientId, Token) ->
<<"client_id">> => ClientId
},
r3_hex_api:post(Config, Path, Params).
+
+%%====================================================================
+%% Internal functions
+%%====================================================================
+
+%% @private
+%% Open a URL in the default browser.
+%% Uses platform-specific commands: open (macOS), xdg-open (Linux), start (Windows).
+-spec open_browser(binary()) -> ok.
+open_browser(Url) when is_binary(Url) ->
+ ok = ensure_valid_http_url(Url),
+ UrlStr = binary_to_list(Url),
+ {Cmd, Args} =
+ case os:type() of
+ {unix, darwin} ->
+ {"open", [UrlStr]};
+ {unix, _} ->
+ {"xdg-open", [UrlStr]};
+ {win32, _} ->
+ {"cmd", ["/c", "start", "", UrlStr]}
+ end,
+ Port = open_port({spawn_executable, os:find_executable(Cmd)}, [{args, Args}]),
+ port_close(Port),
+ ok.
+
+%% @private
+%% Validates that a URL uses http:// or https:// scheme.
+-spec ensure_valid_http_url(binary()) -> ok.
+ensure_valid_http_url(Url) when is_binary(Url) ->
+ case uri_string:parse(Url) of
+ #{scheme := <<"https">>} -> ok;
+ #{scheme := <<"http">>} -> ok;
+ _ -> throw({invalid_url, Url})
+ end.
+
+%% @private
+%% Get the hostname of the current machine.
+-spec get_hostname() -> binary().
+get_hostname() ->
+ {ok, Hostname} = inet:gethostname(),
+ list_to_binary(Hostname).
diff --git a/apps/rebar/src/vendored/r3_hex_api_package.erl b/apps/rebar/src/vendored/r3_hex_api_package.erl
index f7850c49c..46dd92522 100644
--- a/apps/rebar/src/vendored/r3_hex_api_package.erl
+++ b/apps/rebar/src/vendored/r3_hex_api_package.erl
@@ -1,4 +1,4 @@
-%% Vendored from hex_core v0.15.0, do not edit manually
+%% Vendored from hex_core v0.17.0, do not edit manually
%% @doc
%% Hex HTTP API - Packages.
diff --git a/apps/rebar/src/vendored/r3_hex_api_package_owner.erl b/apps/rebar/src/vendored/r3_hex_api_package_owner.erl
index a5e734323..33af12a09 100644
--- a/apps/rebar/src/vendored/r3_hex_api_package_owner.erl
+++ b/apps/rebar/src/vendored/r3_hex_api_package_owner.erl
@@ -1,4 +1,4 @@
-%% Vendored from hex_core v0.15.0, do not edit manually
+%% Vendored from hex_core v0.17.0, do not edit manually
%% @doc
%% Hex HTTP API - Package Owners.
diff --git a/apps/rebar/src/vendored/r3_hex_api_release.erl b/apps/rebar/src/vendored/r3_hex_api_release.erl
index f6d37c34c..218fce8d6 100644
--- a/apps/rebar/src/vendored/r3_hex_api_release.erl
+++ b/apps/rebar/src/vendored/r3_hex_api_release.erl
@@ -1,4 +1,4 @@
-%% Vendored from hex_core v0.15.0, do not edit manually
+%% Vendored from hex_core v0.17.0, do not edit manually
%% @doc
%% Hex HTTP API - Releases.
diff --git a/apps/rebar/src/vendored/r3_hex_api_user.erl b/apps/rebar/src/vendored/r3_hex_api_user.erl
index 1dc1cb60b..c4e5050d4 100644
--- a/apps/rebar/src/vendored/r3_hex_api_user.erl
+++ b/apps/rebar/src/vendored/r3_hex_api_user.erl
@@ -1,4 +1,4 @@
-%% Vendored from hex_core v0.15.0, do not edit manually
+%% Vendored from hex_core v0.17.0, do not edit manually
%% @doc
%% Hex HTTP API - Users.
diff --git a/apps/rebar/src/vendored/r3_hex_cli_auth.erl b/apps/rebar/src/vendored/r3_hex_cli_auth.erl
new file mode 100644
index 000000000..d7dd371a7
--- /dev/null
+++ b/apps/rebar/src/vendored/r3_hex_cli_auth.erl
@@ -0,0 +1,724 @@
+%% Vendored from hex_core v0.17.0, do not edit manually
+
+%% @doc
+%% Authentication handling with callback functions for build-tool-specific operations.
+%%
+%% This module provides generic authentication handling that allows both rebar3
+%% and Elixir Hex (and future build tools) to share the common auth logic while
+%% customizing prompting, persistence, and configuration retrieval.
+%%
+%% == Callbacks ==
+%%
+%% The caller provides a callbacks map with these functions (all required):
+%%
+%% ```
+%% #{
+%% %% Auth configuration for a specific repo
+%% get_auth_config => fun((RepoName :: binary()) ->
+%% #{api_key => binary(),
+%% auth_key => binary(),
+%% oauth_exchange => boolean(),
+%% oauth_exchange_url => binary()} | undefined),
+%%
+%% %% Global OAuth tokens - storage and retrieval
+%% get_oauth_tokens => fun(() -> {ok, #{access_token := binary(),
+%% refresh_token => binary(),
+%% expires_at := integer()}} | error),
+%% persist_oauth_tokens => fun((Scope :: global | binary(),
+%% AccessToken :: binary(),
+%% RefreshToken :: binary() | undefined,
+%% ExpiresAt :: integer()) -> ok),
+%%
+%% %% User interaction
+%% prompt_otp => fun((Message :: binary()) -> {ok, OtpCode :: binary()} | cancelled),
+%% should_authenticate => fun((Reason :: no_credentials | token_refresh_failed) -> boolean()),
+%%
+%% %% OAuth client configuration
+%% get_client_id => fun(() -> binary())
+%% }
+%% '''
+%%
+%% == Auth Resolution Order ==
+%%
+%% For API calls:
+%%
+%% - Per-repo `api_key' from config (with optional OAuth exchange for hex.pm)
+%% - Parent repo `api_key' (for "hexpm:org" organizations)
+%% - Global OAuth token (refreshed if expired)
+%% - Device auth flow (for write operations only)
+%%
+%%
+%% For repo calls:
+%%
+%% - Per-repo `auth_key' with optional OAuth exchange (default true for hex.pm)
+%% - Parent repo `auth_key'
+%% - Global OAuth token
+%%
+%%
+%% == OAuth Exchange ==
+%%
+%% For hex.pm URLs, `api_key' and `auth_key' are exchanged for short-lived OAuth
+%% tokens via the client credentials grant. This behavior can be controlled per-repo
+%% via the `oauth_exchange' option in the repo config (defaults to `true' for hex.pm).
+%%
+%% == Auth Context ==
+%%
+%% Internally, authentication resolution tracks context via `auth_context()':
+%%
+%% - `source' - Where the credentials came from (`env', `config', or `oauth')
+%% - `has_refresh_token' - Whether token refresh is possible on 401
+%%
+%%
+%% == Token Format ==
+%%
+%% OAuth access tokens are automatically prefixed with `<<"Bearer ">>' when used
+%% as `api_key' or `repo_key' in the config.
+-module(r3_hex_cli_auth).
+
+-export([
+ with_api/4,
+ with_api/5,
+ with_repo/3,
+ with_repo/4,
+ resolve_api_auth/3,
+ resolve_repo_auth/2
+]).
+
+-export_type([
+ callbacks/0,
+ permission/0,
+ auth_error/0,
+ auth_context/0,
+ repo_auth_config/0,
+ auth_prompt_reason/0,
+ opts/0
+]).
+
+%% 5 minute buffer before expiry
+-define(EXPIRY_BUFFER_SECONDS, 300).
+
+%% Maximum OTP retry attempts
+-define(MAX_OTP_RETRIES, 3).
+
+-type permission() :: read | write.
+
+-type callbacks() :: #{
+ get_auth_config := fun((RepoName :: binary()) -> repo_auth_config() | undefined),
+ get_oauth_tokens := fun(() -> {ok, oauth_tokens()} | error),
+ persist_oauth_tokens := fun(
+ (
+ Scope :: global | binary(),
+ AccessToken :: binary(),
+ RefreshToken :: binary() | undefined,
+ ExpiresAt :: integer()
+ ) -> ok
+ ),
+ prompt_otp := fun((Message :: binary()) -> {ok, OtpCode :: binary()} | cancelled),
+ should_authenticate := fun((Reason :: auth_prompt_reason()) -> boolean()),
+ get_client_id := fun(() -> binary())
+}.
+
+-type auth_prompt_reason() ::
+ no_credentials
+ | token_refresh_failed.
+
+-type repo_auth_config() :: #{
+ api_key => binary(),
+ repo_key => binary(),
+ auth_key => binary(),
+ oauth_token => oauth_tokens()
+}.
+
+-type oauth_tokens() :: #{
+ access_token := binary(),
+ refresh_token => binary(),
+ expires_at := integer()
+}.
+
+-type auth_error() ::
+ {auth_error, no_credentials}
+ | {auth_error, auth_declined}
+ | {auth_error, otp_cancelled}
+ | {auth_error, otp_max_retries}
+ | {auth_error, token_refresh_failed}
+ | {auth_error, device_auth_timeout}
+ | {auth_error, device_auth_denied}
+ | {auth_error, oauth_exchange_failed}
+ | {auth_error, term()}.
+
+-type auth_context() :: #{
+ source => env | config | oauth,
+ has_refresh_token => boolean()
+}.
+
+-type opts() :: [
+ {optional, boolean()}
+ | {auth_inline, boolean()}
+ | {oauth_open_browser, boolean()}
+].
+
+%%====================================================================
+%% API functions
+%%====================================================================
+
+%% @doc
+%% Execute a function with API authentication.
+%%
+%% Equivalent to `with_api(Callbacks, Permission, Config, Fun, [])'.
+%%
+%% @see with_api/5
+-spec with_api(callbacks(), permission(), r3_hex_core:config(), fun((r3_hex_core:config()) -> Result)) ->
+ Result | {error, auth_error()}
+when
+ Result :: term().
+with_api(Callbacks, Permission, BaseConfig, Fun) ->
+ with_api(Callbacks, Permission, BaseConfig, Fun, []).
+
+%% @doc
+%% Execute a function with API authentication.
+%%
+%% Resolves credentials in this order:
+%%
+%% - Per-repo `api_key' from config (with optional OAuth exchange for hex.pm)
+%% - Parent repo `api_key' (for "hexpm:org" organizations)
+%% - Global OAuth token (refreshed if expired)
+%% - Device auth flow (when `should_authenticate' callback returns true)
+%%
+%%
+%% On 401 responses, handles OTP prompts and token refresh automatically.
+%%
+%% The repository name is taken from the config (`repo_name' or `repo_organization').
+%%
+%% Options:
+%%
+%% - `optional' - When `true', if no credentials are found, executes the function
+%% without authentication first. If the server returns 401, triggers auth
+%% (respecting `auth_inline'). When `false' (default), missing credentials
+%% immediately triggers the `should_authenticate' callback.
+%% - `auth_inline' - When `true' (default), prompts the user via `should_authenticate'
+%% callback when authentication is needed. When `false', returns
+%% `{error, {auth_error, no_credentials}}' instead of prompting.
+%% - `oauth_open_browser' - When `true' (default), automatically opens the browser
+%% during device auth flow. When `false', only prints the URL for the user.
+%%
+%%
+%% Example:
+%% ```
+%% r3_hex_cli_auth:with_api(Callbacks, write, Config, fun(C) ->
+%% r3_hex_api_release:publish(C, Tarball)
+%% end, [{optional, false}, {auth_inline, true}]).
+%% '''
+-spec with_api(
+ callbacks(),
+ permission(),
+ r3_hex_core:config(),
+ fun((r3_hex_core:config()) -> Result),
+ opts()
+) ->
+ Result | {error, auth_error()}
+when
+ Result :: term().
+with_api(Callbacks, Permission, BaseConfig, Fun, Opts) ->
+ Optional = proplists:get_value(optional, Opts, false),
+ AuthInline = proplists:get_value(auth_inline, Opts, true),
+ case resolve_api_auth(Callbacks, Permission, BaseConfig) of
+ {ok, ApiKey, AuthContext} ->
+ Config = BaseConfig#{api_key => ApiKey},
+ execute_with_retry(Callbacks, Config, Fun, AuthContext, 0, undefined, Opts);
+ {error, no_auth} when Optional =:= true ->
+ %% Auth is optional, try without credentials first
+ execute_optional_with_retry(Callbacks, BaseConfig, Fun, Opts);
+ {error, no_auth} when AuthInline =:= true ->
+ %% No auth found, ask user if they want to authenticate
+ maybe_authenticate_and_retry(Callbacks, BaseConfig, Fun, no_credentials, Opts);
+ {error, no_auth} ->
+ %% auth_inline is false, just return error
+ {error, {auth_error, no_credentials}};
+ {error, _} = Error ->
+ Error
+ end.
+
+%% @doc
+%% Execute a function with repository authentication.
+%%
+%% Equivalent to `with_repo(Callbacks, Config, Fun, [])'.
+%%
+%% @see with_repo/4
+-spec with_repo(callbacks(), r3_hex_core:config(), fun((r3_hex_core:config()) -> Result)) ->
+ Result | {error, auth_error()}
+when
+ Result :: term().
+with_repo(Callbacks, BaseConfig, Fun) ->
+ with_repo(Callbacks, BaseConfig, Fun, []).
+
+%% @doc
+%% Execute a function with repository authentication.
+%%
+%% Resolves credentials in this order:
+%%
+%% - `repo_key' in config - passthrough
+%% - `repo_key' from `get_auth_config' callback - passthrough
+%% - `auth_key' from `get_auth_config' when `trusted' is true and `oauth_exchange' is true - exchange for OAuth token
+%% - `auth_key' from `get_auth_config' when `trusted' is true - use directly
+%% - Global OAuth token from `get_oauth_tokens' callback
+%% - No auth when `optional' is true (with retry on 401)
+%% - Prompt via `should_authenticate' when `auth_inline' is true
+%%
+%%
+%% The repository name is taken from the config (`repo_name' or `repo_organization').
+%%
+%% Options:
+%%
+%% - `optional' - When `true' (default), proceeds without auth if none found; retries with auth on 401.
+%% - `auth_inline' - When `true', prompts user via `should_authenticate' callback. Default is `false'.
+%% - `oauth_open_browser' - When `true' (default), automatically opens the browser
+%% during device auth flow. When `false', only prints the URL for the user.
+%%
+%%
+%% Example:
+%% ```
+%% r3_hex_cli_auth:with_repo(Callbacks, Config, fun(C) ->
+%% r3_hex_repo:get_tarball(C, <<"ecto">>, <<"3.0.0">>)
+%% end).
+%% '''
+-spec with_repo(
+ callbacks(), r3_hex_core:config(), fun((r3_hex_core:config()) -> Result), opts()
+) ->
+ Result | {error, auth_error()}
+when
+ Result :: term().
+with_repo(Callbacks, BaseConfig, Fun, Opts) ->
+ Optional = proplists:get_value(optional, Opts, true),
+ AuthInline = proplists:get_value(auth_inline, Opts, false),
+ case resolve_repo_auth(Callbacks, BaseConfig) of
+ {ok, RepoKey, _AuthContext} when is_binary(RepoKey) ->
+ Config = BaseConfig#{repo_key => RepoKey},
+ Fun(Config);
+ no_auth when Optional =:= true ->
+ %% Auth is optional, try without credentials first
+ execute_optional_with_retry(Callbacks, BaseConfig, Fun, Opts);
+ no_auth when AuthInline =:= true ->
+ %% No auth found, ask user if they want to authenticate
+ maybe_authenticate_and_retry(Callbacks, BaseConfig, Fun, no_credentials, Opts);
+ no_auth ->
+ %% auth_inline is false, return error
+ {error, {auth_error, no_credentials}};
+ {error, {auth_error, token_refresh_failed}} when Optional =:= true ->
+ %% Token refresh failed but auth is optional, fall back to no credentials
+ execute_optional_with_retry(Callbacks, BaseConfig, Fun, Opts);
+ {error, _} = Error ->
+ Error
+ end.
+
+%% @private
+%% Extract repository name from config.
+-spec repo_name(r3_hex_core:config()) -> binary().
+repo_name(#{repo_name := Name, repo_organization := Org}) when is_binary(Name) and is_binary(Org) ->
+ <>;
+repo_name(#{repo_name := Name}) when is_binary(Name) -> Name;
+repo_name(_) ->
+ <<"hexpm">>.
+
+%% @private
+%% Ask user if they want to authenticate, and if yes, initiate device auth.
+maybe_authenticate_and_retry(Callbacks, BaseConfig, Fun, Reason, Opts) ->
+ case call_callback(Callbacks, should_authenticate, [Reason]) of
+ true ->
+ case device_auth(Callbacks, BaseConfig, <<"api repositories">>, Opts) of
+ {ok, #{access_token := Token}} ->
+ BearerToken = <<"Bearer ", Token/binary>>,
+ Config = BaseConfig#{api_key => BearerToken},
+ AuthContext = #{source => oauth, has_refresh_token => true},
+ execute_with_retry(Callbacks, Config, Fun, AuthContext, 0, undefined, Opts);
+ {error, _} = Error ->
+ Error
+ end;
+ false ->
+ {error, {auth_error, auth_declined}}
+ end.
+
+%% @private
+%% Execute function without auth, but retry with auth if we get a 401.
+execute_optional_with_retry(Callbacks, BaseConfig, Fun, Opts) ->
+ AuthInline = proplists:get_value(auth_inline, Opts, true),
+ case Fun(BaseConfig) of
+ {ok, {401, _Headers, _Body}} when AuthInline =:= true ->
+ %% Got 401, need auth - ask user if they want to authenticate
+ maybe_authenticate_and_retry(Callbacks, BaseConfig, Fun, no_credentials, Opts);
+ {ok, {401, _Headers, _Body}} ->
+ %% Got 401 but auth_inline is false, return error
+ {error, {auth_error, no_credentials}};
+ Other ->
+ Other
+ end.
+
+%%====================================================================
+%% Internal functions - Device Auth
+%%====================================================================
+
+%% @private
+%% Initiate OAuth device authorization flow.
+%% Prompts user, optionally opens the browser for user authentication,
+%% polls for token completion, and persists tokens via callback on success.
+-spec device_auth(callbacks(), r3_hex_core:config(), binary(), opts()) ->
+ {ok, oauth_tokens()} | {error, auth_error()}.
+device_auth(Callbacks, Config, Scope, Opts) ->
+ ClientId = call_callback(Callbacks, get_client_id, []),
+ OpenBrowser = proplists:get_value(oauth_open_browser, Opts, true),
+ PromptUser = fun(VerificationUri, UserCode) ->
+ io:format("Open ~ts in your browser and enter code: ~ts~n", [VerificationUri, UserCode])
+ end,
+ FlowOpts = [{open_browser, OpenBrowser}],
+ case r3_hex_api_oauth:device_auth_flow(Config, ClientId, Scope, PromptUser, FlowOpts) of
+ {ok, #{access_token := AccessToken, refresh_token := RefreshToken, expires_at := ExpiresAt}} ->
+ ok = call_callback(Callbacks, persist_oauth_tokens, [
+ global, AccessToken, RefreshToken, ExpiresAt
+ ]),
+ {ok, #{
+ access_token => AccessToken,
+ refresh_token => RefreshToken,
+ expires_at => ExpiresAt
+ }};
+ {error, timeout} ->
+ {error, {auth_error, device_auth_timeout}};
+ {error, {access_denied, _Status, _Body}} ->
+ {error, {auth_error, device_auth_denied}};
+ {error, {device_auth_failed, _Status, _Body} = Reason} ->
+ {error, {auth_error, Reason}};
+ {error, {poll_failed, _Status, _Body} = Reason} ->
+ {error, {auth_error, Reason}};
+ {error, Reason} ->
+ {error, {auth_error, Reason}}
+ end.
+
+%% @private
+%% Check if a token is expired (within 5 minute buffer).
+-spec is_token_expired(integer()) -> boolean().
+is_token_expired(ExpiresAt) ->
+ Now = erlang:system_time(second),
+ ExpiresAt - Now < ?EXPIRY_BUFFER_SECONDS.
+
+%%====================================================================
+%% Internal functions - Auth Resolution
+%%====================================================================
+
+%% @private
+-spec resolve_api_auth(callbacks(), permission(), r3_hex_core:config()) ->
+ {ok, binary(), auth_context()} | {error, no_auth} | {error, auth_error()}.
+resolve_api_auth(_Callbacks, _Permission, #{api_key := ApiKey}) when is_binary(ApiKey) ->
+ %% api_key already in config, pass through directly
+ {ok, ApiKey, #{source => config, has_refresh_token => false}};
+resolve_api_auth(Callbacks, _Permission, Config) ->
+ RepoName = repo_name(Config),
+ %% 1. Check per-repo api_key
+ case call_callback(Callbacks, get_auth_config, [RepoName]) of
+ #{api_key := ApiKey} when is_binary(ApiKey) ->
+ {ok, ApiKey, #{source => config, has_refresh_token => false}};
+ _ ->
+ %% 2. Check parent repo (for "hexpm:org" organizations)
+ case get_parent_repo_key(Callbacks, RepoName, api_key) of
+ {ok, ApiKey} ->
+ {ok, ApiKey, #{source => config, has_refresh_token => false}};
+ error ->
+ %% 3. Try global OAuth token
+ resolve_oauth_token_with_context(Callbacks, Config)
+ end
+ end.
+
+%% @private
+%% Resolve repo auth credentials in this order:
+%% 0. repo_key in config => passthrough
+%% 1. repo_key from get_auth_config => passthrough
+%% 2. trusted + auth_key + oauth_exchange => exchange for OAuth token
+%% 3. trusted + auth_key => use directly
+%% 4. trusted + global OAuth tokens => use those
+%% 5. Fallthrough to no_auth (handled by with_repo/4 for optional/auth_inline)
+-spec resolve_repo_auth(callbacks(), r3_hex_core:config()) ->
+ {ok, binary(), auth_context()} | no_auth | {error, auth_error()}.
+resolve_repo_auth(_Callbacks, #{repo_key := RepoKey}) when is_binary(RepoKey) ->
+ %% repo_key already in config, pass through directly
+ {ok, RepoKey, #{source => config, has_refresh_token => false}};
+resolve_repo_auth(Callbacks, Config) ->
+ RepoName = repo_name(Config),
+ global:trans(
+ {{?MODULE, repo}, RepoName},
+ fun() ->
+ do_resolve_repo_auth(Callbacks, RepoName, RepoName, Config)
+ end,
+ [],
+ infinity
+ ).
+
+do_resolve_repo_auth(Callbacks, RepoName, LookupRepo, Config) ->
+ Trusted = maps:get(trusted, Config, false),
+ OAuthExchange = maps:get(oauth_exchange, Config, false),
+ case call_callback(Callbacks, get_auth_config, [LookupRepo]) of
+ #{repo_key := RepoKey} when is_binary(RepoKey) ->
+ %% 1. repo_key from get_auth_config => passthrough
+ {ok, RepoKey, #{source => config, has_refresh_token => false}};
+ #{oauth_token := OAuthToken, auth_key := AuthKey} when
+ is_binary(AuthKey) and OAuthExchange, Trusted
+ ->
+ %% 2. trusted + oauth_token + auth_key + oauth_exchange => use/refresh existing token
+ resolve_repo_oauth_token(Callbacks, RepoName, Config, AuthKey, OAuthToken);
+ #{auth_key := AuthKey} when is_binary(AuthKey) and OAuthExchange, Trusted ->
+ %% 3. trusted + auth_key + oauth_exchange => exchange for new OAuth token
+ exchange_for_oauth_token(Callbacks, RepoName, Config, AuthKey, <<"repositories">>);
+ #{auth_key := AuthKey} when is_binary(AuthKey), Trusted ->
+ %% 4. trusted + auth_key => use directly
+ {ok, AuthKey, #{source => config, has_refresh_token => false}};
+ _ when Trusted ->
+ %% 5. Check parent repo (for "hexpm:org" organizations)
+ case binary:split(LookupRepo, <<":">>) of
+ [ParentName, _OrgName] ->
+ do_resolve_repo_auth(Callbacks, RepoName, ParentName, Config);
+ _ ->
+ %% 6. trusted + global OAuth tokens => use those
+ resolve_global_oauth_for_repo(Callbacks, Config)
+ end;
+ _ ->
+ %% 7. Not trusted, no auth
+ no_auth
+ end.
+
+%% @private
+resolve_global_oauth_for_repo(Callbacks, Config) ->
+ case resolve_oauth_token_with_context(Callbacks, Config) of
+ {ok, Token, AuthContext} ->
+ {ok, Token, AuthContext};
+ {error, no_auth} ->
+ no_auth;
+ {error, _} = Error ->
+ Error
+ end.
+
+%% @private
+%% Resolve repo OAuth token: use if valid, re-exchange if expiring.
+resolve_repo_oauth_token(Callbacks, RepoName, Config, AuthKey, #{
+ access_token := AccessToken, expires_at := ExpiresAt
+}) ->
+ case is_token_expired(ExpiresAt) of
+ false ->
+ %% Token is still valid, use it
+ BearerToken = <<"Bearer ", AccessToken/binary>>,
+ {ok, BearerToken, #{source => oauth, has_refresh_token => false}};
+ true ->
+ %% Token expired, do a new exchange
+ exchange_for_oauth_token(Callbacks, RepoName, Config, AuthKey, <<"repositories">>)
+ end.
+
+%% @private
+%% Exchange api_key/auth_key for OAuth token via client credentials grant.
+%% Persists the token with the repo name for per-repo token storage.
+exchange_for_oauth_token(Callbacks, RepoName, Config, AuthKey, Scope) ->
+ ClientId = call_callback(Callbacks, get_client_id, []),
+ ExchangeConfig =
+ case maps:get(oauth_exchange_url, Config, undefined) of
+ undefined -> Config;
+ OAuthUrl -> Config#{api_url => OAuthUrl}
+ end,
+ case r3_hex_api_oauth:client_credentials_token(ExchangeConfig, ClientId, AuthKey, Scope) of
+ {ok, {200, _, #{<<"access_token">> := AccessToken, <<"expires_in">> := ExpiresIn}}} ->
+ ExpiresAt = erlang:system_time(second) + ExpiresIn,
+ ok = call_callback(Callbacks, persist_oauth_tokens, [
+ RepoName, AccessToken, undefined, ExpiresAt
+ ]),
+ BearerToken = <<"Bearer ", AccessToken/binary>>,
+ {ok, BearerToken, #{source => oauth, has_refresh_token => false}};
+ {ok, {_Status, _, _Body}} ->
+ {error, {auth_error, oauth_exchange_failed}};
+ {error, _} ->
+ {error, {auth_error, oauth_exchange_failed}}
+ end.
+
+%% @private
+get_parent_repo_key(Callbacks, RepoName, KeyType) ->
+ case binary:split(RepoName, <<":">>) of
+ [ParentName, _OrgName] ->
+ case call_callback(Callbacks, get_auth_config, [ParentName]) of
+ #{KeyType := Key} when is_binary(Key) ->
+ {ok, Key};
+ _ ->
+ error
+ end;
+ _ ->
+ error
+ end.
+
+%% @private
+%% Resolve OAuth token with global lock to prevent concurrent refresh attempts.
+resolve_oauth_token_with_context(Callbacks, Config) ->
+ global:trans(
+ {{?MODULE, token_refresh}, self()},
+ fun() ->
+ do_resolve_oauth_token_with_context(Callbacks, Config)
+ end,
+ [],
+ infinity
+ ).
+
+%% @private
+do_resolve_oauth_token_with_context(Callbacks, Config) ->
+ case call_callback(Callbacks, get_oauth_tokens, []) of
+ {ok, #{access_token := AccessToken, expires_at := ExpiresAt} = Tokens} ->
+ HasRefreshToken =
+ maps:is_key(refresh_token, Tokens) andalso
+ is_binary(maps:get(refresh_token, Tokens)),
+ case is_token_expired(ExpiresAt) of
+ true ->
+ maybe_refresh_token_with_context(Callbacks, Config, Tokens);
+ false ->
+ BearerToken = <<"Bearer ", AccessToken/binary>>,
+ {ok, BearerToken, #{source => oauth, has_refresh_token => HasRefreshToken}}
+ end;
+ error ->
+ {error, no_auth}
+ end.
+
+%% @private
+maybe_refresh_token_with_context(Callbacks, Config, #{refresh_token := RefreshToken}) when
+ is_binary(RefreshToken)
+->
+ ClientId = call_callback(Callbacks, get_client_id, []),
+ case r3_hex_api_oauth:refresh_token(Config, ClientId, RefreshToken) of
+ {ok, {200, _, TokenResponse}} when is_map(TokenResponse) ->
+ #{
+ <<"access_token">> := NewAccessToken,
+ <<"expires_in">> := ExpiresIn
+ } = TokenResponse,
+ NewRefreshToken = maps:get(<<"refresh_token">>, TokenResponse, RefreshToken),
+ ExpiresAt = erlang:system_time(second) + ExpiresIn,
+ ok = call_callback(Callbacks, persist_oauth_tokens, [
+ global, NewAccessToken, NewRefreshToken, ExpiresAt
+ ]),
+ BearerToken = <<"Bearer ", NewAccessToken/binary>>,
+ HasRefreshToken = is_binary(NewRefreshToken),
+ {ok, BearerToken, #{source => oauth, has_refresh_token => HasRefreshToken}};
+ {ok, {_Status, _, _Body}} ->
+ {error, {auth_error, token_refresh_failed}};
+ {error, _Reason} ->
+ {error, {auth_error, token_refresh_failed}}
+ end;
+maybe_refresh_token_with_context(_Callbacks, _Config, _Tokens) ->
+ {error, {auth_error, token_refresh_failed}}.
+
+%%====================================================================
+%% Internal functions - Retry Logic
+%%====================================================================
+
+%% @private
+execute_with_retry(Callbacks, Config, Fun, AuthContext, OtpRetries, LastOtpError, Opts) ->
+ case Fun(Config) of
+ {error, otp_required} ->
+ handle_otp_retry(
+ Callbacks, Config, Fun, AuthContext, OtpRetries, <<"Enter OTP code:">>, Opts
+ );
+ {error, invalid_totp} ->
+ handle_otp_retry(
+ Callbacks,
+ Config,
+ Fun,
+ AuthContext,
+ OtpRetries,
+ <<"Invalid OTP code. Please try again:">>,
+ Opts
+ );
+ {ok, {401, Headers, _Body}} = Response ->
+ case detect_auth_error(Headers) of
+ otp_required ->
+ handle_otp_retry(
+ Callbacks, Config, Fun, AuthContext, OtpRetries, <<"Enter OTP code:">>, Opts
+ );
+ invalid_totp ->
+ Msg =
+ case LastOtpError of
+ invalid_totp -> <<"Invalid OTP code. Please try again:">>;
+ _ -> <<"Enter OTP code:">>
+ end,
+ handle_otp_retry(Callbacks, Config, Fun, AuthContext, OtpRetries, Msg, Opts);
+ token_expired ->
+ handle_token_refresh_retry(Callbacks, Config, Fun, AuthContext, Opts);
+ none ->
+ Response
+ end;
+ Other ->
+ Other
+ end.
+
+%% @private
+handle_otp_retry(_Callbacks, _Config, _Fun, _AuthContext, OtpRetries, _Message, _Opts) when
+ OtpRetries >= ?MAX_OTP_RETRIES
+->
+ {error, {auth_error, otp_max_retries}};
+handle_otp_retry(Callbacks, Config, Fun, AuthContext, OtpRetries, Message, Opts) ->
+ case call_callback(Callbacks, prompt_otp, [Message]) of
+ {ok, OtpCode} ->
+ NewConfig = Config#{api_otp => OtpCode},
+ execute_with_retry(
+ Callbacks, NewConfig, Fun, AuthContext, OtpRetries + 1, invalid_totp, Opts
+ );
+ cancelled ->
+ {error, {auth_error, otp_cancelled}}
+ end.
+
+%% @private
+handle_token_refresh_retry(Callbacks, Config, Fun, AuthContext, Opts) ->
+ %% Only attempt refresh if we have a refresh token
+ case maps:get(has_refresh_token, AuthContext, false) of
+ true ->
+ case resolve_oauth_token_with_context(Callbacks, Config) of
+ {ok, NewBearerToken, NewAuthContext} ->
+ NewConfig = Config#{api_key => NewBearerToken},
+ execute_with_retry(
+ Callbacks, NewConfig, Fun, NewAuthContext, 0, undefined, Opts
+ );
+ {error, _} ->
+ maybe_reauthenticate(Callbacks, Config, Fun, Opts)
+ end;
+ false ->
+ maybe_reauthenticate(Callbacks, Config, Fun, Opts)
+ end.
+
+%% @private
+%% After token refresh failure, prompt the user to re-authenticate via device auth
+%% (only when auth_inline is true). Mirrors Hex.OAuth.reauthenticate/1.
+maybe_reauthenticate(Callbacks, Config, Fun, Opts) ->
+ AuthInline = proplists:get_value(auth_inline, Opts, true),
+ case AuthInline of
+ true ->
+ maybe_authenticate_and_retry(Callbacks, Config, Fun, token_refresh_failed, Opts);
+ false ->
+ {error, {auth_error, token_refresh_failed}}
+ end.
+
+%% @private
+-spec detect_auth_error(r3_hex_http:headers()) -> otp_required | invalid_totp | token_expired | none.
+detect_auth_error(Headers) ->
+ case maps:get(<<"www-authenticate">>, Headers, undefined) of
+ undefined ->
+ none;
+ Value ->
+ parse_www_authenticate(Value)
+ end.
+
+%% @private
+parse_www_authenticate(Value) when is_binary(Value) ->
+ case Value of
+ <<"Bearer realm=\"hex\", error=\"totp_required\"", _/binary>> ->
+ otp_required;
+ <<"Bearer realm=\"hex\", error=\"invalid_totp\"", _/binary>> ->
+ invalid_totp;
+ <<"Bearer realm=\"hex\", error=\"token_expired\"", _/binary>> ->
+ token_expired;
+ _ ->
+ none
+ end.
+
+%%====================================================================
+%% Internal functions - Utilities
+%%====================================================================
+
+%% @private
+call_callback(Callbacks, Name, Args) ->
+ Fun = maps:get(Name, Callbacks),
+ erlang:apply(Fun, Args).
diff --git a/apps/rebar/src/vendored/r3_hex_core.erl b/apps/rebar/src/vendored/r3_hex_core.erl
index 4bcf7f618..81648c5c4 100644
--- a/apps/rebar/src/vendored/r3_hex_core.erl
+++ b/apps/rebar/src/vendored/r3_hex_core.erl
@@ -1,4 +1,4 @@
-%% Vendored from hex_core v0.15.0, do not edit manually
+%% Vendored from hex_core v0.17.0, do not edit manually
%% @doc
%% `hex_core' entrypoint module.
@@ -68,11 +68,21 @@
%% * `tarball_max_uncompressed_size' - Maximum size of uncompressed package tarball, defaults to
%% `134_217_728' (128 MiB). Set to `infinity' to not enforce the limit.
%%
+%% * `tarball_files_root' - Root directory for source files when creating tarballs.
+%% Filesystem source paths must resolve inside this root after following symlinks.
+%% Relative source paths are resolved from this root and absolute source paths must be
+%% inside it (default: `"."').
+%%
%% * `docs_tarball_max_size' - Maximum size of docs tarball, defaults to
%% `16_777_216' (16 MiB). Set to `infinity' to not enforce the limit.
%%
%% * `docs_tarball_max_uncompressed_size' - Maximum size of uncompressed docs tarball, defaults to
%% `134_217_728' (128 MiB). Set to `infinity' to not enforce the limit.
+%%
+%% * `metadata_fields' - Either `all' or a list of metadata.config keys (binaries) to read.
+%% When set to a list, the metadata decoder streams past unrequested fields without
+%% buffering their tokens, which keeps peak memory bounded for packages with very
+%% large fields like `<<"files">>'. Defaults to `all'.
-module(r3_hex_core).
-export([default_config/0]).
@@ -110,10 +120,15 @@
repo_verify => boolean(),
repo_verify_origin => boolean(),
send_100_continue => boolean(),
+ tarball_files_root => file:filename(),
tarball_max_size => pos_integer() | infinity,
tarball_max_uncompressed_size => pos_integer() | infinity,
docs_tarball_max_size => pos_integer() | infinity,
- docs_tarball_max_uncompressed_size => pos_integer() | infinity
+ docs_tarball_max_uncompressed_size => pos_integer() | infinity,
+ metadata_fields => all | [binary()],
+ trusted => boolean(),
+ oauth_exchange => boolean(),
+ oauth_exchange_url => binary() | undefined
}.
-spec default_config() -> config().
@@ -136,8 +151,13 @@ default_config() ->
repo_verify => true,
repo_verify_origin => true,
send_100_continue => true,
+ tarball_files_root => ".",
tarball_max_size => 16 * 1024 * 1024,
tarball_max_uncompressed_size => 128 * 1024 * 1024,
docs_tarball_max_size => 16 * 1024 * 1024,
- docs_tarball_max_uncompressed_size => 128 * 1024 * 1024
+ docs_tarball_max_uncompressed_size => 128 * 1024 * 1024,
+ metadata_fields => all,
+ trusted => true,
+ oauth_exchange => true,
+ oauth_exchange_url => undefined
}.
diff --git a/apps/rebar/src/vendored/r3_hex_core.hrl b/apps/rebar/src/vendored/r3_hex_core.hrl
index 43bc6f9f9..47b0e8bcb 100644
--- a/apps/rebar/src/vendored/r3_hex_core.hrl
+++ b/apps/rebar/src/vendored/r3_hex_core.hrl
@@ -1,3 +1,3 @@
-%% Vendored from hex_core v0.15.0, do not edit manually
+%% Vendored from hex_core v0.17.0, do not edit manually
--define(HEX_CORE_VERSION, "0.15.0").
+-define(HEX_CORE_VERSION, "0.17.0").
diff --git a/apps/rebar/src/vendored/r3_hex_erl_tar.erl b/apps/rebar/src/vendored/r3_hex_erl_tar.erl
index fd8bf486e..b4a8e7ebe 100644
--- a/apps/rebar/src/vendored/r3_hex_erl_tar.erl
+++ b/apps/rebar/src/vendored/r3_hex_erl_tar.erl
@@ -1,4 +1,4 @@
-%% Vendored from hex_core v0.15.0, do not edit manually
+%% Vendored from hex_core v0.17.0, do not edit manually
%% This file is a copy of erl_tar.erl from OTP with the following modifications:
%% 1. Module renamed from erl_tar to r3_hex_erl_tar
diff --git a/apps/rebar/src/vendored/r3_hex_erl_tar.hrl b/apps/rebar/src/vendored/r3_hex_erl_tar.hrl
index 7b617350b..dc1b81276 100644
--- a/apps/rebar/src/vendored/r3_hex_erl_tar.hrl
+++ b/apps/rebar/src/vendored/r3_hex_erl_tar.hrl
@@ -1,4 +1,4 @@
-%% Vendored from hex_core v0.15.0, do not edit manually
+%% Vendored from hex_core v0.17.0, do not edit manually
%% This file is a copy of erl_tar.hrl from OTP with the following modifications:
%% 1. Added chunk_size field to #read_opts{} for streaming extraction to disk
diff --git a/apps/rebar/src/vendored/r3_hex_http.erl b/apps/rebar/src/vendored/r3_hex_http.erl
index 3b53974ee..6adf34c7e 100644
--- a/apps/rebar/src/vendored/r3_hex_http.erl
+++ b/apps/rebar/src/vendored/r3_hex_http.erl
@@ -1,4 +1,4 @@
-%% Vendored from hex_core v0.15.0, do not edit manually
+%% Vendored from hex_core v0.17.0, do not edit manually
%% @doc
%% HTTP contract.
diff --git a/apps/rebar/src/vendored/r3_hex_http_httpc.erl b/apps/rebar/src/vendored/r3_hex_http_httpc.erl
index 335776e43..1eb8e960c 100644
--- a/apps/rebar/src/vendored/r3_hex_http_httpc.erl
+++ b/apps/rebar/src/vendored/r3_hex_http_httpc.erl
@@ -1,4 +1,4 @@
-%% Vendored from hex_core v0.15.0, do not edit manually
+%% Vendored from hex_core v0.17.0, do not edit manually
%% @doc
%% httpc-based implementation of {@link r3_hex_http} contract.
@@ -41,15 +41,12 @@ request_to_file(Method, URI, ReqHeaders, Body, Filename, AdapterConfig) when is_
Method,
Request,
HTTPOptions,
- [{stream, unicode:characters_to_list(Filename)}],
+ [{sync, false}, {stream, self}],
Profile
)
of
- {ok, saved_to_file} ->
- {ok, {200, #{}}};
- {ok, {{_, StatusCode, _}, RespHeaders, _RespBody}} ->
- RespHeaders2 = load_headers(RespHeaders),
- {ok, {StatusCode, RespHeaders2}};
+ {ok, RequestId} ->
+ stream_to_file(RequestId, Filename);
{error, Reason} ->
{error, Reason}
end.
@@ -58,6 +55,39 @@ request_to_file(Method, URI, ReqHeaders, Body, Filename, AdapterConfig) when is_
%% Internal functions
%%====================================================================
+%% @private
+%% httpc streams 200/206 responses as messages and returns non-2xx as
+%% a normal response tuple. stream_start includes the response headers.
+stream_to_file(RequestId, Filename) ->
+ receive
+ {http, {RequestId, stream_start, Headers}} ->
+ {ok, File} = file:open(Filename, [write, binary]),
+ case stream_body(RequestId, File) of
+ ok ->
+ ok = file:close(File),
+ {ok, {200, load_headers(Headers)}};
+ {error, Reason} ->
+ ok = file:close(File),
+ {error, Reason}
+ end;
+ {http, {RequestId, {{_, StatusCode, _}, RespHeaders, _RespBody}}} ->
+ {ok, {StatusCode, load_headers(RespHeaders)}};
+ {http, {RequestId, {error, Reason}}} ->
+ {error, Reason}
+ end.
+
+%% @private
+stream_body(RequestId, File) ->
+ receive
+ {http, {RequestId, stream, BinBodyPart}} ->
+ ok = file:write(File, BinBodyPart),
+ stream_body(RequestId, File);
+ {http, {RequestId, stream_end, _Headers}} ->
+ ok;
+ {http, {RequestId, {error, Reason}}} ->
+ {error, Reason}
+ end.
+
%% @private
http_options(URI, AdapterConfig) ->
HTTPOptions0 = maps:get(http_options, AdapterConfig, []),
diff --git a/apps/rebar/src/vendored/r3_hex_licenses.erl b/apps/rebar/src/vendored/r3_hex_licenses.erl
index 2abe803b6..6e429e9f8 100644
--- a/apps/rebar/src/vendored/r3_hex_licenses.erl
+++ b/apps/rebar/src/vendored/r3_hex_licenses.erl
@@ -1,4 +1,4 @@
-%% Vendored from hex_core v0.15.0, do not edit manually
+%% Vendored from hex_core v0.17.0, do not edit manually
%% @doc
%% Hex Licenses.
@@ -667,4 +667,30 @@ valid(<<"xlock">>) -> true;
valid(<<"xpp">>) -> true;
valid(<<"xzoom">>) -> true;
valid(<<"zlib-acknowledgement">>) -> true;
+valid(<<"LicenseRef-", IdString/binary>>) -> valid_license_ref_idstring(IdString);
valid(_) -> false.
+
+valid_license_ref_idstring(<<>>) ->
+ false;
+valid_license_ref_idstring(IdString) ->
+ valid_license_ref_idstring(IdString, true).
+
+valid_license_ref_idstring(<<>>, Valid) ->
+ Valid;
+valid_license_ref_idstring(_, false) ->
+ false;
+valid_license_ref_idstring(<>, true) ->
+ valid_license_ref_idstring(Rest, valid_license_ref_char(Char)).
+
+valid_license_ref_char(Char) when Char >= $A, Char =< $Z ->
+ true;
+valid_license_ref_char(Char) when Char >= $a, Char =< $z ->
+ true;
+valid_license_ref_char(Char) when Char >= $0, Char =< $9 ->
+ true;
+valid_license_ref_char($-) ->
+ true;
+valid_license_ref_char($.) ->
+ true;
+valid_license_ref_char(_) ->
+ false.
diff --git a/apps/rebar/src/vendored/r3_hex_pb_names.erl b/apps/rebar/src/vendored/r3_hex_pb_names.erl
index 8c2c940fe..473580102 100644
--- a/apps/rebar/src/vendored/r3_hex_pb_names.erl
+++ b/apps/rebar/src/vendored/r3_hex_pb_names.erl
@@ -1,4 +1,4 @@
-%% Vendored from hex_core v0.15.0, do not edit manually
+%% Vendored from hex_core v0.17.0, do not edit manually
%% -*- coding: utf-8 -*-
%% % this file is @generated
diff --git a/apps/rebar/src/vendored/r3_hex_pb_package.erl b/apps/rebar/src/vendored/r3_hex_pb_package.erl
index 656f32ec8..d2ecfed99 100644
--- a/apps/rebar/src/vendored/r3_hex_pb_package.erl
+++ b/apps/rebar/src/vendored/r3_hex_pb_package.erl
@@ -1,4 +1,4 @@
-%% Vendored from hex_core v0.15.0, do not edit manually
+%% Vendored from hex_core v0.17.0, do not edit manually
%% -*- coding: utf-8 -*-
%% % this file is @generated
@@ -21,6 +21,7 @@
-export([find_enum_def/1, fetch_enum_def/1]).
-export([enum_symbol_by_value/2, enum_value_by_symbol/2]).
-export([enum_symbol_by_value_RetirementReason/1, enum_value_by_symbol_RetirementReason/1]).
+-export([enum_symbol_by_value_AdvisorySeverity/1, enum_value_by_symbol_AdvisorySeverity/1]).
-export([get_service_names/0]).
-export([get_service_def/1]).
-export([get_rpc_names/1]).
@@ -53,13 +54,15 @@
%% enumerated types
-type 'RetirementReason'() :: 'RETIRED_OTHER' | 'RETIRED_INVALID' | 'RETIRED_SECURITY' | 'RETIRED_DEPRECATED' | 'RETIRED_RENAMED'.
--export_type(['RetirementReason'/0]).
+-type 'AdvisorySeverity'() :: 'SEVERITY_NONE' | 'SEVERITY_LOW' | 'SEVERITY_MEDIUM' | 'SEVERITY_HIGH' | 'SEVERITY_CRITICAL'.
+-export_type(['RetirementReason'/0, 'AdvisorySeverity'/0]).
%% message types
-type 'Package'() ::
#{releases => ['Release'()], % = 1, repeated
name => unicode:chardata(), % = 2, required
- repository => unicode:chardata() % = 3, required
+ repository => unicode:chardata(), % = 3, required
+ advisories => ['SecurityAdvisory'()] % = 4, repeated
}.
-type 'Release'() ::
@@ -67,7 +70,9 @@
inner_checksum => iodata(), % = 2, required
dependencies => ['Dependency'()], % = 3, repeated
retired => 'RetirementStatus'(), % = 4, optional
- outer_checksum => iodata() % = 5, optional
+ outer_checksum => iodata(), % = 5, optional
+ advisory_indexes => [non_neg_integer()], % = 6, repeated, 32 bits
+ published_at => 'Timestamp'() % = 7, optional
}.
-type 'RetirementStatus'() ::
@@ -75,6 +80,16 @@
message => unicode:chardata() % = 2, optional
}.
+-type 'SecurityAdvisory'() ::
+ #{id => unicode:chardata(), % = 1, required
+ summary => unicode:chardata(), % = 2, required
+ html_url => unicode:chardata(), % = 3, required
+ severity => 'SEVERITY_NONE' | 'SEVERITY_LOW' | 'SEVERITY_MEDIUM' | 'SEVERITY_HIGH' | 'SEVERITY_CRITICAL' | integer(), % = 4, optional, enum AdvisorySeverity
+ cvss_score => float() | integer() | infinity | '-infinity' | nan, % = 5, optional
+ api_url => unicode:chardata(), % = 6, required
+ aliases => [unicode:chardata()] % = 7, repeated
+ }.
+
-type 'Dependency'() ::
#{package => unicode:chardata(), % = 1, required
requirement => unicode:chardata(), % = 2, required
@@ -83,9 +98,14 @@
repository => unicode:chardata() % = 5, optional
}.
--export_type(['Package'/0, 'Release'/0, 'RetirementStatus'/0, 'Dependency'/0]).
--type '$msg_name'() :: 'Package' | 'Release' | 'RetirementStatus' | 'Dependency'.
--type '$msg'() :: 'Package'() | 'Release'() | 'RetirementStatus'() | 'Dependency'().
+-type 'Timestamp'() ::
+ #{seconds => integer(), % = 1, required, 64 bits
+ nanos => integer() % = 2, required, 32 bits
+ }.
+
+-export_type(['Package'/0, 'Release'/0, 'RetirementStatus'/0, 'SecurityAdvisory'/0, 'Dependency'/0, 'Timestamp'/0]).
+-type '$msg_name'() :: 'Package' | 'Release' | 'RetirementStatus' | 'SecurityAdvisory' | 'Dependency' | 'Timestamp'.
+-type '$msg'() :: 'Package'() | 'Release'() | 'RetirementStatus'() | 'SecurityAdvisory'() | 'Dependency'() | 'Timestamp'().
-export_type(['$msg_name'/0, '$msg'/0]).
-if(?OTP_RELEASE >= 24).
@@ -105,7 +125,9 @@ encode_msg(Msg, MsgName, Opts) ->
'Package' -> encode_msg_Package(id(Msg, TrUserData), TrUserData);
'Release' -> encode_msg_Release(id(Msg, TrUserData), TrUserData);
'RetirementStatus' -> encode_msg_RetirementStatus(id(Msg, TrUserData), TrUserData);
- 'Dependency' -> encode_msg_Dependency(id(Msg, TrUserData), TrUserData)
+ 'SecurityAdvisory' -> encode_msg_SecurityAdvisory(id(Msg, TrUserData), TrUserData);
+ 'Dependency' -> encode_msg_Dependency(id(Msg, TrUserData), TrUserData);
+ 'Timestamp' -> encode_msg_Timestamp(id(Msg, TrUserData), TrUserData)
end.
@@ -122,7 +144,15 @@ encode_msg_Package(#{name := F2, repository := F3} = M, Bin, TrUserData) ->
_ -> Bin
end,
B2 = begin TrF2 = id(F2, TrUserData), e_type_string(TrF2, <>, TrUserData) end,
- begin TrF3 = id(F3, TrUserData), e_type_string(TrF3, <>, TrUserData) end.
+ B3 = begin TrF3 = id(F3, TrUserData), e_type_string(TrF3, <>, TrUserData) end,
+ case M of
+ #{advisories := F4} ->
+ TrF4 = id(F4, TrUserData),
+ if TrF4 == [] -> B3;
+ true -> e_field_Package_advisories(TrF4, B3, TrUserData)
+ end;
+ _ -> B3
+ end.
encode_msg_Release(Msg, TrUserData) -> encode_msg_Release(Msg, <<>>, TrUserData).
@@ -142,9 +172,21 @@ encode_msg_Release(#{version := F1, inner_checksum := F2} = M, Bin, TrUserData)
#{retired := F4} -> begin TrF4 = id(F4, TrUserData), e_mfield_Release_retired(TrF4, <>, TrUserData) end;
_ -> B3
end,
+ B5 = case M of
+ #{outer_checksum := F5} -> begin TrF5 = id(F5, TrUserData), e_type_bytes(TrF5, <>, TrUserData) end;
+ _ -> B4
+ end,
+ B6 = case M of
+ #{advisory_indexes := F6} ->
+ TrF6 = id(F6, TrUserData),
+ if TrF6 == [] -> B5;
+ true -> e_field_Release_advisory_indexes(TrF6, B5, TrUserData)
+ end;
+ _ -> B5
+ end,
case M of
- #{outer_checksum := F5} -> begin TrF5 = id(F5, TrUserData), e_type_bytes(TrF5, <>, TrUserData) end;
- _ -> B4
+ #{published_at := F7} -> begin TrF7 = id(F7, TrUserData), e_mfield_Release_published_at(TrF7, <>, TrUserData) end;
+ _ -> B6
end.
encode_msg_RetirementStatus(Msg, TrUserData) -> encode_msg_RetirementStatus(Msg, <<>>, TrUserData).
@@ -157,6 +199,31 @@ encode_msg_RetirementStatus(#{reason := F1} = M, Bin, TrUserData) ->
_ -> B1
end.
+encode_msg_SecurityAdvisory(Msg, TrUserData) -> encode_msg_SecurityAdvisory(Msg, <<>>, TrUserData).
+
+
+encode_msg_SecurityAdvisory(#{id := F1, summary := F2, html_url := F3, api_url := F6} = M, Bin, TrUserData) ->
+ B1 = begin TrF1 = id(F1, TrUserData), e_type_string(TrF1, <>, TrUserData) end,
+ B2 = begin TrF2 = id(F2, TrUserData), e_type_string(TrF2, <>, TrUserData) end,
+ B3 = begin TrF3 = id(F3, TrUserData), e_type_string(TrF3, <>, TrUserData) end,
+ B4 = case M of
+ #{severity := F4} -> begin TrF4 = id(F4, TrUserData), e_enum_AdvisorySeverity(TrF4, <>, TrUserData) end;
+ _ -> B3
+ end,
+ B5 = case M of
+ #{cvss_score := F5} -> begin TrF5 = id(F5, TrUserData), e_type_float(TrF5, <>, TrUserData) end;
+ _ -> B4
+ end,
+ B6 = begin TrF6 = id(F6, TrUserData), e_type_string(TrF6, <>, TrUserData) end,
+ case M of
+ #{aliases := F7} ->
+ TrF7 = id(F7, TrUserData),
+ if TrF7 == [] -> B6;
+ true -> e_field_SecurityAdvisory_aliases(TrF7, B6, TrUserData)
+ end;
+ _ -> B6
+ end.
+
encode_msg_Dependency(Msg, TrUserData) -> encode_msg_Dependency(Msg, <<>>, TrUserData).
@@ -176,6 +243,13 @@ encode_msg_Dependency(#{package := F1, requirement := F2} = M, Bin, TrUserData)
_ -> B4
end.
+encode_msg_Timestamp(Msg, TrUserData) -> encode_msg_Timestamp(Msg, <<>>, TrUserData).
+
+
+encode_msg_Timestamp(#{seconds := F1, nanos := F2}, Bin, TrUserData) ->
+ B1 = begin TrF1 = id(F1, TrUserData), e_type_int64(TrF1, <>, TrUserData) end,
+ begin TrF2 = id(F2, TrUserData), e_type_int32(TrF2, <>, TrUserData) end.
+
e_mfield_Package_releases(Msg, Bin, TrUserData) ->
SubBin = encode_msg_Release(Msg, <<>>, TrUserData),
Bin2 = e_varint(byte_size(SubBin), Bin),
@@ -187,6 +261,17 @@ e_field_Package_releases([Elem | Rest], Bin, TrUserData) ->
e_field_Package_releases(Rest, Bin3, TrUserData);
e_field_Package_releases([], Bin, _TrUserData) -> Bin.
+e_mfield_Package_advisories(Msg, Bin, TrUserData) ->
+ SubBin = encode_msg_SecurityAdvisory(Msg, <<>>, TrUserData),
+ Bin2 = e_varint(byte_size(SubBin), Bin),
+ <>.
+
+e_field_Package_advisories([Elem | Rest], Bin, TrUserData) ->
+ Bin2 = <>,
+ Bin3 = e_mfield_Package_advisories(id(Elem, TrUserData), Bin2, TrUserData),
+ e_field_Package_advisories(Rest, Bin3, TrUserData);
+e_field_Package_advisories([], Bin, _TrUserData) -> Bin.
+
e_mfield_Release_dependencies(Msg, Bin, TrUserData) ->
SubBin = encode_msg_Dependency(Msg, <<>>, TrUserData),
Bin2 = e_varint(byte_size(SubBin), Bin),
@@ -203,6 +288,23 @@ e_mfield_Release_retired(Msg, Bin, TrUserData) ->
Bin2 = e_varint(byte_size(SubBin), Bin),
<>.
+e_field_Release_advisory_indexes([Elem | Rest], Bin, TrUserData) ->
+ Bin2 = <>,
+ Bin3 = e_varint(id(Elem, TrUserData), Bin2, TrUserData),
+ e_field_Release_advisory_indexes(Rest, Bin3, TrUserData);
+e_field_Release_advisory_indexes([], Bin, _TrUserData) -> Bin.
+
+e_mfield_Release_published_at(Msg, Bin, TrUserData) ->
+ SubBin = encode_msg_Timestamp(Msg, <<>>, TrUserData),
+ Bin2 = e_varint(byte_size(SubBin), Bin),
+ <>.
+
+e_field_SecurityAdvisory_aliases([Elem | Rest], Bin, TrUserData) ->
+ Bin2 = <>,
+ Bin3 = e_type_string(id(Elem, TrUserData), Bin2, TrUserData),
+ e_field_SecurityAdvisory_aliases(Rest, Bin3, TrUserData);
+e_field_SecurityAdvisory_aliases([], Bin, _TrUserData) -> Bin.
+
e_enum_RetirementReason('RETIRED_OTHER', Bin, _TrUserData) -> <>;
e_enum_RetirementReason('RETIRED_INVALID', Bin, _TrUserData) -> <>;
e_enum_RetirementReason('RETIRED_SECURITY', Bin, _TrUserData) -> <>;
@@ -210,6 +312,13 @@ e_enum_RetirementReason('RETIRED_DEPRECATED', Bin, _TrUserData) -> < <>;
e_enum_RetirementReason(V, Bin, _TrUserData) -> e_varint(V, Bin).
+e_enum_AdvisorySeverity('SEVERITY_NONE', Bin, _TrUserData) -> <>;
+e_enum_AdvisorySeverity('SEVERITY_LOW', Bin, _TrUserData) -> <>;
+e_enum_AdvisorySeverity('SEVERITY_MEDIUM', Bin, _TrUserData) -> <>;
+e_enum_AdvisorySeverity('SEVERITY_HIGH', Bin, _TrUserData) -> <>;
+e_enum_AdvisorySeverity('SEVERITY_CRITICAL', Bin, _TrUserData) -> <>;
+e_enum_AdvisorySeverity(V, Bin, _TrUserData) -> e_varint(V, Bin).
+
-compile({nowarn_unused_function,e_type_sint/3}).
e_type_sint(Value, Bin, _TrUserData) when Value >= 0 -> e_varint(Value * 2, Bin);
e_type_sint(Value, Bin, _TrUserData) -> e_varint(Value * -2 - 1, Bin).
@@ -335,143 +444,172 @@ decode_msg_1_catch(Bin, MsgName, TrUserData) ->
decode_msg_2_doit('Package', Bin, TrUserData) -> id(decode_msg_Package(Bin, TrUserData), TrUserData);
decode_msg_2_doit('Release', Bin, TrUserData) -> id(decode_msg_Release(Bin, TrUserData), TrUserData);
decode_msg_2_doit('RetirementStatus', Bin, TrUserData) -> id(decode_msg_RetirementStatus(Bin, TrUserData), TrUserData);
-decode_msg_2_doit('Dependency', Bin, TrUserData) -> id(decode_msg_Dependency(Bin, TrUserData), TrUserData).
+decode_msg_2_doit('SecurityAdvisory', Bin, TrUserData) -> id(decode_msg_SecurityAdvisory(Bin, TrUserData), TrUserData);
+decode_msg_2_doit('Dependency', Bin, TrUserData) -> id(decode_msg_Dependency(Bin, TrUserData), TrUserData);
+decode_msg_2_doit('Timestamp', Bin, TrUserData) -> id(decode_msg_Timestamp(Bin, TrUserData), TrUserData).
-decode_msg_Package(Bin, TrUserData) -> dfp_read_field_def_Package(Bin, 0, 0, 0, id([], TrUserData), id('$undef', TrUserData), id('$undef', TrUserData), TrUserData).
+decode_msg_Package(Bin, TrUserData) -> dfp_read_field_def_Package(Bin, 0, 0, 0, id([], TrUserData), id('$undef', TrUserData), id('$undef', TrUserData), id([], TrUserData), TrUserData).
-dfp_read_field_def_Package(<<10, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> d_field_Package_releases(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData);
-dfp_read_field_def_Package(<<18, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> d_field_Package_name(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData);
-dfp_read_field_def_Package(<<26, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> d_field_Package_repository(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData);
-dfp_read_field_def_Package(<<>>, 0, 0, _, R1, F@_2, F@_3, TrUserData) ->
+dfp_read_field_def_Package(<<10, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, TrUserData) -> d_field_Package_releases(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, TrUserData);
+dfp_read_field_def_Package(<<18, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, TrUserData) -> d_field_Package_name(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, TrUserData);
+dfp_read_field_def_Package(<<26, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, TrUserData) -> d_field_Package_repository(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, TrUserData);
+dfp_read_field_def_Package(<<34, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, TrUserData) -> d_field_Package_advisories(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, TrUserData);
+dfp_read_field_def_Package(<<>>, 0, 0, _, R1, F@_2, F@_3, R2, TrUserData) ->
S1 = #{name => F@_2, repository => F@_3},
- if R1 == '$undef' -> S1;
- true -> S1#{releases => lists_reverse(R1, TrUserData)}
+ S2 = if R1 == '$undef' -> S1;
+ true -> S1#{releases => lists_reverse(R1, TrUserData)}
+ end,
+ if R2 == '$undef' -> S2;
+ true -> S2#{advisories => lists_reverse(R2, TrUserData)}
end;
-dfp_read_field_def_Package(Other, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> dg_read_field_def_Package(Other, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData).
+dfp_read_field_def_Package(Other, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, TrUserData) -> dg_read_field_def_Package(Other, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, TrUserData).
-dg_read_field_def_Package(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, TrUserData) when N < 32 - 7 -> dg_read_field_def_Package(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, TrUserData);
-dg_read_field_def_Package(<<0:1, X:7, Rest/binary>>, N, Acc, _, F@_1, F@_2, F@_3, TrUserData) ->
+dg_read_field_def_Package(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, TrUserData) when N < 32 - 7 -> dg_read_field_def_Package(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, TrUserData);
+dg_read_field_def_Package(<<0:1, X:7, Rest/binary>>, N, Acc, _, F@_1, F@_2, F@_3, F@_4, TrUserData) ->
Key = X bsl N + Acc,
case Key of
- 10 -> d_field_Package_releases(Rest, 0, 0, 0, F@_1, F@_2, F@_3, TrUserData);
- 18 -> d_field_Package_name(Rest, 0, 0, 0, F@_1, F@_2, F@_3, TrUserData);
- 26 -> d_field_Package_repository(Rest, 0, 0, 0, F@_1, F@_2, F@_3, TrUserData);
+ 10 -> d_field_Package_releases(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, TrUserData);
+ 18 -> d_field_Package_name(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, TrUserData);
+ 26 -> d_field_Package_repository(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, TrUserData);
+ 34 -> d_field_Package_advisories(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, TrUserData);
_ ->
case Key band 7 of
- 0 -> skip_varint_Package(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, TrUserData);
- 1 -> skip_64_Package(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, TrUserData);
- 2 -> skip_length_delimited_Package(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, TrUserData);
- 3 -> skip_group_Package(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, TrUserData);
- 5 -> skip_32_Package(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, TrUserData)
+ 0 -> skip_varint_Package(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, TrUserData);
+ 1 -> skip_64_Package(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, TrUserData);
+ 2 -> skip_length_delimited_Package(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, TrUserData);
+ 3 -> skip_group_Package(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, TrUserData);
+ 5 -> skip_32_Package(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, TrUserData)
end
end;
-dg_read_field_def_Package(<<>>, 0, 0, _, R1, F@_2, F@_3, TrUserData) ->
+dg_read_field_def_Package(<<>>, 0, 0, _, R1, F@_2, F@_3, R2, TrUserData) ->
S1 = #{name => F@_2, repository => F@_3},
- if R1 == '$undef' -> S1;
- true -> S1#{releases => lists_reverse(R1, TrUserData)}
+ S2 = if R1 == '$undef' -> S1;
+ true -> S1#{releases => lists_reverse(R1, TrUserData)}
+ end,
+ if R2 == '$undef' -> S2;
+ true -> S2#{advisories => lists_reverse(R2, TrUserData)}
end.
-d_field_Package_releases(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, TrUserData) when N < 57 -> d_field_Package_releases(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, TrUserData);
-d_field_Package_releases(<<0:1, X:7, Rest/binary>>, N, Acc, F, Prev, F@_2, F@_3, TrUserData) ->
+d_field_Package_releases(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, TrUserData) when N < 57 -> d_field_Package_releases(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, TrUserData);
+d_field_Package_releases(<<0:1, X:7, Rest/binary>>, N, Acc, F, Prev, F@_2, F@_3, F@_4, TrUserData) ->
{NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, {id(decode_msg_Release(Bs, TrUserData), TrUserData), Rest2} end,
- dfp_read_field_def_Package(RestF, 0, 0, F, cons(NewFValue, Prev, TrUserData), F@_2, F@_3, TrUserData).
+ dfp_read_field_def_Package(RestF, 0, 0, F, cons(NewFValue, Prev, TrUserData), F@_2, F@_3, F@_4, TrUserData).
-d_field_Package_name(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, TrUserData) when N < 57 -> d_field_Package_name(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, TrUserData);
-d_field_Package_name(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, _, F@_3, TrUserData) ->
+d_field_Package_name(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, TrUserData) when N < 57 -> d_field_Package_name(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, TrUserData);
+d_field_Package_name(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, _, F@_3, F@_4, TrUserData) ->
{NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, Bytes2 = binary:copy(Bytes), {id(Bytes2, TrUserData), Rest2} end,
- dfp_read_field_def_Package(RestF, 0, 0, F, F@_1, NewFValue, F@_3, TrUserData).
+ dfp_read_field_def_Package(RestF, 0, 0, F, F@_1, NewFValue, F@_3, F@_4, TrUserData).
-d_field_Package_repository(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, TrUserData) when N < 57 -> d_field_Package_repository(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, TrUserData);
-d_field_Package_repository(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, _, TrUserData) ->
+d_field_Package_repository(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, TrUserData) when N < 57 -> d_field_Package_repository(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, TrUserData);
+d_field_Package_repository(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, _, F@_4, TrUserData) ->
{NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, Bytes2 = binary:copy(Bytes), {id(Bytes2, TrUserData), Rest2} end,
- dfp_read_field_def_Package(RestF, 0, 0, F, F@_1, F@_2, NewFValue, TrUserData).
+ dfp_read_field_def_Package(RestF, 0, 0, F, F@_1, F@_2, NewFValue, F@_4, TrUserData).
+
+d_field_Package_advisories(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, TrUserData) when N < 57 -> d_field_Package_advisories(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, TrUserData);
+d_field_Package_advisories(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, Prev, TrUserData) ->
+ {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, {id(decode_msg_SecurityAdvisory(Bs, TrUserData), TrUserData), Rest2} end,
+ dfp_read_field_def_Package(RestF, 0, 0, F, F@_1, F@_2, F@_3, cons(NewFValue, Prev, TrUserData), TrUserData).
-skip_varint_Package(<<1:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> skip_varint_Package(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData);
-skip_varint_Package(<<0:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> dfp_read_field_def_Package(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData).
+skip_varint_Package(<<1:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, TrUserData) -> skip_varint_Package(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, TrUserData);
+skip_varint_Package(<<0:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, TrUserData) -> dfp_read_field_def_Package(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, TrUserData).
-skip_length_delimited_Package(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, TrUserData) when N < 57 -> skip_length_delimited_Package(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, TrUserData);
-skip_length_delimited_Package(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, TrUserData) ->
+skip_length_delimited_Package(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, TrUserData) when N < 57 -> skip_length_delimited_Package(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, TrUserData);
+skip_length_delimited_Package(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, TrUserData) ->
Length = X bsl N + Acc,
<<_:Length/binary, Rest2/binary>> = Rest,
- dfp_read_field_def_Package(Rest2, 0, 0, F, F@_1, F@_2, F@_3, TrUserData).
+ dfp_read_field_def_Package(Rest2, 0, 0, F, F@_1, F@_2, F@_3, F@_4, TrUserData).
-skip_group_Package(Bin, _, Z2, FNum, F@_1, F@_2, F@_3, TrUserData) ->
+skip_group_Package(Bin, _, Z2, FNum, F@_1, F@_2, F@_3, F@_4, TrUserData) ->
{_, Rest} = read_group(Bin, FNum),
- dfp_read_field_def_Package(Rest, 0, Z2, FNum, F@_1, F@_2, F@_3, TrUserData).
+ dfp_read_field_def_Package(Rest, 0, Z2, FNum, F@_1, F@_2, F@_3, F@_4, TrUserData).
-skip_32_Package(<<_:32, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> dfp_read_field_def_Package(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData).
+skip_32_Package(<<_:32, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, TrUserData) -> dfp_read_field_def_Package(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, TrUserData).
-skip_64_Package(<<_:64, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> dfp_read_field_def_Package(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData).
+skip_64_Package(<<_:64, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, TrUserData) -> dfp_read_field_def_Package(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, TrUserData).
-decode_msg_Release(Bin, TrUserData) -> dfp_read_field_def_Release(Bin, 0, 0, 0, id('$undef', TrUserData), id('$undef', TrUserData), id([], TrUserData), id('$undef', TrUserData), id('$undef', TrUserData), TrUserData).
+decode_msg_Release(Bin, TrUserData) ->
+ dfp_read_field_def_Release(Bin, 0, 0, 0, id('$undef', TrUserData), id('$undef', TrUserData), id([], TrUserData), id('$undef', TrUserData), id('$undef', TrUserData), id([], TrUserData), id('$undef', TrUserData), TrUserData).
-dfp_read_field_def_Release(<<10, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> d_field_Release_version(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData);
-dfp_read_field_def_Release(<<18, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> d_field_Release_inner_checksum(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData);
-dfp_read_field_def_Release(<<26, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> d_field_Release_dependencies(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData);
-dfp_read_field_def_Release(<<34, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> d_field_Release_retired(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData);
-dfp_read_field_def_Release(<<42, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> d_field_Release_outer_checksum(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData);
-dfp_read_field_def_Release(<<>>, 0, 0, _, F@_1, F@_2, R1, F@_4, F@_5, TrUserData) ->
- S1 = #{version => F@_1, inner_checksum => F@_2},
+dfp_read_field_def_Release(<<10, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) -> d_field_Release_version(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData);
+dfp_read_field_def_Release(<<18, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) -> d_field_Release_inner_checksum(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData);
+dfp_read_field_def_Release(<<26, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) -> d_field_Release_dependencies(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData);
+dfp_read_field_def_Release(<<34, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) -> d_field_Release_retired(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData);
+dfp_read_field_def_Release(<<42, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) -> d_field_Release_outer_checksum(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData);
+dfp_read_field_def_Release(<<50, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) -> d_pfield_Release_advisory_indexes(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData);
+dfp_read_field_def_Release(<<48, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) -> d_field_Release_advisory_indexes(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData);
+dfp_read_field_def_Release(<<58, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) -> d_field_Release_published_at(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData);
+dfp_read_field_def_Release(<<>>, 0, 0, _, F@_1, F@_2, R1, F@_4, F@_5, R2, F@_7, TrUserData) ->
+ S1 = #{version => F@_1, inner_checksum => F@_2, advisory_indexes => lists_reverse(R2, TrUserData)},
S2 = if R1 == '$undef' -> S1;
true -> S1#{dependencies => lists_reverse(R1, TrUserData)}
end,
S3 = if F@_4 == '$undef' -> S2;
true -> S2#{retired => F@_4}
end,
- if F@_5 == '$undef' -> S3;
- true -> S3#{outer_checksum => F@_5}
+ S4 = if F@_5 == '$undef' -> S3;
+ true -> S3#{outer_checksum => F@_5}
+ end,
+ if F@_7 == '$undef' -> S4;
+ true -> S4#{published_at => F@_7}
end;
-dfp_read_field_def_Release(Other, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> dg_read_field_def_Release(Other, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData).
+dfp_read_field_def_Release(Other, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) -> dg_read_field_def_Release(Other, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData).
-dg_read_field_def_Release(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) when N < 32 - 7 -> dg_read_field_def_Release(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData);
-dg_read_field_def_Release(<<0:1, X:7, Rest/binary>>, N, Acc, _, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) ->
+dg_read_field_def_Release(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) when N < 32 - 7 -> dg_read_field_def_Release(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData);
+dg_read_field_def_Release(<<0:1, X:7, Rest/binary>>, N, Acc, _, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) ->
Key = X bsl N + Acc,
case Key of
- 10 -> d_field_Release_version(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData);
- 18 -> d_field_Release_inner_checksum(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData);
- 26 -> d_field_Release_dependencies(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData);
- 34 -> d_field_Release_retired(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData);
- 42 -> d_field_Release_outer_checksum(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData);
+ 10 -> d_field_Release_version(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData);
+ 18 -> d_field_Release_inner_checksum(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData);
+ 26 -> d_field_Release_dependencies(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData);
+ 34 -> d_field_Release_retired(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData);
+ 42 -> d_field_Release_outer_checksum(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData);
+ 50 -> d_pfield_Release_advisory_indexes(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData);
+ 48 -> d_field_Release_advisory_indexes(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData);
+ 58 -> d_field_Release_published_at(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData);
_ ->
case Key band 7 of
- 0 -> skip_varint_Release(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData);
- 1 -> skip_64_Release(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData);
- 2 -> skip_length_delimited_Release(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData);
- 3 -> skip_group_Release(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData);
- 5 -> skip_32_Release(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData)
+ 0 -> skip_varint_Release(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData);
+ 1 -> skip_64_Release(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData);
+ 2 -> skip_length_delimited_Release(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData);
+ 3 -> skip_group_Release(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData);
+ 5 -> skip_32_Release(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData)
end
end;
-dg_read_field_def_Release(<<>>, 0, 0, _, F@_1, F@_2, R1, F@_4, F@_5, TrUserData) ->
- S1 = #{version => F@_1, inner_checksum => F@_2},
+dg_read_field_def_Release(<<>>, 0, 0, _, F@_1, F@_2, R1, F@_4, F@_5, R2, F@_7, TrUserData) ->
+ S1 = #{version => F@_1, inner_checksum => F@_2, advisory_indexes => lists_reverse(R2, TrUserData)},
S2 = if R1 == '$undef' -> S1;
true -> S1#{dependencies => lists_reverse(R1, TrUserData)}
end,
S3 = if F@_4 == '$undef' -> S2;
true -> S2#{retired => F@_4}
end,
- if F@_5 == '$undef' -> S3;
- true -> S3#{outer_checksum => F@_5}
+ S4 = if F@_5 == '$undef' -> S3;
+ true -> S3#{outer_checksum => F@_5}
+ end,
+ if F@_7 == '$undef' -> S4;
+ true -> S4#{published_at => F@_7}
end.
-d_field_Release_version(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) when N < 57 -> d_field_Release_version(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData);
-d_field_Release_version(<<0:1, X:7, Rest/binary>>, N, Acc, F, _, F@_2, F@_3, F@_4, F@_5, TrUserData) ->
+d_field_Release_version(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) when N < 57 -> d_field_Release_version(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData);
+d_field_Release_version(<<0:1, X:7, Rest/binary>>, N, Acc, F, _, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) ->
{NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, Bytes2 = binary:copy(Bytes), {id(Bytes2, TrUserData), Rest2} end,
- dfp_read_field_def_Release(RestF, 0, 0, F, NewFValue, F@_2, F@_3, F@_4, F@_5, TrUserData).
+ dfp_read_field_def_Release(RestF, 0, 0, F, NewFValue, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData).
-d_field_Release_inner_checksum(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) when N < 57 -> d_field_Release_inner_checksum(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData);
-d_field_Release_inner_checksum(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, _, F@_3, F@_4, F@_5, TrUserData) ->
+d_field_Release_inner_checksum(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) when N < 57 ->
+ d_field_Release_inner_checksum(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData);
+d_field_Release_inner_checksum(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, _, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) ->
{NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, Bytes2 = binary:copy(Bytes), {id(Bytes2, TrUserData), Rest2} end,
- dfp_read_field_def_Release(RestF, 0, 0, F, F@_1, NewFValue, F@_3, F@_4, F@_5, TrUserData).
+ dfp_read_field_def_Release(RestF, 0, 0, F, F@_1, NewFValue, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData).
-d_field_Release_dependencies(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) when N < 57 -> d_field_Release_dependencies(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData);
-d_field_Release_dependencies(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, Prev, F@_4, F@_5, TrUserData) ->
+d_field_Release_dependencies(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) when N < 57 -> d_field_Release_dependencies(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData);
+d_field_Release_dependencies(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, Prev, F@_4, F@_5, F@_6, F@_7, TrUserData) ->
{NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, {id(decode_msg_Dependency(Bs, TrUserData), TrUserData), Rest2} end,
- dfp_read_field_def_Release(RestF, 0, 0, F, F@_1, F@_2, cons(NewFValue, Prev, TrUserData), F@_4, F@_5, TrUserData).
+ dfp_read_field_def_Release(RestF, 0, 0, F, F@_1, F@_2, cons(NewFValue, Prev, TrUserData), F@_4, F@_5, F@_6, F@_7, TrUserData).
-d_field_Release_retired(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) when N < 57 -> d_field_Release_retired(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData);
-d_field_Release_retired(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, Prev, F@_5, TrUserData) ->
+d_field_Release_retired(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) when N < 57 -> d_field_Release_retired(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData);
+d_field_Release_retired(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, Prev, F@_5, F@_6, F@_7, TrUserData) ->
{NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, {id(decode_msg_RetirementStatus(Bs, TrUserData), TrUserData), Rest2} end,
dfp_read_field_def_Release(RestF,
0,
@@ -484,29 +622,71 @@ d_field_Release_retired(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3,
true -> merge_msg_RetirementStatus(Prev, NewFValue, TrUserData)
end,
F@_5,
+ F@_6,
+ F@_7,
TrUserData).
-d_field_Release_outer_checksum(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) when N < 57 -> d_field_Release_outer_checksum(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData);
-d_field_Release_outer_checksum(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, _, TrUserData) ->
+d_field_Release_outer_checksum(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) when N < 57 ->
+ d_field_Release_outer_checksum(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData);
+d_field_Release_outer_checksum(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, _, F@_6, F@_7, TrUserData) ->
{NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, Bytes2 = binary:copy(Bytes), {id(Bytes2, TrUserData), Rest2} end,
- dfp_read_field_def_Release(RestF, 0, 0, F, F@_1, F@_2, F@_3, F@_4, NewFValue, TrUserData).
+ dfp_read_field_def_Release(RestF, 0, 0, F, F@_1, F@_2, F@_3, F@_4, NewFValue, F@_6, F@_7, TrUserData).
-skip_varint_Release(<<1:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> skip_varint_Release(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData);
-skip_varint_Release(<<0:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> dfp_read_field_def_Release(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData).
+d_field_Release_advisory_indexes(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) when N < 57 ->
+ d_field_Release_advisory_indexes(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData);
+d_field_Release_advisory_indexes(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, Prev, F@_7, TrUserData) ->
+ {NewFValue, RestF} = {id((X bsl N + Acc) band 4294967295, TrUserData), Rest},
+ dfp_read_field_def_Release(RestF, 0, 0, F, F@_1, F@_2, F@_3, F@_4, F@_5, cons(NewFValue, Prev, TrUserData), F@_7, TrUserData).
-skip_length_delimited_Release(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) when N < 57 -> skip_length_delimited_Release(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData);
-skip_length_delimited_Release(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) ->
+d_pfield_Release_advisory_indexes(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) when N < 57 ->
+ d_pfield_Release_advisory_indexes(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData);
+d_pfield_Release_advisory_indexes(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, E, F@_7, TrUserData) ->
+ Len = X bsl N + Acc,
+ <> = Rest,
+ NewSeq = d_packed_field_Release_advisory_indexes(PackedBytes, 0, 0, F, E, TrUserData),
+ dfp_read_field_def_Release(Rest2, 0, 0, F, F@_1, F@_2, F@_3, F@_4, F@_5, NewSeq, F@_7, TrUserData).
+
+d_packed_field_Release_advisory_indexes(<<1:1, X:7, Rest/binary>>, N, Acc, F, AccSeq, TrUserData) when N < 57 -> d_packed_field_Release_advisory_indexes(Rest, N + 7, X bsl N + Acc, F, AccSeq, TrUserData);
+d_packed_field_Release_advisory_indexes(<<0:1, X:7, Rest/binary>>, N, Acc, F, AccSeq, TrUserData) ->
+ {NewFValue, RestF} = {id((X bsl N + Acc) band 4294967295, TrUserData), Rest},
+ d_packed_field_Release_advisory_indexes(RestF, 0, 0, F, [NewFValue | AccSeq], TrUserData);
+d_packed_field_Release_advisory_indexes(<<>>, 0, 0, _, AccSeq, _) -> AccSeq.
+
+d_field_Release_published_at(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) when N < 57 -> d_field_Release_published_at(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData);
+d_field_Release_published_at(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, Prev, TrUserData) ->
+ {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, {id(decode_msg_Timestamp(Bs, TrUserData), TrUserData), Rest2} end,
+ dfp_read_field_def_Release(RestF,
+ 0,
+ 0,
+ F,
+ F@_1,
+ F@_2,
+ F@_3,
+ F@_4,
+ F@_5,
+ F@_6,
+ if Prev == '$undef' -> NewFValue;
+ true -> merge_msg_Timestamp(Prev, NewFValue, TrUserData)
+ end,
+ TrUserData).
+
+skip_varint_Release(<<1:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) -> skip_varint_Release(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData);
+skip_varint_Release(<<0:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) -> dfp_read_field_def_Release(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData).
+
+skip_length_delimited_Release(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) when N < 57 ->
+ skip_length_delimited_Release(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData);
+skip_length_delimited_Release(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) ->
Length = X bsl N + Acc,
<<_:Length/binary, Rest2/binary>> = Rest,
- dfp_read_field_def_Release(Rest2, 0, 0, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData).
+ dfp_read_field_def_Release(Rest2, 0, 0, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData).
-skip_group_Release(Bin, _, Z2, FNum, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) ->
+skip_group_Release(Bin, _, Z2, FNum, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) ->
{_, Rest} = read_group(Bin, FNum),
- dfp_read_field_def_Release(Rest, 0, Z2, FNum, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData).
+ dfp_read_field_def_Release(Rest, 0, Z2, FNum, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData).
-skip_32_Release(<<_:32, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> dfp_read_field_def_Release(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData).
+skip_32_Release(<<_:32, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) -> dfp_read_field_def_Release(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData).
-skip_64_Release(<<_:64, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> dfp_read_field_def_Release(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData).
+skip_64_Release(<<_:64, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) -> dfp_read_field_def_Release(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData).
decode_msg_RetirementStatus(Bin, TrUserData) -> dfp_read_field_def_RetirementStatus(Bin, 0, 0, 0, id('$undef', TrUserData), id('$undef', TrUserData), TrUserData).
@@ -567,6 +747,118 @@ skip_32_RetirementStatus(<<_:32, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserDat
skip_64_RetirementStatus(<<_:64, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> dfp_read_field_def_RetirementStatus(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData).
+decode_msg_SecurityAdvisory(Bin, TrUserData) ->
+ dfp_read_field_def_SecurityAdvisory(Bin, 0, 0, 0, id('$undef', TrUserData), id('$undef', TrUserData), id('$undef', TrUserData), id('$undef', TrUserData), id('$undef', TrUserData), id('$undef', TrUserData), id([], TrUserData), TrUserData).
+
+dfp_read_field_def_SecurityAdvisory(<<10, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) -> d_field_SecurityAdvisory_id(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData);
+dfp_read_field_def_SecurityAdvisory(<<18, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) -> d_field_SecurityAdvisory_summary(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData);
+dfp_read_field_def_SecurityAdvisory(<<26, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) -> d_field_SecurityAdvisory_html_url(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData);
+dfp_read_field_def_SecurityAdvisory(<<32, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) -> d_field_SecurityAdvisory_severity(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData);
+dfp_read_field_def_SecurityAdvisory(<<45, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) -> d_field_SecurityAdvisory_cvss_score(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData);
+dfp_read_field_def_SecurityAdvisory(<<50, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) -> d_field_SecurityAdvisory_api_url(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData);
+dfp_read_field_def_SecurityAdvisory(<<58, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) -> d_field_SecurityAdvisory_aliases(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData);
+dfp_read_field_def_SecurityAdvisory(<<>>, 0, 0, _, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, R1, TrUserData) ->
+ S1 = #{id => F@_1, summary => F@_2, html_url => F@_3, api_url => F@_6, aliases => lists_reverse(R1, TrUserData)},
+ S2 = if F@_4 == '$undef' -> S1;
+ true -> S1#{severity => F@_4}
+ end,
+ if F@_5 == '$undef' -> S2;
+ true -> S2#{cvss_score => F@_5}
+ end;
+dfp_read_field_def_SecurityAdvisory(Other, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) -> dg_read_field_def_SecurityAdvisory(Other, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData).
+
+dg_read_field_def_SecurityAdvisory(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) when N < 32 - 7 ->
+ dg_read_field_def_SecurityAdvisory(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData);
+dg_read_field_def_SecurityAdvisory(<<0:1, X:7, Rest/binary>>, N, Acc, _, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) ->
+ Key = X bsl N + Acc,
+ case Key of
+ 10 -> d_field_SecurityAdvisory_id(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData);
+ 18 -> d_field_SecurityAdvisory_summary(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData);
+ 26 -> d_field_SecurityAdvisory_html_url(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData);
+ 32 -> d_field_SecurityAdvisory_severity(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData);
+ 45 -> d_field_SecurityAdvisory_cvss_score(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData);
+ 50 -> d_field_SecurityAdvisory_api_url(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData);
+ 58 -> d_field_SecurityAdvisory_aliases(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData);
+ _ ->
+ case Key band 7 of
+ 0 -> skip_varint_SecurityAdvisory(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData);
+ 1 -> skip_64_SecurityAdvisory(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData);
+ 2 -> skip_length_delimited_SecurityAdvisory(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData);
+ 3 -> skip_group_SecurityAdvisory(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData);
+ 5 -> skip_32_SecurityAdvisory(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData)
+ end
+ end;
+dg_read_field_def_SecurityAdvisory(<<>>, 0, 0, _, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, R1, TrUserData) ->
+ S1 = #{id => F@_1, summary => F@_2, html_url => F@_3, api_url => F@_6, aliases => lists_reverse(R1, TrUserData)},
+ S2 = if F@_4 == '$undef' -> S1;
+ true -> S1#{severity => F@_4}
+ end,
+ if F@_5 == '$undef' -> S2;
+ true -> S2#{cvss_score => F@_5}
+ end.
+
+d_field_SecurityAdvisory_id(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) when N < 57 -> d_field_SecurityAdvisory_id(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData);
+d_field_SecurityAdvisory_id(<<0:1, X:7, Rest/binary>>, N, Acc, F, _, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) ->
+ {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, Bytes2 = binary:copy(Bytes), {id(Bytes2, TrUserData), Rest2} end,
+ dfp_read_field_def_SecurityAdvisory(RestF, 0, 0, F, NewFValue, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData).
+
+d_field_SecurityAdvisory_summary(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) when N < 57 ->
+ d_field_SecurityAdvisory_summary(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData);
+d_field_SecurityAdvisory_summary(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, _, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) ->
+ {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, Bytes2 = binary:copy(Bytes), {id(Bytes2, TrUserData), Rest2} end,
+ dfp_read_field_def_SecurityAdvisory(RestF, 0, 0, F, F@_1, NewFValue, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData).
+
+d_field_SecurityAdvisory_html_url(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) when N < 57 ->
+ d_field_SecurityAdvisory_html_url(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData);
+d_field_SecurityAdvisory_html_url(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, _, F@_4, F@_5, F@_6, F@_7, TrUserData) ->
+ {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, Bytes2 = binary:copy(Bytes), {id(Bytes2, TrUserData), Rest2} end,
+ dfp_read_field_def_SecurityAdvisory(RestF, 0, 0, F, F@_1, F@_2, NewFValue, F@_4, F@_5, F@_6, F@_7, TrUserData).
+
+d_field_SecurityAdvisory_severity(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) when N < 57 ->
+ d_field_SecurityAdvisory_severity(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData);
+d_field_SecurityAdvisory_severity(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, _, F@_5, F@_6, F@_7, TrUserData) ->
+ {NewFValue, RestF} = {id(d_enum_AdvisorySeverity(begin <> = <<(X bsl N + Acc):32/unsigned-native>>, id(Res, TrUserData) end), TrUserData), Rest},
+ dfp_read_field_def_SecurityAdvisory(RestF, 0, 0, F, F@_1, F@_2, F@_3, NewFValue, F@_5, F@_6, F@_7, TrUserData).
+
+d_field_SecurityAdvisory_cvss_score(<<0:16, 128, 127, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, _, F@_6, F@_7, TrUserData) ->
+ dfp_read_field_def_SecurityAdvisory(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, id(infinity, TrUserData), F@_6, F@_7, TrUserData);
+d_field_SecurityAdvisory_cvss_score(<<0:16, 128, 255, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, _, F@_6, F@_7, TrUserData) ->
+ dfp_read_field_def_SecurityAdvisory(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, id('-infinity', TrUserData), F@_6, F@_7, TrUserData);
+d_field_SecurityAdvisory_cvss_score(<<_:16, 1:1, _:7, _:1, 127:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, _, F@_6, F@_7, TrUserData) ->
+ dfp_read_field_def_SecurityAdvisory(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, id(nan, TrUserData), F@_6, F@_7, TrUserData);
+d_field_SecurityAdvisory_cvss_score(<>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, _, F@_6, F@_7, TrUserData) ->
+ dfp_read_field_def_SecurityAdvisory(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, id(Value, TrUserData), F@_6, F@_7, TrUserData).
+
+d_field_SecurityAdvisory_api_url(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) when N < 57 ->
+ d_field_SecurityAdvisory_api_url(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData);
+d_field_SecurityAdvisory_api_url(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, _, F@_7, TrUserData) ->
+ {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, Bytes2 = binary:copy(Bytes), {id(Bytes2, TrUserData), Rest2} end,
+ dfp_read_field_def_SecurityAdvisory(RestF, 0, 0, F, F@_1, F@_2, F@_3, F@_4, F@_5, NewFValue, F@_7, TrUserData).
+
+d_field_SecurityAdvisory_aliases(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) when N < 57 ->
+ d_field_SecurityAdvisory_aliases(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData);
+d_field_SecurityAdvisory_aliases(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, Prev, TrUserData) ->
+ {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, Bytes2 = binary:copy(Bytes), {id(Bytes2, TrUserData), Rest2} end,
+ dfp_read_field_def_SecurityAdvisory(RestF, 0, 0, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, cons(NewFValue, Prev, TrUserData), TrUserData).
+
+skip_varint_SecurityAdvisory(<<1:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) -> skip_varint_SecurityAdvisory(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData);
+skip_varint_SecurityAdvisory(<<0:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) -> dfp_read_field_def_SecurityAdvisory(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData).
+
+skip_length_delimited_SecurityAdvisory(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) when N < 57 ->
+ skip_length_delimited_SecurityAdvisory(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData);
+skip_length_delimited_SecurityAdvisory(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) ->
+ Length = X bsl N + Acc,
+ <<_:Length/binary, Rest2/binary>> = Rest,
+ dfp_read_field_def_SecurityAdvisory(Rest2, 0, 0, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData).
+
+skip_group_SecurityAdvisory(Bin, _, Z2, FNum, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) ->
+ {_, Rest} = read_group(Bin, FNum),
+ dfp_read_field_def_SecurityAdvisory(Rest, 0, Z2, FNum, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData).
+
+skip_32_SecurityAdvisory(<<_:32, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) -> dfp_read_field_def_SecurityAdvisory(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData).
+
+skip_64_SecurityAdvisory(<<_:64, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) -> dfp_read_field_def_SecurityAdvisory(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData).
+
decode_msg_Dependency(Bin, TrUserData) -> dfp_read_field_def_Dependency(Bin, 0, 0, 0, id('$undef', TrUserData), id('$undef', TrUserData), id('$undef', TrUserData), id('$undef', TrUserData), id('$undef', TrUserData), TrUserData).
dfp_read_field_def_Dependency(<<10, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> d_field_Dependency_package(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData);
@@ -659,6 +951,57 @@ skip_32_Dependency(<<_:32, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_
skip_64_Dependency(<<_:64, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> dfp_read_field_def_Dependency(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData).
+decode_msg_Timestamp(Bin, TrUserData) -> dfp_read_field_def_Timestamp(Bin, 0, 0, 0, id('$undef', TrUserData), id('$undef', TrUserData), TrUserData).
+
+dfp_read_field_def_Timestamp(<<8, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> d_field_Timestamp_seconds(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData);
+dfp_read_field_def_Timestamp(<<16, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> d_field_Timestamp_nanos(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData);
+dfp_read_field_def_Timestamp(<<>>, 0, 0, _, F@_1, F@_2, _) -> #{seconds => F@_1, nanos => F@_2};
+dfp_read_field_def_Timestamp(Other, Z1, Z2, F, F@_1, F@_2, TrUserData) -> dg_read_field_def_Timestamp(Other, Z1, Z2, F, F@_1, F@_2, TrUserData).
+
+dg_read_field_def_Timestamp(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) when N < 32 - 7 -> dg_read_field_def_Timestamp(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, TrUserData);
+dg_read_field_def_Timestamp(<<0:1, X:7, Rest/binary>>, N, Acc, _, F@_1, F@_2, TrUserData) ->
+ Key = X bsl N + Acc,
+ case Key of
+ 8 -> d_field_Timestamp_seconds(Rest, 0, 0, 0, F@_1, F@_2, TrUserData);
+ 16 -> d_field_Timestamp_nanos(Rest, 0, 0, 0, F@_1, F@_2, TrUserData);
+ _ ->
+ case Key band 7 of
+ 0 -> skip_varint_Timestamp(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData);
+ 1 -> skip_64_Timestamp(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData);
+ 2 -> skip_length_delimited_Timestamp(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData);
+ 3 -> skip_group_Timestamp(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData);
+ 5 -> skip_32_Timestamp(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData)
+ end
+ end;
+dg_read_field_def_Timestamp(<<>>, 0, 0, _, F@_1, F@_2, _) -> #{seconds => F@_1, nanos => F@_2}.
+
+d_field_Timestamp_seconds(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) when N < 57 -> d_field_Timestamp_seconds(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, TrUserData);
+d_field_Timestamp_seconds(<<0:1, X:7, Rest/binary>>, N, Acc, F, _, F@_2, TrUserData) ->
+ {NewFValue, RestF} = {begin <> = <<(X bsl N + Acc):64/unsigned-native>>, id(Res, TrUserData) end, Rest},
+ dfp_read_field_def_Timestamp(RestF, 0, 0, F, NewFValue, F@_2, TrUserData).
+
+d_field_Timestamp_nanos(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) when N < 57 -> d_field_Timestamp_nanos(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, TrUserData);
+d_field_Timestamp_nanos(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, _, TrUserData) ->
+ {NewFValue, RestF} = {begin <> = <<(X bsl N + Acc):32/unsigned-native>>, id(Res, TrUserData) end, Rest},
+ dfp_read_field_def_Timestamp(RestF, 0, 0, F, F@_1, NewFValue, TrUserData).
+
+skip_varint_Timestamp(<<1:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> skip_varint_Timestamp(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData);
+skip_varint_Timestamp(<<0:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> dfp_read_field_def_Timestamp(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData).
+
+skip_length_delimited_Timestamp(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) when N < 57 -> skip_length_delimited_Timestamp(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, TrUserData);
+skip_length_delimited_Timestamp(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) ->
+ Length = X bsl N + Acc,
+ <<_:Length/binary, Rest2/binary>> = Rest,
+ dfp_read_field_def_Timestamp(Rest2, 0, 0, F, F@_1, F@_2, TrUserData).
+
+skip_group_Timestamp(Bin, _, Z2, FNum, F@_1, F@_2, TrUserData) ->
+ {_, Rest} = read_group(Bin, FNum),
+ dfp_read_field_def_Timestamp(Rest, 0, Z2, FNum, F@_1, F@_2, TrUserData).
+
+skip_32_Timestamp(<<_:32, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> dfp_read_field_def_Timestamp(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData).
+
+skip_64_Timestamp(<<_:64, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> dfp_read_field_def_Timestamp(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData).
+
d_enum_RetirementReason(0) -> 'RETIRED_OTHER';
d_enum_RetirementReason(1) -> 'RETIRED_INVALID';
d_enum_RetirementReason(2) -> 'RETIRED_SECURITY';
@@ -666,6 +1009,13 @@ d_enum_RetirementReason(3) -> 'RETIRED_DEPRECATED';
d_enum_RetirementReason(4) -> 'RETIRED_RENAMED';
d_enum_RetirementReason(V) -> V.
+d_enum_AdvisorySeverity(0) -> 'SEVERITY_NONE';
+d_enum_AdvisorySeverity(1) -> 'SEVERITY_LOW';
+d_enum_AdvisorySeverity(2) -> 'SEVERITY_MEDIUM';
+d_enum_AdvisorySeverity(3) -> 'SEVERITY_HIGH';
+d_enum_AdvisorySeverity(4) -> 'SEVERITY_CRITICAL';
+d_enum_AdvisorySeverity(V) -> V.
+
read_group(Bin, FieldNum) ->
{NumBytes, EndTagLen} = read_gr_b(Bin, 0, 0, 0, 0, FieldNum),
<> = Bin,
@@ -732,17 +1082,25 @@ merge_msgs(Prev, New, MsgName, Opts) ->
'Package' -> merge_msg_Package(Prev, New, TrUserData);
'Release' -> merge_msg_Release(Prev, New, TrUserData);
'RetirementStatus' -> merge_msg_RetirementStatus(Prev, New, TrUserData);
- 'Dependency' -> merge_msg_Dependency(Prev, New, TrUserData)
+ 'SecurityAdvisory' -> merge_msg_SecurityAdvisory(Prev, New, TrUserData);
+ 'Dependency' -> merge_msg_Dependency(Prev, New, TrUserData);
+ 'Timestamp' -> merge_msg_Timestamp(Prev, New, TrUserData)
end.
-compile({nowarn_unused_function,merge_msg_Package/3}).
merge_msg_Package(#{} = PMsg, #{name := NFname, repository := NFrepository} = NMsg, TrUserData) ->
S1 = #{name => NFname, repository => NFrepository},
+ S2 = case {PMsg, NMsg} of
+ {#{releases := PFreleases}, #{releases := NFreleases}} -> S1#{releases => 'erlang_++'(PFreleases, NFreleases, TrUserData)};
+ {_, #{releases := NFreleases}} -> S1#{releases => NFreleases};
+ {#{releases := PFreleases}, _} -> S1#{releases => PFreleases};
+ {_, _} -> S1
+ end,
case {PMsg, NMsg} of
- {#{releases := PFreleases}, #{releases := NFreleases}} -> S1#{releases => 'erlang_++'(PFreleases, NFreleases, TrUserData)};
- {_, #{releases := NFreleases}} -> S1#{releases => NFreleases};
- {#{releases := PFreleases}, _} -> S1#{releases => PFreleases};
- {_, _} -> S1
+ {#{advisories := PFadvisories}, #{advisories := NFadvisories}} -> S2#{advisories => 'erlang_++'(PFadvisories, NFadvisories, TrUserData)};
+ {_, #{advisories := NFadvisories}} -> S2#{advisories => NFadvisories};
+ {#{advisories := PFadvisories}, _} -> S2#{advisories => PFadvisories};
+ {_, _} -> S2
end.
-compile({nowarn_unused_function,merge_msg_Release/3}).
@@ -760,10 +1118,22 @@ merge_msg_Release(#{} = PMsg, #{version := NFversion, inner_checksum := NFinner_
{#{retired := PFretired}, _} -> S2#{retired => PFretired};
{_, _} -> S2
end,
+ S4 = case {PMsg, NMsg} of
+ {_, #{outer_checksum := NFouter_checksum}} -> S3#{outer_checksum => NFouter_checksum};
+ {#{outer_checksum := PFouter_checksum}, _} -> S3#{outer_checksum => PFouter_checksum};
+ _ -> S3
+ end,
+ S5 = case {PMsg, NMsg} of
+ {#{advisory_indexes := PFadvisory_indexes}, #{advisory_indexes := NFadvisory_indexes}} -> S4#{advisory_indexes => 'erlang_++'(PFadvisory_indexes, NFadvisory_indexes, TrUserData)};
+ {_, #{advisory_indexes := NFadvisory_indexes}} -> S4#{advisory_indexes => NFadvisory_indexes};
+ {#{advisory_indexes := PFadvisory_indexes}, _} -> S4#{advisory_indexes => PFadvisory_indexes};
+ {_, _} -> S4
+ end,
case {PMsg, NMsg} of
- {_, #{outer_checksum := NFouter_checksum}} -> S3#{outer_checksum => NFouter_checksum};
- {#{outer_checksum := PFouter_checksum}, _} -> S3#{outer_checksum => PFouter_checksum};
- _ -> S3
+ {#{published_at := PFpublished_at}, #{published_at := NFpublished_at}} -> S5#{published_at => merge_msg_Timestamp(PFpublished_at, NFpublished_at, TrUserData)};
+ {_, #{published_at := NFpublished_at}} -> S5#{published_at => NFpublished_at};
+ {#{published_at := PFpublished_at}, _} -> S5#{published_at => PFpublished_at};
+ {_, _} -> S5
end.
-compile({nowarn_unused_function,merge_msg_RetirementStatus/3}).
@@ -775,6 +1145,26 @@ merge_msg_RetirementStatus(#{} = PMsg, #{reason := NFreason} = NMsg, _) ->
_ -> S1
end.
+-compile({nowarn_unused_function,merge_msg_SecurityAdvisory/3}).
+merge_msg_SecurityAdvisory(#{} = PMsg, #{id := NFid, summary := NFsummary, html_url := NFhtml_url, api_url := NFapi_url} = NMsg, TrUserData) ->
+ S1 = #{id => NFid, summary => NFsummary, html_url => NFhtml_url, api_url => NFapi_url},
+ S2 = case {PMsg, NMsg} of
+ {_, #{severity := NFseverity}} -> S1#{severity => NFseverity};
+ {#{severity := PFseverity}, _} -> S1#{severity => PFseverity};
+ _ -> S1
+ end,
+ S3 = case {PMsg, NMsg} of
+ {_, #{cvss_score := NFcvss_score}} -> S2#{cvss_score => NFcvss_score};
+ {#{cvss_score := PFcvss_score}, _} -> S2#{cvss_score => PFcvss_score};
+ _ -> S2
+ end,
+ case {PMsg, NMsg} of
+ {#{aliases := PFaliases}, #{aliases := NFaliases}} -> S3#{aliases => 'erlang_++'(PFaliases, NFaliases, TrUserData)};
+ {_, #{aliases := NFaliases}} -> S3#{aliases => NFaliases};
+ {#{aliases := PFaliases}, _} -> S3#{aliases => PFaliases};
+ {_, _} -> S3
+ end.
+
-compile({nowarn_unused_function,merge_msg_Dependency/3}).
merge_msg_Dependency(#{} = PMsg, #{package := NFpackage, requirement := NFrequirement} = NMsg, _) ->
S1 = #{package => NFpackage, requirement => NFrequirement},
@@ -794,6 +1184,9 @@ merge_msg_Dependency(#{} = PMsg, #{package := NFpackage, requirement := NFrequir
_ -> S3
end.
+-compile({nowarn_unused_function,merge_msg_Timestamp/3}).
+merge_msg_Timestamp(#{}, #{seconds := NFseconds, nanos := NFnanos}, _) -> #{seconds => NFseconds, nanos => NFnanos}.
+
verify_msg(Msg, MsgName) when is_atom(MsgName) -> verify_msg(Msg, MsgName, []).
@@ -803,7 +1196,9 @@ verify_msg(Msg, MsgName, Opts) ->
'Package' -> v_msg_Package(Msg, [MsgName], TrUserData);
'Release' -> v_msg_Release(Msg, [MsgName], TrUserData);
'RetirementStatus' -> v_msg_RetirementStatus(Msg, [MsgName], TrUserData);
+ 'SecurityAdvisory' -> v_msg_SecurityAdvisory(Msg, [MsgName], TrUserData);
'Dependency' -> v_msg_Dependency(Msg, [MsgName], TrUserData);
+ 'Timestamp' -> v_msg_Timestamp(Msg, [MsgName], TrUserData);
_ -> mk_type_error(not_a_known_message, Msg, [])
end.
@@ -822,9 +1217,19 @@ v_msg_Package(#{name := F2, repository := F3} = M, Path, TrUserData) ->
end,
v_type_string(F2, [name | Path], TrUserData),
v_type_string(F3, [repository | Path], TrUserData),
+ case M of
+ #{advisories := F4} ->
+ if is_list(F4) ->
+ _ = [v_submsg_SecurityAdvisory(Elem, [advisories | Path], TrUserData) || Elem <- F4],
+ ok;
+ true -> mk_type_error({invalid_list_of, {msg, 'SecurityAdvisory'}}, F4, [advisories | Path])
+ end;
+ _ -> ok
+ end,
lists:foreach(fun (releases) -> ok;
(name) -> ok;
(repository) -> ok;
+ (advisories) -> ok;
(OtherKey) -> mk_type_error({extraneous_key, OtherKey}, M, Path)
end,
maps:keys(M)),
@@ -858,11 +1263,26 @@ v_msg_Release(#{version := F1, inner_checksum := F2} = M, Path, TrUserData) ->
#{outer_checksum := F5} -> v_type_bytes(F5, [outer_checksum | Path], TrUserData);
_ -> ok
end,
+ case M of
+ #{advisory_indexes := F6} ->
+ if is_list(F6) ->
+ _ = [v_type_uint32(Elem, [advisory_indexes | Path], TrUserData) || Elem <- F6],
+ ok;
+ true -> mk_type_error({invalid_list_of, uint32}, F6, [advisory_indexes | Path])
+ end;
+ _ -> ok
+ end,
+ case M of
+ #{published_at := F7} -> v_submsg_Timestamp(F7, [published_at | Path], TrUserData);
+ _ -> ok
+ end,
lists:foreach(fun (version) -> ok;
(inner_checksum) -> ok;
(dependencies) -> ok;
(retired) -> ok;
(outer_checksum) -> ok;
+ (advisory_indexes) -> ok;
+ (published_at) -> ok;
(OtherKey) -> mk_type_error({extraneous_key, OtherKey}, M, Path)
end,
maps:keys(M)),
@@ -891,6 +1311,48 @@ v_msg_RetirementStatus(#{reason := F1} = M, Path, TrUserData) ->
v_msg_RetirementStatus(M, Path, _TrUserData) when is_map(M) -> mk_type_error({missing_fields, [reason] -- maps:keys(M), 'RetirementStatus'}, M, Path);
v_msg_RetirementStatus(X, Path, _TrUserData) -> mk_type_error({expected_msg, 'RetirementStatus'}, X, Path).
+-compile({nowarn_unused_function,v_submsg_SecurityAdvisory/3}).
+-dialyzer({nowarn_function,v_submsg_SecurityAdvisory/3}).
+v_submsg_SecurityAdvisory(Msg, Path, TrUserData) -> v_msg_SecurityAdvisory(Msg, Path, TrUserData).
+
+-compile({nowarn_unused_function,v_msg_SecurityAdvisory/3}).
+-dialyzer({nowarn_function,v_msg_SecurityAdvisory/3}).
+v_msg_SecurityAdvisory(#{id := F1, summary := F2, html_url := F3, api_url := F6} = M, Path, TrUserData) ->
+ v_type_string(F1, [id | Path], TrUserData),
+ v_type_string(F2, [summary | Path], TrUserData),
+ v_type_string(F3, [html_url | Path], TrUserData),
+ case M of
+ #{severity := F4} -> v_enum_AdvisorySeverity(F4, [severity | Path], TrUserData);
+ _ -> ok
+ end,
+ case M of
+ #{cvss_score := F5} -> v_type_float(F5, [cvss_score | Path], TrUserData);
+ _ -> ok
+ end,
+ v_type_string(F6, [api_url | Path], TrUserData),
+ case M of
+ #{aliases := F7} ->
+ if is_list(F7) ->
+ _ = [v_type_string(Elem, [aliases | Path], TrUserData) || Elem <- F7],
+ ok;
+ true -> mk_type_error({invalid_list_of, string}, F7, [aliases | Path])
+ end;
+ _ -> ok
+ end,
+ lists:foreach(fun (id) -> ok;
+ (summary) -> ok;
+ (html_url) -> ok;
+ (severity) -> ok;
+ (cvss_score) -> ok;
+ (api_url) -> ok;
+ (aliases) -> ok;
+ (OtherKey) -> mk_type_error({extraneous_key, OtherKey}, M, Path)
+ end,
+ maps:keys(M)),
+ ok;
+v_msg_SecurityAdvisory(M, Path, _TrUserData) when is_map(M) -> mk_type_error({missing_fields, [id, summary, html_url, api_url] -- maps:keys(M), 'SecurityAdvisory'}, M, Path);
+v_msg_SecurityAdvisory(X, Path, _TrUserData) -> mk_type_error({expected_msg, 'SecurityAdvisory'}, X, Path).
+
-compile({nowarn_unused_function,v_submsg_Dependency/3}).
-dialyzer({nowarn_function,v_submsg_Dependency/3}).
v_submsg_Dependency(Msg, Path, TrUserData) -> v_msg_Dependency(Msg, Path, TrUserData).
@@ -924,6 +1386,24 @@ v_msg_Dependency(#{package := F1, requirement := F2} = M, Path, TrUserData) ->
v_msg_Dependency(M, Path, _TrUserData) when is_map(M) -> mk_type_error({missing_fields, [package, requirement] -- maps:keys(M), 'Dependency'}, M, Path);
v_msg_Dependency(X, Path, _TrUserData) -> mk_type_error({expected_msg, 'Dependency'}, X, Path).
+-compile({nowarn_unused_function,v_submsg_Timestamp/3}).
+-dialyzer({nowarn_function,v_submsg_Timestamp/3}).
+v_submsg_Timestamp(Msg, Path, TrUserData) -> v_msg_Timestamp(Msg, Path, TrUserData).
+
+-compile({nowarn_unused_function,v_msg_Timestamp/3}).
+-dialyzer({nowarn_function,v_msg_Timestamp/3}).
+v_msg_Timestamp(#{seconds := F1, nanos := F2} = M, Path, TrUserData) ->
+ v_type_int64(F1, [seconds | Path], TrUserData),
+ v_type_int32(F2, [nanos | Path], TrUserData),
+ lists:foreach(fun (seconds) -> ok;
+ (nanos) -> ok;
+ (OtherKey) -> mk_type_error({extraneous_key, OtherKey}, M, Path)
+ end,
+ maps:keys(M)),
+ ok;
+v_msg_Timestamp(M, Path, _TrUserData) when is_map(M) -> mk_type_error({missing_fields, [seconds, nanos] -- maps:keys(M), 'Timestamp'}, M, Path);
+v_msg_Timestamp(X, Path, _TrUserData) -> mk_type_error({expected_msg, 'Timestamp'}, X, Path).
+
-compile({nowarn_unused_function,v_enum_RetirementReason/3}).
-dialyzer({nowarn_function,v_enum_RetirementReason/3}).
v_enum_RetirementReason('RETIRED_OTHER', _Path, _TrUserData) -> ok;
@@ -934,6 +1414,34 @@ v_enum_RetirementReason('RETIRED_RENAMED', _Path, _TrUserData) -> ok;
v_enum_RetirementReason(V, _Path, _TrUserData) when -2147483648 =< V, V =< 2147483647, is_integer(V) -> ok;
v_enum_RetirementReason(X, Path, _TrUserData) -> mk_type_error({invalid_enum, 'RetirementReason'}, X, Path).
+-compile({nowarn_unused_function,v_enum_AdvisorySeverity/3}).
+-dialyzer({nowarn_function,v_enum_AdvisorySeverity/3}).
+v_enum_AdvisorySeverity('SEVERITY_NONE', _Path, _TrUserData) -> ok;
+v_enum_AdvisorySeverity('SEVERITY_LOW', _Path, _TrUserData) -> ok;
+v_enum_AdvisorySeverity('SEVERITY_MEDIUM', _Path, _TrUserData) -> ok;
+v_enum_AdvisorySeverity('SEVERITY_HIGH', _Path, _TrUserData) -> ok;
+v_enum_AdvisorySeverity('SEVERITY_CRITICAL', _Path, _TrUserData) -> ok;
+v_enum_AdvisorySeverity(V, _Path, _TrUserData) when -2147483648 =< V, V =< 2147483647, is_integer(V) -> ok;
+v_enum_AdvisorySeverity(X, Path, _TrUserData) -> mk_type_error({invalid_enum, 'AdvisorySeverity'}, X, Path).
+
+-compile({nowarn_unused_function,v_type_int32/3}).
+-dialyzer({nowarn_function,v_type_int32/3}).
+v_type_int32(N, _Path, _TrUserData) when is_integer(N), -2147483648 =< N, N =< 2147483647 -> ok;
+v_type_int32(N, Path, _TrUserData) when is_integer(N) -> mk_type_error({value_out_of_range, int32, signed, 32}, N, Path);
+v_type_int32(X, Path, _TrUserData) -> mk_type_error({bad_integer, int32, signed, 32}, X, Path).
+
+-compile({nowarn_unused_function,v_type_int64/3}).
+-dialyzer({nowarn_function,v_type_int64/3}).
+v_type_int64(N, _Path, _TrUserData) when is_integer(N), -9223372036854775808 =< N, N =< 9223372036854775807 -> ok;
+v_type_int64(N, Path, _TrUserData) when is_integer(N) -> mk_type_error({value_out_of_range, int64, signed, 64}, N, Path);
+v_type_int64(X, Path, _TrUserData) -> mk_type_error({bad_integer, int64, signed, 64}, X, Path).
+
+-compile({nowarn_unused_function,v_type_uint32/3}).
+-dialyzer({nowarn_function,v_type_uint32/3}).
+v_type_uint32(N, _Path, _TrUserData) when is_integer(N), 0 =< N, N =< 4294967295 -> ok;
+v_type_uint32(N, Path, _TrUserData) when is_integer(N) -> mk_type_error({value_out_of_range, uint32, unsigned, 32}, N, Path);
+v_type_uint32(X, Path, _TrUserData) -> mk_type_error({bad_integer, uint32, unsigned, 32}, X, Path).
+
-compile({nowarn_unused_function,v_type_bool/3}).
-dialyzer({nowarn_function,v_type_bool/3}).
v_type_bool(false, _Path, _TrUserData) -> ok;
@@ -942,6 +1450,15 @@ v_type_bool(0, _Path, _TrUserData) -> ok;
v_type_bool(1, _Path, _TrUserData) -> ok;
v_type_bool(X, Path, _TrUserData) -> mk_type_error(bad_boolean_value, X, Path).
+-compile({nowarn_unused_function,v_type_float/3}).
+-dialyzer({nowarn_function,v_type_float/3}).
+v_type_float(N, _Path, _TrUserData) when is_float(N) -> ok;
+v_type_float(N, _Path, _TrUserData) when is_integer(N) -> ok;
+v_type_float(infinity, _Path, _TrUserData) -> ok;
+v_type_float('-infinity', _Path, _TrUserData) -> ok;
+v_type_float(nan, _Path, _TrUserData) -> ok;
+v_type_float(X, Path, _TrUserData) -> mk_type_error(bad_float_value, X, Path).
+
-compile({nowarn_unused_function,v_type_string/3}).
-dialyzer({nowarn_function,v_type_string/3}).
v_type_string(S, Path, _TrUserData) when is_list(S); is_binary(S) ->
@@ -998,35 +1515,48 @@ cons(Elem, Acc, _TrUserData) -> [Elem | Acc].
get_msg_defs() ->
[{{enum, 'RetirementReason'}, [{'RETIRED_OTHER', 0}, {'RETIRED_INVALID', 1}, {'RETIRED_SECURITY', 2}, {'RETIRED_DEPRECATED', 3}, {'RETIRED_RENAMED', 4}]},
+ {{enum, 'AdvisorySeverity'}, [{'SEVERITY_NONE', 0}, {'SEVERITY_LOW', 1}, {'SEVERITY_MEDIUM', 2}, {'SEVERITY_HIGH', 3}, {'SEVERITY_CRITICAL', 4}]},
{{msg, 'Package'},
[#{name => releases, fnum => 1, rnum => 2, type => {msg, 'Release'}, occurrence => repeated, opts => []},
#{name => name, fnum => 2, rnum => 3, type => string, occurrence => required, opts => []},
- #{name => repository, fnum => 3, rnum => 4, type => string, occurrence => required, opts => []}]},
+ #{name => repository, fnum => 3, rnum => 4, type => string, occurrence => required, opts => []},
+ #{name => advisories, fnum => 4, rnum => 5, type => {msg, 'SecurityAdvisory'}, occurrence => repeated, opts => []}]},
{{msg, 'Release'},
[#{name => version, fnum => 1, rnum => 2, type => string, occurrence => required, opts => []},
#{name => inner_checksum, fnum => 2, rnum => 3, type => bytes, occurrence => required, opts => []},
#{name => dependencies, fnum => 3, rnum => 4, type => {msg, 'Dependency'}, occurrence => repeated, opts => []},
#{name => retired, fnum => 4, rnum => 5, type => {msg, 'RetirementStatus'}, occurrence => optional, opts => []},
- #{name => outer_checksum, fnum => 5, rnum => 6, type => bytes, occurrence => optional, opts => []}]},
+ #{name => outer_checksum, fnum => 5, rnum => 6, type => bytes, occurrence => optional, opts => []},
+ #{name => advisory_indexes, fnum => 6, rnum => 7, type => uint32, occurrence => repeated, opts => []},
+ #{name => published_at, fnum => 7, rnum => 8, type => {msg, 'Timestamp'}, occurrence => optional, opts => []}]},
{{msg, 'RetirementStatus'}, [#{name => reason, fnum => 1, rnum => 2, type => {enum, 'RetirementReason'}, occurrence => required, opts => []}, #{name => message, fnum => 2, rnum => 3, type => string, occurrence => optional, opts => []}]},
+ {{msg, 'SecurityAdvisory'},
+ [#{name => id, fnum => 1, rnum => 2, type => string, occurrence => required, opts => []},
+ #{name => summary, fnum => 2, rnum => 3, type => string, occurrence => required, opts => []},
+ #{name => html_url, fnum => 3, rnum => 4, type => string, occurrence => required, opts => []},
+ #{name => severity, fnum => 4, rnum => 5, type => {enum, 'AdvisorySeverity'}, occurrence => optional, opts => []},
+ #{name => cvss_score, fnum => 5, rnum => 6, type => float, occurrence => optional, opts => []},
+ #{name => api_url, fnum => 6, rnum => 7, type => string, occurrence => required, opts => []},
+ #{name => aliases, fnum => 7, rnum => 8, type => string, occurrence => repeated, opts => []}]},
{{msg, 'Dependency'},
[#{name => package, fnum => 1, rnum => 2, type => string, occurrence => required, opts => []},
#{name => requirement, fnum => 2, rnum => 3, type => string, occurrence => required, opts => []},
#{name => optional, fnum => 3, rnum => 4, type => bool, occurrence => optional, opts => []},
#{name => app, fnum => 4, rnum => 5, type => string, occurrence => optional, opts => []},
- #{name => repository, fnum => 5, rnum => 6, type => string, occurrence => optional, opts => []}]}].
+ #{name => repository, fnum => 5, rnum => 6, type => string, occurrence => optional, opts => []}]},
+ {{msg, 'Timestamp'}, [#{name => seconds, fnum => 1, rnum => 2, type => int64, occurrence => required, opts => []}, #{name => nanos, fnum => 2, rnum => 3, type => int32, occurrence => required, opts => []}]}].
-get_msg_names() -> ['Package', 'Release', 'RetirementStatus', 'Dependency'].
+get_msg_names() -> ['Package', 'Release', 'RetirementStatus', 'SecurityAdvisory', 'Dependency', 'Timestamp'].
get_group_names() -> [].
-get_msg_or_group_names() -> ['Package', 'Release', 'RetirementStatus', 'Dependency'].
+get_msg_or_group_names() -> ['Package', 'Release', 'RetirementStatus', 'SecurityAdvisory', 'Dependency', 'Timestamp'].
-get_enum_names() -> ['RetirementReason'].
+get_enum_names() -> ['RetirementReason', 'AdvisorySeverity'].
fetch_msg_def(MsgName) ->
@@ -1046,31 +1576,46 @@ fetch_enum_def(EnumName) ->
find_msg_def('Package') ->
[#{name => releases, fnum => 1, rnum => 2, type => {msg, 'Release'}, occurrence => repeated, opts => []},
#{name => name, fnum => 2, rnum => 3, type => string, occurrence => required, opts => []},
- #{name => repository, fnum => 3, rnum => 4, type => string, occurrence => required, opts => []}];
+ #{name => repository, fnum => 3, rnum => 4, type => string, occurrence => required, opts => []},
+ #{name => advisories, fnum => 4, rnum => 5, type => {msg, 'SecurityAdvisory'}, occurrence => repeated, opts => []}];
find_msg_def('Release') ->
[#{name => version, fnum => 1, rnum => 2, type => string, occurrence => required, opts => []},
#{name => inner_checksum, fnum => 2, rnum => 3, type => bytes, occurrence => required, opts => []},
#{name => dependencies, fnum => 3, rnum => 4, type => {msg, 'Dependency'}, occurrence => repeated, opts => []},
#{name => retired, fnum => 4, rnum => 5, type => {msg, 'RetirementStatus'}, occurrence => optional, opts => []},
- #{name => outer_checksum, fnum => 5, rnum => 6, type => bytes, occurrence => optional, opts => []}];
+ #{name => outer_checksum, fnum => 5, rnum => 6, type => bytes, occurrence => optional, opts => []},
+ #{name => advisory_indexes, fnum => 6, rnum => 7, type => uint32, occurrence => repeated, opts => []},
+ #{name => published_at, fnum => 7, rnum => 8, type => {msg, 'Timestamp'}, occurrence => optional, opts => []}];
find_msg_def('RetirementStatus') -> [#{name => reason, fnum => 1, rnum => 2, type => {enum, 'RetirementReason'}, occurrence => required, opts => []}, #{name => message, fnum => 2, rnum => 3, type => string, occurrence => optional, opts => []}];
+find_msg_def('SecurityAdvisory') ->
+ [#{name => id, fnum => 1, rnum => 2, type => string, occurrence => required, opts => []},
+ #{name => summary, fnum => 2, rnum => 3, type => string, occurrence => required, opts => []},
+ #{name => html_url, fnum => 3, rnum => 4, type => string, occurrence => required, opts => []},
+ #{name => severity, fnum => 4, rnum => 5, type => {enum, 'AdvisorySeverity'}, occurrence => optional, opts => []},
+ #{name => cvss_score, fnum => 5, rnum => 6, type => float, occurrence => optional, opts => []},
+ #{name => api_url, fnum => 6, rnum => 7, type => string, occurrence => required, opts => []},
+ #{name => aliases, fnum => 7, rnum => 8, type => string, occurrence => repeated, opts => []}];
find_msg_def('Dependency') ->
[#{name => package, fnum => 1, rnum => 2, type => string, occurrence => required, opts => []},
#{name => requirement, fnum => 2, rnum => 3, type => string, occurrence => required, opts => []},
#{name => optional, fnum => 3, rnum => 4, type => bool, occurrence => optional, opts => []},
#{name => app, fnum => 4, rnum => 5, type => string, occurrence => optional, opts => []},
#{name => repository, fnum => 5, rnum => 6, type => string, occurrence => optional, opts => []}];
+find_msg_def('Timestamp') -> [#{name => seconds, fnum => 1, rnum => 2, type => int64, occurrence => required, opts => []}, #{name => nanos, fnum => 2, rnum => 3, type => int32, occurrence => required, opts => []}];
find_msg_def(_) -> error.
find_enum_def('RetirementReason') -> [{'RETIRED_OTHER', 0}, {'RETIRED_INVALID', 1}, {'RETIRED_SECURITY', 2}, {'RETIRED_DEPRECATED', 3}, {'RETIRED_RENAMED', 4}];
+find_enum_def('AdvisorySeverity') -> [{'SEVERITY_NONE', 0}, {'SEVERITY_LOW', 1}, {'SEVERITY_MEDIUM', 2}, {'SEVERITY_HIGH', 3}, {'SEVERITY_CRITICAL', 4}];
find_enum_def(_) -> error.
-enum_symbol_by_value('RetirementReason', Value) -> enum_symbol_by_value_RetirementReason(Value).
+enum_symbol_by_value('RetirementReason', Value) -> enum_symbol_by_value_RetirementReason(Value);
+enum_symbol_by_value('AdvisorySeverity', Value) -> enum_symbol_by_value_AdvisorySeverity(Value).
-enum_value_by_symbol('RetirementReason', Sym) -> enum_value_by_symbol_RetirementReason(Sym).
+enum_value_by_symbol('RetirementReason', Sym) -> enum_value_by_symbol_RetirementReason(Sym);
+enum_value_by_symbol('AdvisorySeverity', Sym) -> enum_value_by_symbol_AdvisorySeverity(Sym).
enum_symbol_by_value_RetirementReason(0) -> 'RETIRED_OTHER';
@@ -1086,6 +1631,19 @@ enum_value_by_symbol_RetirementReason('RETIRED_SECURITY') -> 2;
enum_value_by_symbol_RetirementReason('RETIRED_DEPRECATED') -> 3;
enum_value_by_symbol_RetirementReason('RETIRED_RENAMED') -> 4.
+enum_symbol_by_value_AdvisorySeverity(0) -> 'SEVERITY_NONE';
+enum_symbol_by_value_AdvisorySeverity(1) -> 'SEVERITY_LOW';
+enum_symbol_by_value_AdvisorySeverity(2) -> 'SEVERITY_MEDIUM';
+enum_symbol_by_value_AdvisorySeverity(3) -> 'SEVERITY_HIGH';
+enum_symbol_by_value_AdvisorySeverity(4) -> 'SEVERITY_CRITICAL'.
+
+
+enum_value_by_symbol_AdvisorySeverity('SEVERITY_NONE') -> 0;
+enum_value_by_symbol_AdvisorySeverity('SEVERITY_LOW') -> 1;
+enum_value_by_symbol_AdvisorySeverity('SEVERITY_MEDIUM') -> 2;
+enum_value_by_symbol_AdvisorySeverity('SEVERITY_HIGH') -> 3;
+enum_value_by_symbol_AdvisorySeverity('SEVERITY_CRITICAL') -> 4.
+
get_service_names() -> [].
@@ -1133,22 +1691,28 @@ service_and_rpc_name_to_fqbins(S, R) -> error({gpb_error, {badservice_or_rpc, {S
fqbin_to_msg_name(<<"Package">>) -> 'Package';
fqbin_to_msg_name(<<"Release">>) -> 'Release';
fqbin_to_msg_name(<<"RetirementStatus">>) -> 'RetirementStatus';
+fqbin_to_msg_name(<<"SecurityAdvisory">>) -> 'SecurityAdvisory';
fqbin_to_msg_name(<<"Dependency">>) -> 'Dependency';
+fqbin_to_msg_name(<<"Timestamp">>) -> 'Timestamp';
fqbin_to_msg_name(E) -> error({gpb_error, {badmsg, E}}).
msg_name_to_fqbin('Package') -> <<"Package">>;
msg_name_to_fqbin('Release') -> <<"Release">>;
msg_name_to_fqbin('RetirementStatus') -> <<"RetirementStatus">>;
+msg_name_to_fqbin('SecurityAdvisory') -> <<"SecurityAdvisory">>;
msg_name_to_fqbin('Dependency') -> <<"Dependency">>;
+msg_name_to_fqbin('Timestamp') -> <<"Timestamp">>;
msg_name_to_fqbin(E) -> error({gpb_error, {badmsg, E}}).
fqbin_to_enum_name(<<"RetirementReason">>) -> 'RetirementReason';
+fqbin_to_enum_name(<<"AdvisorySeverity">>) -> 'AdvisorySeverity';
fqbin_to_enum_name(E) -> error({gpb_error, {badenum, E}}).
enum_name_to_fqbin('RetirementReason') -> <<"RetirementReason">>;
+enum_name_to_fqbin('AdvisorySeverity') -> <<"AdvisorySeverity">>;
enum_name_to_fqbin(E) -> error({gpb_error, {badenum, E}}).
@@ -1179,7 +1743,7 @@ get_all_source_basenames() -> ["r3_hex_pb_package.proto"].
get_all_proto_names() -> ["r3_hex_pb_package"].
-get_msg_containment("r3_hex_pb_package") -> ['Dependency', 'Package', 'Release', 'RetirementStatus'];
+get_msg_containment("r3_hex_pb_package") -> ['Dependency', 'Package', 'Release', 'RetirementStatus', 'SecurityAdvisory', 'Timestamp'];
get_msg_containment(P) -> error({gpb_error, {badproto, P}}).
@@ -1195,13 +1759,15 @@ get_rpc_containment("r3_hex_pb_package") -> [];
get_rpc_containment(P) -> error({gpb_error, {badproto, P}}).
-get_enum_containment("r3_hex_pb_package") -> ['RetirementReason'];
+get_enum_containment("r3_hex_pb_package") -> ['AdvisorySeverity', 'RetirementReason'];
get_enum_containment(P) -> error({gpb_error, {badproto, P}}).
+get_proto_by_msg_name_as_fqbin(<<"Timestamp">>) -> "r3_hex_pb_package";
get_proto_by_msg_name_as_fqbin(<<"RetirementStatus">>) -> "r3_hex_pb_package";
get_proto_by_msg_name_as_fqbin(<<"Release">>) -> "r3_hex_pb_package";
get_proto_by_msg_name_as_fqbin(<<"Package">>) -> "r3_hex_pb_package";
+get_proto_by_msg_name_as_fqbin(<<"SecurityAdvisory">>) -> "r3_hex_pb_package";
get_proto_by_msg_name_as_fqbin(<<"Dependency">>) -> "r3_hex_pb_package";
get_proto_by_msg_name_as_fqbin(E) -> error({gpb_error, {badmsg, E}}).
@@ -1210,6 +1776,7 @@ get_proto_by_msg_name_as_fqbin(E) -> error({gpb_error, {badmsg, E}}).
get_proto_by_service_name_as_fqbin(E) -> error({gpb_error, {badservice, E}}).
+get_proto_by_enum_name_as_fqbin(<<"AdvisorySeverity">>) -> "r3_hex_pb_package";
get_proto_by_enum_name_as_fqbin(<<"RetirementReason">>) -> "r3_hex_pb_package";
get_proto_by_enum_name_as_fqbin(E) -> error({gpb_error, {badenum, E}}).
diff --git a/apps/rebar/src/vendored/r3_hex_pb_signed.erl b/apps/rebar/src/vendored/r3_hex_pb_signed.erl
index bfcfc7a94..b6835b737 100644
--- a/apps/rebar/src/vendored/r3_hex_pb_signed.erl
+++ b/apps/rebar/src/vendored/r3_hex_pb_signed.erl
@@ -1,4 +1,4 @@
-%% Vendored from hex_core v0.15.0, do not edit manually
+%% Vendored from hex_core v0.17.0, do not edit manually
%% -*- coding: utf-8 -*-
%% % this file is @generated
diff --git a/apps/rebar/src/vendored/r3_hex_pb_versions.erl b/apps/rebar/src/vendored/r3_hex_pb_versions.erl
index b4af33e8f..2a6880887 100644
--- a/apps/rebar/src/vendored/r3_hex_pb_versions.erl
+++ b/apps/rebar/src/vendored/r3_hex_pb_versions.erl
@@ -1,4 +1,4 @@
-%% Vendored from hex_core v0.15.0, do not edit manually
+%% Vendored from hex_core v0.17.0, do not edit manually
%% -*- coding: utf-8 -*-
%% % this file is @generated
@@ -63,7 +63,8 @@
-type 'Package'() ::
#{name => unicode:chardata(), % = 1, required
versions => [unicode:chardata()], % = 2, repeated
- retired => [integer()] % = 3, repeated, 32 bits
+ retired => [integer()], % = 3, repeated, 32 bits
+ with_advisories => [integer()] % = 5, repeated, 32 bits
}.
-export_type(['Versions'/0, 'Package'/0]).
@@ -117,13 +118,21 @@ encode_msg_Package(#{name := F1} = M, Bin, TrUserData) ->
end;
_ -> B1
end,
+ B3 = case M of
+ #{retired := F3} ->
+ TrF3 = id(F3, TrUserData),
+ if TrF3 == [] -> B2;
+ true -> e_field_Package_retired(TrF3, B2, TrUserData)
+ end;
+ _ -> B2
+ end,
case M of
- #{retired := F3} ->
- TrF3 = id(F3, TrUserData),
- if TrF3 == [] -> B2;
- true -> e_field_Package_retired(TrF3, B2, TrUserData)
+ #{with_advisories := F4} ->
+ TrF4 = id(F4, TrUserData),
+ if TrF4 == [] -> B3;
+ true -> e_field_Package_with_advisories(TrF4, B3, TrUserData)
end;
- _ -> B2
+ _ -> B3
end.
e_mfield_Versions_packages(Msg, Bin, TrUserData) ->
@@ -155,6 +164,18 @@ e_pfield_Package_retired([Value | Rest], Bin, TrUserData) ->
e_pfield_Package_retired(Rest, Bin2, TrUserData);
e_pfield_Package_retired([], Bin, _TrUserData) -> Bin.
+e_field_Package_with_advisories(Elems, Bin, TrUserData) when Elems =/= [] ->
+ SubBin = e_pfield_Package_with_advisories(Elems, <<>>, TrUserData),
+ Bin2 = <>,
+ Bin3 = e_varint(byte_size(SubBin), Bin2),
+ <>;
+e_field_Package_with_advisories([], Bin, _TrUserData) -> Bin.
+
+e_pfield_Package_with_advisories([Value | Rest], Bin, TrUserData) ->
+ Bin2 = e_type_int32(id(Value, TrUserData), Bin, TrUserData),
+ e_pfield_Package_with_advisories(Rest, Bin2, TrUserData);
+e_pfield_Package_with_advisories([], Bin, _TrUserData) -> Bin.
+
-compile({nowarn_unused_function,e_type_sint/3}).
e_type_sint(Value, Bin, _TrUserData) when Value >= 0 -> e_varint(Value * 2, Bin);
e_type_sint(Value, Bin, _TrUserData) -> e_varint(Value * -2 - 1, Bin).
@@ -341,55 +362,59 @@ skip_32_Versions(<<_:32, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> df
skip_64_Versions(<<_:64, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> dfp_read_field_def_Versions(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData).
-decode_msg_Package(Bin, TrUserData) -> dfp_read_field_def_Package(Bin, 0, 0, 0, id('$undef', TrUserData), id([], TrUserData), id([], TrUserData), TrUserData).
+decode_msg_Package(Bin, TrUserData) -> dfp_read_field_def_Package(Bin, 0, 0, 0, id('$undef', TrUserData), id([], TrUserData), id([], TrUserData), id([], TrUserData), TrUserData).
-dfp_read_field_def_Package(<<10, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> d_field_Package_name(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData);
-dfp_read_field_def_Package(<<18, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> d_field_Package_versions(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData);
-dfp_read_field_def_Package(<<26, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> d_pfield_Package_retired(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData);
-dfp_read_field_def_Package(<<24, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> d_field_Package_retired(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData);
-dfp_read_field_def_Package(<<>>, 0, 0, _, F@_1, R1, R2, TrUserData) -> #{name => F@_1, versions => lists_reverse(R1, TrUserData), retired => lists_reverse(R2, TrUserData)};
-dfp_read_field_def_Package(Other, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> dg_read_field_def_Package(Other, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData).
+dfp_read_field_def_Package(<<10, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, TrUserData) -> d_field_Package_name(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, TrUserData);
+dfp_read_field_def_Package(<<18, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, TrUserData) -> d_field_Package_versions(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, TrUserData);
+dfp_read_field_def_Package(<<26, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, TrUserData) -> d_pfield_Package_retired(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, TrUserData);
+dfp_read_field_def_Package(<<24, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, TrUserData) -> d_field_Package_retired(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, TrUserData);
+dfp_read_field_def_Package(<<42, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, TrUserData) -> d_pfield_Package_with_advisories(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, TrUserData);
+dfp_read_field_def_Package(<<40, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, TrUserData) -> d_field_Package_with_advisories(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, TrUserData);
+dfp_read_field_def_Package(<<>>, 0, 0, _, F@_1, R1, R2, R3, TrUserData) -> #{name => F@_1, versions => lists_reverse(R1, TrUserData), retired => lists_reverse(R2, TrUserData), with_advisories => lists_reverse(R3, TrUserData)};
+dfp_read_field_def_Package(Other, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, TrUserData) -> dg_read_field_def_Package(Other, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, TrUserData).
-dg_read_field_def_Package(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, TrUserData) when N < 32 - 7 -> dg_read_field_def_Package(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, TrUserData);
-dg_read_field_def_Package(<<0:1, X:7, Rest/binary>>, N, Acc, _, F@_1, F@_2, F@_3, TrUserData) ->
+dg_read_field_def_Package(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, TrUserData) when N < 32 - 7 -> dg_read_field_def_Package(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, TrUserData);
+dg_read_field_def_Package(<<0:1, X:7, Rest/binary>>, N, Acc, _, F@_1, F@_2, F@_3, F@_4, TrUserData) ->
Key = X bsl N + Acc,
case Key of
- 10 -> d_field_Package_name(Rest, 0, 0, 0, F@_1, F@_2, F@_3, TrUserData);
- 18 -> d_field_Package_versions(Rest, 0, 0, 0, F@_1, F@_2, F@_3, TrUserData);
- 26 -> d_pfield_Package_retired(Rest, 0, 0, 0, F@_1, F@_2, F@_3, TrUserData);
- 24 -> d_field_Package_retired(Rest, 0, 0, 0, F@_1, F@_2, F@_3, TrUserData);
+ 10 -> d_field_Package_name(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, TrUserData);
+ 18 -> d_field_Package_versions(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, TrUserData);
+ 26 -> d_pfield_Package_retired(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, TrUserData);
+ 24 -> d_field_Package_retired(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, TrUserData);
+ 42 -> d_pfield_Package_with_advisories(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, TrUserData);
+ 40 -> d_field_Package_with_advisories(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, TrUserData);
_ ->
case Key band 7 of
- 0 -> skip_varint_Package(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, TrUserData);
- 1 -> skip_64_Package(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, TrUserData);
- 2 -> skip_length_delimited_Package(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, TrUserData);
- 3 -> skip_group_Package(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, TrUserData);
- 5 -> skip_32_Package(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, TrUserData)
+ 0 -> skip_varint_Package(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, TrUserData);
+ 1 -> skip_64_Package(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, TrUserData);
+ 2 -> skip_length_delimited_Package(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, TrUserData);
+ 3 -> skip_group_Package(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, TrUserData);
+ 5 -> skip_32_Package(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, TrUserData)
end
end;
-dg_read_field_def_Package(<<>>, 0, 0, _, F@_1, R1, R2, TrUserData) -> #{name => F@_1, versions => lists_reverse(R1, TrUserData), retired => lists_reverse(R2, TrUserData)}.
+dg_read_field_def_Package(<<>>, 0, 0, _, F@_1, R1, R2, R3, TrUserData) -> #{name => F@_1, versions => lists_reverse(R1, TrUserData), retired => lists_reverse(R2, TrUserData), with_advisories => lists_reverse(R3, TrUserData)}.
-d_field_Package_name(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, TrUserData) when N < 57 -> d_field_Package_name(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, TrUserData);
-d_field_Package_name(<<0:1, X:7, Rest/binary>>, N, Acc, F, _, F@_2, F@_3, TrUserData) ->
+d_field_Package_name(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, TrUserData) when N < 57 -> d_field_Package_name(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, TrUserData);
+d_field_Package_name(<<0:1, X:7, Rest/binary>>, N, Acc, F, _, F@_2, F@_3, F@_4, TrUserData) ->
{NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, Bytes2 = binary:copy(Bytes), {id(Bytes2, TrUserData), Rest2} end,
- dfp_read_field_def_Package(RestF, 0, 0, F, NewFValue, F@_2, F@_3, TrUserData).
+ dfp_read_field_def_Package(RestF, 0, 0, F, NewFValue, F@_2, F@_3, F@_4, TrUserData).
-d_field_Package_versions(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, TrUserData) when N < 57 -> d_field_Package_versions(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, TrUserData);
-d_field_Package_versions(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, Prev, F@_3, TrUserData) ->
+d_field_Package_versions(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, TrUserData) when N < 57 -> d_field_Package_versions(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, TrUserData);
+d_field_Package_versions(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, Prev, F@_3, F@_4, TrUserData) ->
{NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, Bytes2 = binary:copy(Bytes), {id(Bytes2, TrUserData), Rest2} end,
- dfp_read_field_def_Package(RestF, 0, 0, F, F@_1, cons(NewFValue, Prev, TrUserData), F@_3, TrUserData).
+ dfp_read_field_def_Package(RestF, 0, 0, F, F@_1, cons(NewFValue, Prev, TrUserData), F@_3, F@_4, TrUserData).
-d_field_Package_retired(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, TrUserData) when N < 57 -> d_field_Package_retired(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, TrUserData);
-d_field_Package_retired(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, Prev, TrUserData) ->
+d_field_Package_retired(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, TrUserData) when N < 57 -> d_field_Package_retired(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, TrUserData);
+d_field_Package_retired(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, Prev, F@_4, TrUserData) ->
{NewFValue, RestF} = {begin <> = <<(X bsl N + Acc):32/unsigned-native>>, id(Res, TrUserData) end, Rest},
- dfp_read_field_def_Package(RestF, 0, 0, F, F@_1, F@_2, cons(NewFValue, Prev, TrUserData), TrUserData).
+ dfp_read_field_def_Package(RestF, 0, 0, F, F@_1, F@_2, cons(NewFValue, Prev, TrUserData), F@_4, TrUserData).
-d_pfield_Package_retired(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, TrUserData) when N < 57 -> d_pfield_Package_retired(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, TrUserData);
-d_pfield_Package_retired(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, E, TrUserData) ->
+d_pfield_Package_retired(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, TrUserData) when N < 57 -> d_pfield_Package_retired(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, TrUserData);
+d_pfield_Package_retired(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, E, F@_4, TrUserData) ->
Len = X bsl N + Acc,
<> = Rest,
NewSeq = d_packed_field_Package_retired(PackedBytes, 0, 0, F, E, TrUserData),
- dfp_read_field_def_Package(Rest2, 0, 0, F, F@_1, F@_2, NewSeq, TrUserData).
+ dfp_read_field_def_Package(Rest2, 0, 0, F, F@_1, F@_2, NewSeq, F@_4, TrUserData).
d_packed_field_Package_retired(<<1:1, X:7, Rest/binary>>, N, Acc, F, AccSeq, TrUserData) when N < 57 -> d_packed_field_Package_retired(Rest, N + 7, X bsl N + Acc, F, AccSeq, TrUserData);
d_packed_field_Package_retired(<<0:1, X:7, Rest/binary>>, N, Acc, F, AccSeq, TrUserData) ->
@@ -397,22 +422,40 @@ d_packed_field_Package_retired(<<0:1, X:7, Rest/binary>>, N, Acc, F, AccSeq, TrU
d_packed_field_Package_retired(RestF, 0, 0, F, [NewFValue | AccSeq], TrUserData);
d_packed_field_Package_retired(<<>>, 0, 0, _, AccSeq, _) -> AccSeq.
-skip_varint_Package(<<1:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> skip_varint_Package(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData);
-skip_varint_Package(<<0:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> dfp_read_field_def_Package(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData).
+d_field_Package_with_advisories(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, TrUserData) when N < 57 -> d_field_Package_with_advisories(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, TrUserData);
+d_field_Package_with_advisories(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, Prev, TrUserData) ->
+ {NewFValue, RestF} = {begin <> = <<(X bsl N + Acc):32/unsigned-native>>, id(Res, TrUserData) end, Rest},
+ dfp_read_field_def_Package(RestF, 0, 0, F, F@_1, F@_2, F@_3, cons(NewFValue, Prev, TrUserData), TrUserData).
-skip_length_delimited_Package(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, TrUserData) when N < 57 -> skip_length_delimited_Package(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, TrUserData);
-skip_length_delimited_Package(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, TrUserData) ->
+d_pfield_Package_with_advisories(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, TrUserData) when N < 57 -> d_pfield_Package_with_advisories(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, TrUserData);
+d_pfield_Package_with_advisories(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, E, TrUserData) ->
+ Len = X bsl N + Acc,
+ <> = Rest,
+ NewSeq = d_packed_field_Package_with_advisories(PackedBytes, 0, 0, F, E, TrUserData),
+ dfp_read_field_def_Package(Rest2, 0, 0, F, F@_1, F@_2, F@_3, NewSeq, TrUserData).
+
+d_packed_field_Package_with_advisories(<<1:1, X:7, Rest/binary>>, N, Acc, F, AccSeq, TrUserData) when N < 57 -> d_packed_field_Package_with_advisories(Rest, N + 7, X bsl N + Acc, F, AccSeq, TrUserData);
+d_packed_field_Package_with_advisories(<<0:1, X:7, Rest/binary>>, N, Acc, F, AccSeq, TrUserData) ->
+ {NewFValue, RestF} = {begin <> = <<(X bsl N + Acc):32/unsigned-native>>, id(Res, TrUserData) end, Rest},
+ d_packed_field_Package_with_advisories(RestF, 0, 0, F, [NewFValue | AccSeq], TrUserData);
+d_packed_field_Package_with_advisories(<<>>, 0, 0, _, AccSeq, _) -> AccSeq.
+
+skip_varint_Package(<<1:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, TrUserData) -> skip_varint_Package(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, TrUserData);
+skip_varint_Package(<<0:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, TrUserData) -> dfp_read_field_def_Package(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, TrUserData).
+
+skip_length_delimited_Package(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, TrUserData) when N < 57 -> skip_length_delimited_Package(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, TrUserData);
+skip_length_delimited_Package(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, TrUserData) ->
Length = X bsl N + Acc,
<<_:Length/binary, Rest2/binary>> = Rest,
- dfp_read_field_def_Package(Rest2, 0, 0, F, F@_1, F@_2, F@_3, TrUserData).
+ dfp_read_field_def_Package(Rest2, 0, 0, F, F@_1, F@_2, F@_3, F@_4, TrUserData).
-skip_group_Package(Bin, _, Z2, FNum, F@_1, F@_2, F@_3, TrUserData) ->
+skip_group_Package(Bin, _, Z2, FNum, F@_1, F@_2, F@_3, F@_4, TrUserData) ->
{_, Rest} = read_group(Bin, FNum),
- dfp_read_field_def_Package(Rest, 0, Z2, FNum, F@_1, F@_2, F@_3, TrUserData).
+ dfp_read_field_def_Package(Rest, 0, Z2, FNum, F@_1, F@_2, F@_3, F@_4, TrUserData).
-skip_32_Package(<<_:32, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> dfp_read_field_def_Package(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData).
+skip_32_Package(<<_:32, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, TrUserData) -> dfp_read_field_def_Package(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, TrUserData).
-skip_64_Package(<<_:64, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> dfp_read_field_def_Package(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData).
+skip_64_Package(<<_:64, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, TrUserData) -> dfp_read_field_def_Package(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, TrUserData).
read_group(Bin, FieldNum) ->
{NumBytes, EndTagLen} = read_gr_b(Bin, 0, 0, 0, 0, FieldNum),
@@ -500,11 +543,17 @@ merge_msg_Package(#{} = PMsg, #{name := NFname} = NMsg, TrUserData) ->
{#{versions := PFversions}, _} -> S1#{versions => PFversions};
{_, _} -> S1
end,
+ S3 = case {PMsg, NMsg} of
+ {#{retired := PFretired}, #{retired := NFretired}} -> S2#{retired => 'erlang_++'(PFretired, NFretired, TrUserData)};
+ {_, #{retired := NFretired}} -> S2#{retired => NFretired};
+ {#{retired := PFretired}, _} -> S2#{retired => PFretired};
+ {_, _} -> S2
+ end,
case {PMsg, NMsg} of
- {#{retired := PFretired}, #{retired := NFretired}} -> S2#{retired => 'erlang_++'(PFretired, NFretired, TrUserData)};
- {_, #{retired := NFretired}} -> S2#{retired => NFretired};
- {#{retired := PFretired}, _} -> S2#{retired => PFretired};
- {_, _} -> S2
+ {#{with_advisories := PFwith_advisories}, #{with_advisories := NFwith_advisories}} -> S3#{with_advisories => 'erlang_++'(PFwith_advisories, NFwith_advisories, TrUserData)};
+ {_, #{with_advisories := NFwith_advisories}} -> S3#{with_advisories => NFwith_advisories};
+ {#{with_advisories := PFwith_advisories}, _} -> S3#{with_advisories => PFwith_advisories};
+ {_, _} -> S3
end.
@@ -567,9 +616,19 @@ v_msg_Package(#{name := F1} = M, Path, TrUserData) ->
end;
_ -> ok
end,
+ case M of
+ #{with_advisories := F4} ->
+ if is_list(F4) ->
+ _ = [v_type_int32(Elem, [with_advisories | Path], TrUserData) || Elem <- F4],
+ ok;
+ true -> mk_type_error({invalid_list_of, int32}, F4, [with_advisories | Path])
+ end;
+ _ -> ok
+ end,
lists:foreach(fun (name) -> ok;
(versions) -> ok;
(retired) -> ok;
+ (with_advisories) -> ok;
(OtherKey) -> mk_type_error({extraneous_key, OtherKey}, M, Path)
end,
maps:keys(M)),
@@ -636,7 +695,8 @@ get_msg_defs() ->
{{msg, 'Package'},
[#{name => name, fnum => 1, rnum => 2, type => string, occurrence => required, opts => []},
#{name => versions, fnum => 2, rnum => 3, type => string, occurrence => repeated, opts => []},
- #{name => retired, fnum => 3, rnum => 4, type => int32, occurrence => repeated, opts => [packed]}]}].
+ #{name => retired, fnum => 3, rnum => 4, type => int32, occurrence => repeated, opts => [packed]},
+ #{name => with_advisories, fnum => 5, rnum => 5, type => int32, occurrence => repeated, opts => [packed]}]}].
get_msg_names() -> ['Versions', 'Package'].
@@ -666,7 +726,8 @@ find_msg_def('Versions') -> [#{name => packages, fnum => 1, rnum => 2, type => {
find_msg_def('Package') ->
[#{name => name, fnum => 1, rnum => 2, type => string, occurrence => required, opts => []},
#{name => versions, fnum => 2, rnum => 3, type => string, occurrence => repeated, opts => []},
- #{name => retired, fnum => 3, rnum => 4, type => int32, occurrence => repeated, opts => [packed]}];
+ #{name => retired, fnum => 3, rnum => 4, type => int32, occurrence => repeated, opts => [packed]},
+ #{name => with_advisories, fnum => 5, rnum => 5, type => int32, occurrence => repeated, opts => [packed]}];
find_msg_def(_) -> error.
diff --git a/apps/rebar/src/vendored/r3_hex_registry.erl b/apps/rebar/src/vendored/r3_hex_registry.erl
index da66f7082..b82849c58 100644
--- a/apps/rebar/src/vendored/r3_hex_registry.erl
+++ b/apps/rebar/src/vendored/r3_hex_registry.erl
@@ -1,4 +1,4 @@
-%% Vendored from hex_core v0.15.0, do not edit manually
+%% Vendored from hex_core v0.17.0, do not edit manually
%% @doc
%% Functions for encoding and decoding Hex registries.
diff --git a/apps/rebar/src/vendored/r3_hex_repo.erl b/apps/rebar/src/vendored/r3_hex_repo.erl
index d2085e22a..a9b6ed081 100644
--- a/apps/rebar/src/vendored/r3_hex_repo.erl
+++ b/apps/rebar/src/vendored/r3_hex_repo.erl
@@ -1,4 +1,4 @@
-%% Vendored from hex_core v0.15.0, do not edit manually
+%% Vendored from hex_core v0.17.0, do not edit manually
%% @doc
%% Repo API.
@@ -12,7 +12,9 @@
get_docs/3,
get_docs_to_file/4,
get_public_key/1,
- get_hex_installs/1
+ get_hex_installs/1,
+ fingerprint/1,
+ fingerprint_equal/2
]).
%%====================================================================
@@ -208,6 +210,66 @@ get_hex_installs(Config) ->
Other
end.
+%% @doc
+%% Computes a SHA256 fingerprint of a PEM-encoded public key.
+%%
+%% Returns a string in the format "SHA256:" followed by base64, which can be used
+%% to verify public keys out-of-band.
+%%
+%% Examples:
+%%
+%% ```
+%% > r3_hex_repo:fingerprint(PublicKeyPem).
+%% "SHA256:abc123..."
+%% '''
+%% @end
+-spec fingerprint(binary()) -> string().
+fingerprint(PublicKeyPem) when is_binary(PublicKeyPem) ->
+ [PemEntry] = public_key:pem_decode(PublicKeyPem),
+ PublicKey = public_key:pem_entry_decode(PemEntry),
+ application:ensure_all_started(ssh),
+ ssh:hostkey_fingerprint(sha256, PublicKey).
+
+%% @doc
+%% Compares a PEM-encoded public key against an expected fingerprint.
+%%
+%% Uses constant-time comparison to prevent timing attacks.
+%%
+%% Examples:
+%%
+%% ```
+%% > r3_hex_repo:fingerprint_equal(PublicKeyPem, "SHA256:abc123...").
+%% true
+%% '''
+%% @end
+-spec fingerprint_equal(binary(), iodata()) -> boolean().
+fingerprint_equal(PublicKeyPem, ExpectedFingerprint) when is_binary(PublicKeyPem) ->
+ ActualFingerprint = fingerprint(PublicKeyPem),
+ constant_time_compare(
+ list_to_binary(ActualFingerprint),
+ iolist_to_binary(ExpectedFingerprint)
+ ).
+
+%% @private
+%% Constant-time comparison to prevent timing attacks.
+%% Uses crypto:hash_equals/2 on OTP 25+, falls back to manual comparison on older versions.
+-if(?OTP_RELEASE >= 25).
+constant_time_compare(A, B) when byte_size(A) =/= byte_size(B) ->
+ false;
+constant_time_compare(A, B) ->
+ crypto:hash_equals(A, B).
+-else.
+constant_time_compare(A, B) when byte_size(A) =:= byte_size(B) ->
+ constant_time_compare(A, B, 0);
+constant_time_compare(_, _) ->
+ false.
+
+constant_time_compare(<>, <>, Acc) ->
+ constant_time_compare(RestA, RestB, Acc bor (X bxor Y));
+constant_time_compare(<<>>, <<>>, Acc) ->
+ Acc =:= 0.
+-endif.
+
%%====================================================================
%% Internal functions
%%====================================================================
diff --git a/apps/rebar/src/vendored/r3_hex_safe_binary_to_term.erl b/apps/rebar/src/vendored/r3_hex_safe_binary_to_term.erl
index cccc35ecb..a58495737 100644
--- a/apps/rebar/src/vendored/r3_hex_safe_binary_to_term.erl
+++ b/apps/rebar/src/vendored/r3_hex_safe_binary_to_term.erl
@@ -1,4 +1,4 @@
-%% Vendored from hex_core v0.15.0, do not edit manually
+%% Vendored from hex_core v0.17.0, do not edit manually
%% @hidden
%% Safe deserialization of Erlang terms from binary.
diff --git a/apps/rebar/src/vendored/r3_hex_tarball.erl b/apps/rebar/src/vendored/r3_hex_tarball.erl
index b84834bd3..e8c24a96c 100644
--- a/apps/rebar/src/vendored/r3_hex_tarball.erl
+++ b/apps/rebar/src/vendored/r3_hex_tarball.erl
@@ -1,4 +1,4 @@
-%% Vendored from hex_core v0.15.0, do not edit manually
+%% Vendored from hex_core v0.17.0, do not edit manually
%% @doc
%% Functions for creating and unpacking Hex tarballs.
@@ -12,13 +12,14 @@
format_error/1
]).
-ifdef(TEST).
--export([do_decode_metadata/1, gzip/1, normalize_requirements/1]).
+-export([do_decode_metadata/1, do_decode_metadata/2, gzip/1, normalize_requirements/1]).
-endif.
-define(VERSION, <<"3">>).
-define(HASH_CHUNK_SIZE, 65536).
-define(MAX_VERSION_SIZE, 32).
-define(MAX_CHECKSUM_SIZE, 128).
--define(MAX_METADATA_SIZE, 128 * 1024).
+-define(MAX_METADATA_SIZE, 1024 * 1024).
+-define(METADATA_CHUNK_SIZE, 4096).
-define(BUILD_TOOL_FILES, [
{<<"mix.exs">>, <<"mix">>},
{<<"rebar.config">>, <<"rebar3">>},
@@ -68,6 +69,7 @@ create(Metadata, Files, Config) ->
tarball_max_size := TarballMaxSize,
tarball_max_uncompressed_size := TarballMaxUncompressedSize
} = Config,
+ FilesRoot = maps:get(tarball_files_root, Config, "."),
MetadataBinary = encode_metadata(Metadata),
@@ -75,35 +77,42 @@ create(Metadata, Files, Config) ->
false ->
{error, {tarball, {file_too_big, "metadata.config"}}};
true ->
- ContentsTarball = create_memory_tarball(Files),
- ContentsTarballCompressed = gzip(ContentsTarball),
- InnerChecksum = inner_checksum(?VERSION, MetadataBinary, ContentsTarballCompressed),
- InnerChecksumBase16 = encode_base16(InnerChecksum),
-
- OuterFiles = [
- {"VERSION", ?VERSION},
- {"CHECKSUM", InnerChecksumBase16},
- {"metadata.config", MetadataBinary},
- {"contents.tar.gz", ContentsTarballCompressed}
- ],
-
- case valid_size(ContentsTarball, TarballMaxUncompressedSize) of
- true ->
- Tarball = create_memory_tarball(OuterFiles),
- OuterChecksum = checksum(Tarball),
+ case validate_create_files(Files, FilesRoot) of
+ {ok, ValidatedFiles} ->
+ ContentsTarball = create_memory_tarball(ValidatedFiles),
+ ContentsTarballCompressed = gzip(ContentsTarball),
+ InnerChecksum = inner_checksum(
+ ?VERSION, MetadataBinary, ContentsTarballCompressed
+ ),
+ InnerChecksumBase16 = encode_base16(InnerChecksum),
+
+ OuterFiles = [
+ {"VERSION", ?VERSION},
+ {"CHECKSUM", InnerChecksumBase16},
+ {"metadata.config", MetadataBinary},
+ {"contents.tar.gz", ContentsTarballCompressed}
+ ],
- case valid_size(Tarball, TarballMaxSize) of
+ case valid_size(ContentsTarball, TarballMaxUncompressedSize) of
true ->
- {ok, #{
- tarball => Tarball,
- outer_checksum => OuterChecksum,
- inner_checksum => InnerChecksum
- }};
+ Tarball = create_memory_tarball(OuterFiles),
+ OuterChecksum = checksum(Tarball),
+
+ case valid_size(Tarball, TarballMaxSize) of
+ true ->
+ {ok, #{
+ tarball => Tarball,
+ outer_checksum => OuterChecksum,
+ inner_checksum => InnerChecksum
+ }};
+ false ->
+ {error, {tarball, {too_big_compressed, TarballMaxSize}}}
+ end;
false ->
- {error, {tarball, {too_big_compressed, TarballMaxSize}}}
+ {error, {tarball, {too_big_uncompressed, TarballMaxUncompressedSize}}}
end;
- false ->
- {error, {tarball, {too_big_uncompressed, TarballMaxUncompressedSize}}}
+ {error, _} = Error ->
+ Error
end
end.
@@ -134,21 +143,27 @@ create_docs(Files, Config) ->
docs_tarball_max_size := TarballMaxSize,
docs_tarball_max_uncompressed_size := TarballMaxUncompressedSize
} = Config,
+ FilesRoot = maps:get(tarball_files_root, Config, "."),
- UncompressedTarball = create_memory_tarball(Files),
+ case validate_create_files(Files, FilesRoot) of
+ {ok, ValidatedFiles} ->
+ UncompressedTarball = create_memory_tarball(ValidatedFiles),
- case valid_size(UncompressedTarball, TarballMaxUncompressedSize) of
- true ->
- Tarball = gzip(UncompressedTarball),
-
- case valid_size(Tarball, TarballMaxSize) of
+ case valid_size(UncompressedTarball, TarballMaxUncompressedSize) of
true ->
- {ok, Tarball};
+ Tarball = gzip(UncompressedTarball),
+
+ case valid_size(Tarball, TarballMaxSize) of
+ true ->
+ {ok, Tarball};
+ false ->
+ {error, {tarball, {too_big_compressed, TarballMaxSize}}}
+ end;
false ->
- {error, {tarball, {too_big_compressed, TarballMaxSize}}}
+ {error, {tarball, {too_big_uncompressed, TarballMaxUncompressedSize}}}
end;
- false ->
- {error, {tarball, {too_big_uncompressed, TarballMaxUncompressedSize}}}
+ {error, _} = Error ->
+ Error
end.
-spec create_docs(files()) -> {ok, tarball()} | {error, term()}.
@@ -345,6 +360,12 @@ format_error({tarball, {bad_version, Vsn}}) ->
io_lib:format("unsupported version: ~p", [Vsn]);
format_error({tarball, invalid_checksum}) ->
"invalid tarball checksum";
+format_error({tarball, {unsafe_path, Name}}) ->
+ io_lib:format("unsafe path in tarball: ~s", [Name]);
+format_error({tarball, {unsafe_symlink, Name, LinkTarget}}) ->
+ io_lib:format("unsafe symlink in tarball: ~s -> ~s", [Name, LinkTarget]);
+format_error({tarball, {unsupported_file_type, Name, Type}}) ->
+ io_lib:format("unsupported file type in tarball: ~s (~p)", [Name, Type]);
format_error({tarball, Reason}) ->
"tarball error, " ++ r3_hex_erl_tar:format_error(Reason);
format_error({inner_tarball, Reason}) ->
@@ -548,41 +569,291 @@ check_inner_checksum(#{files := Files} = State) ->
%% @private
decode_metadata({error, _} = Error) ->
Error;
-decode_metadata(#{files := #{"metadata.config" := Binary}} = State) when is_binary(Binary) ->
- case do_decode_metadata(Binary) of
+decode_metadata(#{files := #{"metadata.config" := Binary}, config := Config} = State) when
+ is_binary(Binary)
+->
+ Fields = maps:get(metadata_fields, Config, all),
+ case do_decode_metadata(Binary, Fields) of
#{} = Metadata -> maps:put(metadata, normalize_metadata(Metadata), State);
Other -> Other
end.
+-ifdef(TEST).
+do_decode_metadata(Binary) ->
+ do_decode_metadata(Binary, all).
+-endif.
+
%% @private
-do_decode_metadata(Binary) when is_binary(Binary) ->
- {ok, String} = characters_to_list(Binary),
+do_decode_metadata(Binary, all) when is_binary(Binary) ->
+ case decode_metadata_chunked(utf8, Binary, <<>>, [], "", []) of
+ latin1_fallback ->
+ decode_metadata_chunked(latin1, Binary, <<>>, [], "", []);
+ Other ->
+ Other
+ end;
+do_decode_metadata(Binary, Fields) when is_binary(Binary), is_list(Fields) ->
+ case decode_metadata_streaming(utf8, Binary, <<>>, [], "", [], Fields, start) of
+ latin1_fallback ->
+ decode_metadata_streaming(latin1, Binary, <<>>, [], "", [], Fields, start);
+ Other ->
+ Other
+ end.
- case r3_safe_erl_term:string(String) of
- {ok, Tokens, _Line} ->
- try
- Terms = r3_safe_erl_term:terms(Tokens),
- maps:from_list(Terms)
- catch
- error:function_clause ->
- {error, {metadata, invalid_terms}};
- error:badarg ->
- {error, {metadata, not_key_value}}
+%% @private
+%% Streams the metadata.config binary through r3_safe_erl_term:tokens/2 in
+%% small chunks so we never materialize the whole binary as a char list.
+%% Each accepted dot-terminated form is parsed and accumulated immediately,
+%% keeping peak memory at roughly one chunk + one term's tokens + AST.
+decode_metadata_chunked(Encoding, Binary, IncTail, Cont, Chars, Acc) ->
+ case Chars of
+ [] when Binary =:= <<>>, IncTail =:= <<>> ->
+ flush_metadata_eof(Cont, Acc);
+ [] when Binary =:= <<>>, Encoding =:= utf8 ->
+ %% Trailing bytes that can never form a complete UTF-8 sequence —
+ %% restart the whole decode in latin1 mode rather than spin.
+ latin1_fallback;
+ [] ->
+ case decode_metadata_chunk(Encoding, Binary, IncTail) of
+ {ok, NewChars, NewBinary, NewTail} ->
+ feed_metadata(Encoding, Cont, NewChars, NewBinary, NewTail, Acc);
+ latin1_fallback ->
+ latin1_fallback
+ end;
+ _ ->
+ feed_metadata(Encoding, Cont, Chars, Binary, IncTail, Acc)
+ end.
+
+%% @private
+feed_metadata(Encoding, Cont, Chars, Binary, IncTail, Acc) ->
+ case r3_safe_erl_term:tokens(Cont, Chars) of
+ {more, NewCont} ->
+ decode_metadata_chunked(Encoding, Binary, IncTail, NewCont, "", Acc);
+ {done, {ok, Tokens, _}, RestChars} ->
+ case parse_metadata_term(Tokens) of
+ {ok, Term} ->
+ decode_metadata_chunked(
+ Encoding, Binary, IncTail, [], normalize_rest_chars(RestChars), [Term | Acc]
+ );
+ {error, _} = Err ->
+ Err
end;
- {error, {_Line, r3_safe_erl_term, Reason}, _Line2} ->
+ {done, {eof, _}, _} ->
+ finalize_metadata(Acc);
+ {done, {error, {_, r3_safe_erl_term, Reason}, _}, _} ->
{error, {metadata, Reason}}
end.
%% @private
-characters_to_list(Binary) ->
- case unicode:characters_to_list(Binary) of
- List when is_list(List) ->
- {ok, List};
+flush_metadata_eof([], Acc) ->
+ finalize_metadata(Acc);
+flush_metadata_eof(Cont, Acc) ->
+ case r3_safe_erl_term:tokens(Cont, eof) of
+ {done, {eof, _}, _} ->
+ finalize_metadata(Acc);
+ {done, {ok, _Tokens, _}, _} ->
+ {error, {metadata, invalid_terms}};
+ {done, {error, {_, r3_safe_erl_term, Reason}, _}, _} ->
+ {error, {metadata, Reason}}
+ end.
+
+%% @private
+finalize_metadata([]) ->
+ {error, {metadata, invalid_terms}};
+finalize_metadata(Acc) ->
+ try maps:from_list(lists:reverse(Acc)) of
+ Map -> Map
+ catch
+ error:badarg -> {error, {metadata, not_key_value}}
+ end.
+
+%% @private
+parse_metadata_term(Tokens) ->
+ case erl_parse:parse_term(Tokens) of
+ {ok, Term} -> {ok, Term};
+ {error, _} -> {error, {metadata, invalid_terms}}
+ end.
+
+%% @private
+decode_metadata_chunk(utf8, Binary, IncTail) ->
+ {Chunk, Rest} = take_metadata_chunk(Binary),
+ Combined =
+ case IncTail of
+ <<>> -> Chunk;
+ _ -> <>
+ end,
+ case unicode:characters_to_list(Combined, utf8) of
+ L when is_list(L) ->
+ {ok, L, Rest, <<>>};
+ {incomplete, L, NewTail} ->
+ {ok, L, Rest, NewTail};
{error, _, _} ->
- case unicode:characters_to_list(Binary, latin1) of
- List when is_list(List) -> {ok, List};
- Other -> Other
- end
+ latin1_fallback
+ end;
+decode_metadata_chunk(latin1, Binary, _IncTail) ->
+ {Chunk, Rest} = take_metadata_chunk(Binary),
+ {ok, binary_to_list(Chunk), Rest, <<>>}.
+
+%% @private
+take_metadata_chunk(Binary) when byte_size(Binary) > ?METADATA_CHUNK_SIZE ->
+ <> = Binary,
+ {Chunk, Rest};
+take_metadata_chunk(Binary) ->
+ {Binary, <<>>}.
+
+%% @private
+normalize_rest_chars(eof) -> "";
+normalize_rest_chars(L) when is_list(L) -> L.
+
+%% @private
+%% Streams the metadata.config binary through r3_safe_erl_term:token/2 one token
+%% at a time. Forms whose key is in Fields are accumulated and parsed; forms
+%% whose key is not in Fields are discarded with only a depth counter held in
+%% state, so peak memory stays bounded regardless of the unwanted form's size.
+decode_metadata_streaming(Encoding, Binary, IncTail, Cont, Chars, Acc, Fields, State) ->
+ case Chars of
+ [] when Binary =:= <<>>, IncTail =:= <<>> ->
+ flush_metadata_streaming_eof(Cont, Acc, Fields, State);
+ [] when Binary =:= <<>>, Encoding =:= utf8 ->
+ latin1_fallback;
+ [] ->
+ case decode_metadata_chunk(Encoding, Binary, IncTail) of
+ {ok, NewChars, NewBinary, NewTail} ->
+ feed_metadata_streaming(
+ Encoding, Cont, NewChars, NewBinary, NewTail, Acc, Fields, State
+ );
+ latin1_fallback ->
+ latin1_fallback
+ end;
+ _ ->
+ feed_metadata_streaming(Encoding, Cont, Chars, Binary, IncTail, Acc, Fields, State)
+ end.
+
+%% @private
+feed_metadata_streaming(Encoding, Cont, Chars, Binary, IncTail, Acc, Fields, State) ->
+ case r3_safe_erl_term:token(Cont, Chars) of
+ {more, NewCont} ->
+ decode_metadata_streaming(Encoding, Binary, IncTail, NewCont, "", Acc, Fields, State);
+ {done, {ok, Token, _}, RestChars} ->
+ case advance_metadata_state(State, Acc, Fields, Token) of
+ {next, NewState, NewAcc} ->
+ decode_metadata_streaming(
+ Encoding,
+ Binary,
+ IncTail,
+ [],
+ normalize_rest_chars(RestChars),
+ NewAcc,
+ Fields,
+ NewState
+ );
+ {error, _} = Err ->
+ Err
+ end;
+ {done, {eof, _}, _} ->
+ finalize_metadata_streaming(Acc, State);
+ {done, {error, {_, r3_safe_erl_term, Reason}, _}, _} ->
+ {error, {metadata, Reason}}
+ end.
+
+%% @private
+flush_metadata_streaming_eof([], Acc, _Fields, State) ->
+ finalize_metadata_streaming(Acc, State);
+flush_metadata_streaming_eof(Cont, Acc, Fields, State) ->
+ case r3_safe_erl_term:token(Cont, eof) of
+ {done, {ok, Token, _}, _} ->
+ case advance_metadata_state(State, Acc, Fields, Token) of
+ {next, NewState, NewAcc} ->
+ flush_metadata_streaming_eof([], NewAcc, Fields, NewState);
+ {error, _} = Err ->
+ Err
+ end;
+ {done, {eof, _}, _} ->
+ finalize_metadata_streaming(Acc, State);
+ {done, {error, {_, r3_safe_erl_term, Reason}, _}, _} ->
+ {error, {metadata, Reason}}
+ end.
+
+%% @private
+finalize_metadata_streaming(Acc, start) ->
+ finalize_metadata(Acc);
+finalize_metadata_streaming([], between) ->
+ #{};
+finalize_metadata_streaming(Acc, between) ->
+ finalize_metadata(Acc);
+finalize_metadata_streaming(_Acc, _State) ->
+ {error, {metadata, invalid_terms}}.
+
+%% @private
+%% State machine for streaming the metadata.config schema. Forms are required
+%% to be `{<<"key">>, value}.` — anything else is rejected as invalid.
+%%
+%% States: start | between | {after_open, Prefix} | {after_left_binary, Prefix}
+%% | {after_key, KeyChars, Prefix} | {after_right_binary, KeyChars, Prefix}
+%% | {accumulate, Prefix, Depth} | {skip, Depth}
+%%
+%% `start` is the initial position; `between` is the position after a form has
+%% been completed. Distinguishing them lets empty input return the same
+%% invalid_terms error as the non-streaming path while a stream that
+%% successfully skipped every form returns an empty map.
+advance_metadata_state(Open, Acc, _Fields, {'{', _} = T) when Open =:= start; Open =:= between ->
+ {next, {after_open, [T]}, Acc};
+advance_metadata_state({after_open, Prefix}, Acc, _Fields, {'<<', _} = T) ->
+ {next, {after_left_binary, [T | Prefix]}, Acc};
+advance_metadata_state({after_left_binary, Prefix}, Acc, _Fields, {string, _, KeyChars} = T) ->
+ {next, {after_key, KeyChars, [T | Prefix]}, Acc};
+advance_metadata_state({after_key, KeyChars, Prefix}, Acc, _Fields, {'>>', _} = T) ->
+ {next, {after_right_binary, KeyChars, [T | Prefix]}, Acc};
+advance_metadata_state({after_right_binary, KeyChars, Prefix}, Acc, Fields, {',', _} = T) ->
+ case extract_metadata_key(KeyChars) of
+ {ok, Key} ->
+ case lists:member(Key, Fields) of
+ true -> {next, {accumulate, [T | Prefix], 1}, Acc};
+ false -> {next, {skip, 1}, Acc}
+ end;
+ error ->
+ {error, {metadata, not_key_value}}
+ end;
+advance_metadata_state({accumulate, Prefix, 0}, Acc, _Fields, {dot, _} = T) ->
+ Tokens = lists:reverse([T | Prefix]),
+ case parse_metadata_term(Tokens) of
+ {ok, Term} -> {next, between, [Term | Acc]};
+ {error, _} = Err -> Err
+ end;
+advance_metadata_state({accumulate, _, _}, _Acc, _Fields, {dot, _}) ->
+ {error, {metadata, invalid_terms}};
+advance_metadata_state({accumulate, Prefix, Depth}, Acc, _Fields, {Open, _} = T) when
+ Open =:= '{'; Open =:= '['
+->
+ {next, {accumulate, [T | Prefix], Depth + 1}, Acc};
+advance_metadata_state({accumulate, Prefix, Depth}, Acc, _Fields, {Close, _} = T) when
+ Close =:= '}'; Close =:= ']'
+->
+ {next, {accumulate, [T | Prefix], Depth - 1}, Acc};
+advance_metadata_state({accumulate, Prefix, Depth}, Acc, _Fields, T) ->
+ {next, {accumulate, [T | Prefix], Depth}, Acc};
+advance_metadata_state({skip, 0}, Acc, _Fields, {dot, _}) ->
+ {next, between, Acc};
+advance_metadata_state({skip, _}, _Acc, _Fields, {dot, _}) ->
+ {error, {metadata, invalid_terms}};
+advance_metadata_state({skip, Depth}, Acc, _Fields, {Open, _}) when
+ Open =:= '{'; Open =:= '['
+->
+ {next, {skip, Depth + 1}, Acc};
+advance_metadata_state({skip, Depth}, Acc, _Fields, {Close, _}) when
+ Close =:= '}'; Close =:= ']'
+->
+ {next, {skip, Depth - 1}, Acc};
+advance_metadata_state({skip, Depth}, Acc, _Fields, _Token) ->
+ {next, {skip, Depth}, Acc};
+advance_metadata_state(_State, _Acc, _Fields, _Token) ->
+ {error, {metadata, not_key_value}}.
+
+%% @private
+extract_metadata_key(KeyChars) ->
+ try list_to_binary(KeyChars) of
+ Key -> {ok, Key}
+ catch
+ error:badarg -> error
end.
%% @private
@@ -631,6 +902,193 @@ guess_build_tools(Metadata) ->
%% Tar Helpers
%%====================================================================
+%% @private
+validate_create_files(Files, FilesRoot) when is_list(Files) ->
+ validate_create_files(Files, FilesRoot, []).
+
+validate_create_files([], _FilesRoot, Acc) ->
+ {ok, lists:reverse(Acc)};
+validate_create_files([File | Rest], FilesRoot, Acc) ->
+ case validate_create_file(File, FilesRoot) of
+ {ok, ValidatedFile} -> validate_create_files(Rest, FilesRoot, [ValidatedFile | Acc]);
+ {error, _} = Error -> Error
+ end.
+
+validate_create_file({Filename, Contents}, _FilesRoot) when
+ is_list(Filename), is_binary(Contents)
+->
+ case validate_archive_path(Filename) of
+ ok -> {ok, {Filename, Contents}};
+ {error, _} = Error -> Error
+ end;
+validate_create_file(Filename, FilesRoot) when is_list(Filename) ->
+ validate_create_file({Filename, Filename}, FilesRoot);
+validate_create_file({Filename, AbsFilename}, FilesRoot) when
+ is_list(Filename), is_list(AbsFilename)
+->
+ case validate_archive_path(Filename) of
+ ok -> validate_source_file(Filename, AbsFilename, FilesRoot);
+ {error, _} = Error -> Error
+ end.
+
+validate_archive_path(Filename) ->
+ case safe_relative_archive_path(Filename) of
+ false -> {error, {tarball, {unsafe_path, Filename}}};
+ true -> ok
+ end.
+
+validate_source_file(ArchiveName, SourcePath, FilesRoot) ->
+ case source_file_paths(SourcePath, FilesRoot) of
+ {ok, DiskPath, RelativePath, Root} ->
+ validate_source_file_root(ArchiveName, DiskPath, RelativePath, Root);
+ outside_root ->
+ {error, {tarball, {unsafe_path, ArchiveName}}}
+ end.
+
+source_file_paths(SourcePath, FilesRoot) ->
+ Root = normalize_root(filename:absname(FilesRoot)),
+ case source_relative_path(SourcePath, Root) of
+ {ok, RelativePath} ->
+ {ok, source_disk_path(SourcePath, Root), RelativePath, Root};
+ outside_root ->
+ outside_root
+ end.
+
+normalize_root(Path) ->
+ filename:join(normalize_root_parts(filename:split(Path), [])).
+
+normalize_root_parts([], Acc) ->
+ lists:reverse(Acc);
+normalize_root_parts(["." | Parts], Acc) ->
+ normalize_root_parts(Parts, Acc);
+normalize_root_parts([".." | Parts], Acc) ->
+ normalize_root_parent(Parts, Acc);
+normalize_root_parts([Part | Parts], Acc) ->
+ normalize_root_parts(Parts, [Part | Acc]).
+
+normalize_root_parent(Parts, [Root] = Acc) ->
+ case filename:pathtype(Root) of
+ relative -> normalize_root_parts(Parts, []);
+ _ -> normalize_root_parts(Parts, Acc)
+ end;
+normalize_root_parent(Parts, [_Part | Acc]) ->
+ normalize_root_parts(Parts, Acc);
+normalize_root_parent(Parts, []) ->
+ normalize_root_parts(Parts, []).
+
+source_disk_path(SourcePath, Root) ->
+ case filename:pathtype(SourcePath) of
+ absolute -> SourcePath;
+ _ -> filename:join(Root, SourcePath)
+ end.
+
+source_relative_path(SourcePath, Root) ->
+ case filename:pathtype(SourcePath) of
+ absolute -> strip_root_path(filename:split(SourcePath), filename:split(Root));
+ _ -> {ok, SourcePath}
+ end.
+
+strip_root_path([], []) ->
+ {ok, "."};
+strip_root_path(PathParts, []) ->
+ {ok, filename:join(PathParts)};
+strip_root_path([Part | PathParts], [Part | RootParts]) ->
+ strip_root_path(PathParts, RootParts);
+strip_root_path(_PathParts, _RootParts) ->
+ outside_root.
+
+validate_source_file_root(ArchiveName, DiskPath, RelativePath, Root) ->
+ case file:read_link_info(DiskPath, []) of
+ {ok, #file_info{type = Type}} when Type =:= regular; Type =:= directory ->
+ case validate_source_root(ArchiveName, RelativePath, Root) of
+ ok -> {ok, {ArchiveName, DiskPath}};
+ {error, _} = Error -> Error
+ end;
+ {ok, #file_info{type = symlink}} ->
+ {ok, LinkTarget} = file:read_link(DiskPath),
+ ResolvedTarget = archive_join(archive_dirname(ArchiveName), LinkTarget),
+ case safe_relative_archive_path(ResolvedTarget) of
+ false ->
+ {error, {tarball, {unsafe_symlink, ArchiveName, LinkTarget}}};
+ true ->
+ case validate_source_root(ArchiveName, RelativePath, Root) of
+ ok -> {ok, {ArchiveName, DiskPath}};
+ {error, _} = Error -> Error
+ end
+ end;
+ {ok, #file_info{type = Type}} ->
+ {error, {tarball, {unsupported_file_type, ArchiveName, Type}}};
+ _ ->
+ case validate_source_root(ArchiveName, RelativePath, Root) of
+ ok -> {ok, {ArchiveName, DiskPath}};
+ {error, _} = Error -> Error
+ end
+ end.
+
+validate_source_root(ArchiveName, SourcePath, FilesRoot) ->
+ case filelib:safe_relative_path(SourcePath, FilesRoot) of
+ unsafe -> {error, {tarball, {unsafe_path, ArchiveName}}};
+ _ -> ok
+ end.
+
+safe_relative_archive_path(Path) ->
+ case archive_path_absolute(Path) orelse archive_path_drive(Path) of
+ true -> false;
+ false -> safe_relative_archive_path(archive_path_split(Path), [])
+ end.
+
+safe_relative_archive_path([], _Acc) ->
+ true;
+safe_relative_archive_path(["." | Rest], Acc) ->
+ safe_relative_archive_path(Rest, Acc);
+safe_relative_archive_path([".." | _Rest], []) ->
+ false;
+safe_relative_archive_path([".." | Rest], [_ | Acc]) ->
+ safe_relative_archive_path(Rest, Acc);
+safe_relative_archive_path([_Part | Rest], Acc) ->
+ safe_relative_archive_path(Rest, [ok | Acc]).
+
+archive_path_absolute([$/ | _Rest]) ->
+ true;
+archive_path_absolute([$\\ | _Rest]) ->
+ true;
+archive_path_absolute(_Path) ->
+ false.
+
+archive_path_drive([Drive, $: | _Rest]) when
+ Drive >= $a, Drive =< $z;
+ Drive >= $A, Drive =< $Z
+->
+ true;
+archive_path_drive(_Path) ->
+ false.
+
+archive_path_split(Path) ->
+ string:tokens(Path, "/\\").
+
+archive_dirname(Path) ->
+ case archive_path_split(Path) of
+ [] -> ".";
+ [_Name] -> ".";
+ Parts -> string:join(lists:droplast(Parts), "/")
+ end.
+
+archive_join(_Dir, Path) when Path =:= [] ->
+ Path;
+archive_join(_Dir, Path = [$/ | _Rest]) ->
+ Path;
+archive_join(_Dir, Path = [$\\ | _Rest]) ->
+ Path;
+archive_join(_Dir, Path = [Drive, $: | _Rest]) when
+ Drive >= $a, Drive =< $z;
+ Drive >= $A, Drive =< $Z
+->
+ Path;
+archive_join(".", Path) ->
+ Path;
+archive_join(Dir, Path) ->
+ Dir ++ "/" ++ Path.
+
%% @private
unpack_tarball(Source, memory, MaxSize) ->
case r3_hex_erl_tar:extract(Source, [memory, compressed, {max_size, MaxSize}]) of
diff --git a/apps/rebar/src/vendored/r3_safe_erl_term.erl b/apps/rebar/src/vendored/r3_safe_erl_term.erl
index a54aca467..811feed56 100644
--- a/apps/rebar/src/vendored/r3_safe_erl_term.erl
+++ b/apps/rebar/src/vendored/r3_safe_erl_term.erl
@@ -45,7 +45,7 @@
-export([format_error/1]).
%% User code. This is placed here to allow extra attributes.
--file("r3_safe_erl_term.xrl", 26).
+-file("r3_safe_erl_term.xrl", 28).
-export([terms/1]).
@@ -742,17 +742,17 @@ yyaction_5(TokenChars, TokenLine) ->
{ token, { list_to_atom (TokenChars), TokenLine } } .
-compile({inline,yyaction_6/1}).
--file("r3_safe_erl_term.xrl", 20).
+-file("r3_safe_erl_term.xrl", 22).
yyaction_6(TokenLine) ->
- { token, { dot, TokenLine } } .
+ { end_token, { dot, TokenLine } } .
-compile({inline,yyaction_7/1}).
--file("r3_safe_erl_term.xrl", 21).
+-file("r3_safe_erl_term.xrl", 23).
yyaction_7(TokenLine) ->
{ token, { '/', TokenLine } } .
-compile({inline,yyaction_8/0}).
--file("r3_safe_erl_term.xrl", 22).
+-file("r3_safe_erl_term.xrl", 24).
yyaction_8() ->
skip_token .
-file("leexinc.hrl", 377).
diff --git a/apps/rebar/src/vendored/r3_safe_erl_term.xrl b/apps/rebar/src/vendored/r3_safe_erl_term.xrl
index f932f789b..2c7b9f81d 100644
--- a/apps/rebar/src/vendored/r3_safe_erl_term.xrl
+++ b/apps/rebar/src/vendored/r3_safe_erl_term.xrl
@@ -1,4 +1,4 @@
-%% Vendored from hex_core v0.15.0, do not edit manually
+%% Vendored from hex_core v0.17.0, do not edit manually
%%% Author : Robert Virding
%%% Purpose : Token definitions for Erlang.
@@ -19,7 +19,9 @@ Rules.
{D}+ : {token, {integer, TokenLine, list_to_integer(TokenChars)}}.
[\#\[\]}{,+-] : {token, {list_to_atom(TokenChars), TokenLine}}.
(<<|>>|=>) : {token, {list_to_atom(TokenChars), TokenLine}}.
-\. : {token, {dot, TokenLine}}.
+% end_token (not token) lets r3_hex_tarball stream-decode metadata.config
+% one form at a time via r3_safe_erl_term:tokens/2.
+\. : {end_token, {dot, TokenLine}}.
/ : {token, {'/', TokenLine}}.
{WS}+ : skip_token.
diff --git a/apps/rebar/test/mock_pkg_resource.erl b/apps/rebar/test/mock_pkg_resource.erl
index f609b5f36..cb2f1fb4e 100644
--- a/apps/rebar/test/mock_pkg_resource.erl
+++ b/apps/rebar/test/mock_pkg_resource.erl
@@ -101,7 +101,8 @@ mock_download(Opts) ->
<<"version">> => Vsn},
Files = all_files(rebar_app_info:dir(AppInfo1)),
- {ok, #{tarball := Tarball}} = r3_hex_tarball:create(Metadata, archive_names(Dir, Files)),
+ HexConfig = r3_hex_core:default_config(),
+ {ok, #{tarball := Tarball}} = r3_hex_tarball:create(Metadata, archive_names(Dir, Files), HexConfig#{tarball_files_root => Dir}),
Archive = filename:join([Dir, TarApp]),
file:write_file(Archive, Tarball),
diff --git a/apps/rebar/test/rebar_pkg_SUITE.erl b/apps/rebar/test/rebar_pkg_SUITE.erl
index 6a74fcb96..007502291 100644
--- a/apps/rebar/test/rebar_pkg_SUITE.erl
+++ b/apps/rebar/test/rebar_pkg_SUITE.erl
@@ -17,7 +17,8 @@
all() -> [good_uncached, good_cached, badpkg, badhash_nocache,
badindexchk, badhash_cache, bad_to_good, good_disconnect,
bad_disconnect, pkgs_provider, find_highest_matching,
- parse_deps_ignores_optional].
+ parse_deps_ignores_optional,
+ oauth_download_with_token, oauth_download_token_refresh].
init_per_suite(Config) ->
application:start(meck),
@@ -102,6 +103,20 @@ init_per_testcase(bad_disconnect=Name, Config0) ->
{error, econnrefused}
end),
Config;
+init_per_testcase(oauth_download_with_token=Name, Config0) ->
+ Config = [{good_cache, false},
+ {pkg, {<<"goodpkg">>, <<"1.0.0">>}},
+ {oauth_token, <<"test-oauth-token">>}
+ | Config0],
+ mock_config_oauth(Name, Config);
+init_per_testcase(oauth_download_token_refresh=Name, Config0) ->
+ Config = [{good_cache, false},
+ {pkg, {<<"goodpkg">>, <<"1.0.0">>}},
+ {oauth_token, <<"expired-token">>},
+ {oauth_refresh_token, <<"refresh-token">>},
+ {new_oauth_token, <<"new-access-token">>}
+ | Config0],
+ mock_config_oauth_refresh(Name, Config);
init_per_testcase(Name, Config0) ->
Config = [{good_cache, false},
{pkg, {<<"goodpkg">>, <<"1.0.0">>}}
@@ -268,6 +283,44 @@ parse_deps_ignores_optional(_Config) ->
{<<"alias">>, {pkg, <<"ali">>, <<"4.0">>, _, _}}],
Result).
+%% Test that OAuth token is properly sent as Bearer token in requests
+oauth_download_with_token(Config) ->
+ Tmp = ?config(tmp_dir, Config),
+ {Pkg, Vsn} = ?config(pkg, Config),
+ State = ?config(state, Config),
+ OAuthToken = ?config(oauth_token, Config),
+ ExpectedBearer = <<"Bearer ", OAuthToken/binary>>,
+ ?assertEqual(ok,
+ rebar_pkg_resource:download(Tmp, {pkg, Pkg, Vsn, ?good_checksum, ?good_checksum,
+ #{name => <<"hexpm">>, trusted => true}},
+ State, #{}, true)),
+ %% Verify that the Bearer token was sent
+ ?assert(meck:called(r3_hex_repo, get_tarball,
+ [meck:is(fun(#{repo_key := Key}) -> Key =:= ExpectedBearer end), '_', '_'])),
+ Cache = ?config(cache_dir, Config),
+ ?assert(filelib:is_regular(filename:join(Cache, <>))).
+
+%% Test that OAuth token is refreshed on 401 and request is retried
+oauth_download_token_refresh(Config) ->
+ Tmp = ?config(tmp_dir, Config),
+ {Pkg, Vsn} = ?config(pkg, Config),
+ State = ?config(state, Config),
+ _OldToken = ?config(oauth_token, Config),
+ _RefreshToken = ?config(oauth_refresh_token, Config),
+ NewToken = ?config(new_oauth_token, Config),
+ NewBearer = <<"Bearer ", NewToken/binary>>,
+ ?assertEqual(ok,
+ rebar_pkg_resource:download(Tmp, {pkg, Pkg, Vsn, ?good_checksum, ?good_checksum,
+ #{name => <<"hexpm">>, trusted => true}},
+ State, #{}, true)),
+ %% Verify that refresh was called
+ ?assert(meck:called(r3_hex_api_oauth, refresh_token, '_')),
+ %% Verify that the new Bearer token was used for retry
+ ?assert(meck:called(r3_hex_repo, get_tarball,
+ [meck:is(fun(#{repo_key := Key}) -> Key =:= NewBearer end), '_', '_'])),
+ Cache = ?config(cache_dir, Config),
+ ?assert(filelib:is_regular(filename:join(Cache, <>))).
+
%%%%%%%%%%%%%%%
%%% Helpers %%%
%%%%%%%%%%%%%%%
@@ -372,3 +425,214 @@ copy_to_cache({Pkg,Vsn}, Config) ->
Source = filename:join(?config(data_dir, Config), Name),
Dest = filename:join(?config(cache_dir, Config), Name),
ec_file:copy(Source, Dest).
+
+%% Mock config for OAuth tests - similar to mock_config but includes OAuth token handling
+mock_config_oauth(Name, Config) ->
+ Priv = ?config(priv_dir, Config),
+ CacheRoot = filename:join([Priv, "cache", atom_to_list(Name)]),
+ TmpDir = filename:join([Priv, "tmp", atom_to_list(Name)]),
+ Tid = ets:new(registry_table, [public]),
+ AllDeps = [
+ {{<<"goodpkg">>,<<"1.0.0">>}, [[], ?good_checksum, ?good_checksum, [<<"rebar3">>]]}
+ ],
+ ets:insert_new(Tid, AllDeps),
+ CacheDir = filename:join([CacheRoot, "hex", "com", "test", "packages"]),
+ filelib:ensure_dir(filename:join([CacheDir, "registry"])),
+ ok = ets:tab2file(Tid, filename:join([CacheDir, "registry"])),
+
+ catch ets:delete(?PACKAGE_TABLE),
+ rebar_packages:new_package_table(),
+ lists:foreach(fun({{N, Vsn}, [Deps, InnerChecksum, OuterChecksum, _]}) ->
+ {ok, Parsed} = rebar_semver:parse_version(Vsn),
+ ets:insert(?PACKAGE_TABLE, #package{key={ec_cnv:to_binary(N), Parsed, <<"hexpm">>},
+ dependencies=Deps,
+ retired=false,
+ inner_checksum=InnerChecksum,
+ outer_checksum=OuterChecksum})
+ end, AllDeps),
+
+ meck:new(r3_hex_repo, [passthrough]),
+ meck:expect(r3_hex_repo, get_package,
+ fun(_Config, PkgName) ->
+ Matches = ets:match_object(Tid, {{PkgName,'_'}, '_'}),
+ Releases =
+ [#{outer_checksum => OuterChecksum,
+ inner_checksum => InnerChecksum,
+ version => Vsn,
+ dependencies => Deps} ||
+ {{_, Vsn}, [Deps, InnerChecksum, OuterChecksum, _]} <- Matches],
+ {ok, {200, #{}, Releases}}
+ end),
+
+ meck:new(rebar_state, [passthrough]),
+ meck:expect(rebar_state, get,
+ fun(_State, rebar_packages_cdn, _Default) ->
+ "http://test.com/";
+ (_, _, Default) ->
+ Default
+ end),
+ meck:expect(rebar_state, resources,
+ fun(_State) ->
+ DefaultConfig = r3_hex_core:default_config(),
+ %% trusted => true is required for OAuth token resolution
+ [rebar_resource_v2:new(pkg, rebar_pkg_resource,
+ #{repos => [DefaultConfig#{name => <<"hexpm">>,
+ trusted => true}],
+ base_config => #{}})]
+ end),
+
+ meck:new(rebar_dir, [passthrough]),
+ meck:expect(rebar_dir, global_cache_dir, fun(_) -> CacheRoot end),
+
+ meck:expect(rebar_packages, registry_dir, fun(_) -> {ok, CacheDir} end),
+ meck:expect(rebar_packages, package_dir, fun(_, _) -> {ok, CacheDir} end),
+
+ meck:new(rebar_prv_update, [passthrough]),
+ meck:expect(rebar_prv_update, do, fun(State) -> {ok, State} end),
+
+ {Pkg, Vsn} = ?config(pkg, Config),
+ PkgFile = <>,
+ {ok, PkgContents} = file:read_file(filename:join(?config(data_dir, Config), PkgFile)),
+
+ %% Write auth config file with OAuth token
+ OAuthToken = ?config(oauth_token, Config),
+ AuthConfigDir = filename:join([CacheRoot, "config"]),
+ AuthConfigFile = filename:join(AuthConfigDir, "hex.config"),
+ filelib:ensure_dir(AuthConfigFile),
+ AuthConfig = #{<<"$oauth">> => #{
+ access_token => OAuthToken,
+ expires_at => erlang:system_time(second) + 3600
+ }},
+ ok = file:write_file(AuthConfigFile, io_lib:format("~p.~n", [AuthConfig])),
+
+ meck:expect(rebar_dir, global_config_dir, fun(_) -> AuthConfigDir end),
+
+ %% For OAuth test: verify Bearer token is passed and return success
+ meck:expect(r3_hex_repo, get_tarball,
+ fun(#{repo_key := <<"Bearer ", _/binary>>}, _, _) ->
+ {ok, {200, #{<<"etag">> => ?good_etag}, PkgContents}};
+ (_, _, _) ->
+ {ok, {401, #{}, #{<<"message">> => <<"Unauthorized">>}}}
+ end),
+
+ [{cache_root, CacheRoot},
+ {cache_dir, CacheDir},
+ {tmp_dir, TmpDir},
+ {mock_table, Tid},
+ {state, rebar_state:new()} | Config].
+
+%% Mock config for OAuth refresh tests - returns 401 first, then success after refresh
+mock_config_oauth_refresh(Name, Config) ->
+ Priv = ?config(priv_dir, Config),
+ CacheRoot = filename:join([Priv, "cache", atom_to_list(Name)]),
+ TmpDir = filename:join([Priv, "tmp", atom_to_list(Name)]),
+ Tid = ets:new(registry_table, [public]),
+ AllDeps = [
+ {{<<"goodpkg">>,<<"1.0.0">>}, [[], ?good_checksum, ?good_checksum, [<<"rebar3">>]]}
+ ],
+ ets:insert_new(Tid, AllDeps),
+ CacheDir = filename:join([CacheRoot, "hex", "com", "test", "packages"]),
+ filelib:ensure_dir(filename:join([CacheDir, "registry"])),
+ ok = ets:tab2file(Tid, filename:join([CacheDir, "registry"])),
+
+ catch ets:delete(?PACKAGE_TABLE),
+ rebar_packages:new_package_table(),
+ lists:foreach(fun({{N, Vsn}, [Deps, InnerChecksum, OuterChecksum, _]}) ->
+ {ok, Parsed} = rebar_semver:parse_version(Vsn),
+ ets:insert(?PACKAGE_TABLE, #package{key={ec_cnv:to_binary(N), Parsed, <<"hexpm">>},
+ dependencies=Deps,
+ retired=false,
+ inner_checksum=InnerChecksum,
+ outer_checksum=OuterChecksum})
+ end, AllDeps),
+
+ meck:new(r3_hex_repo, [passthrough]),
+ meck:expect(r3_hex_repo, get_package,
+ fun(_Config, PkgName) ->
+ Matches = ets:match_object(Tid, {{PkgName,'_'}, '_'}),
+ Releases =
+ [#{outer_checksum => OuterChecksum,
+ inner_checksum => InnerChecksum,
+ version => Vsn,
+ dependencies => Deps} ||
+ {{_, Vsn}, [Deps, InnerChecksum, OuterChecksum, _]} <- Matches],
+ {ok, {200, #{}, Releases}}
+ end),
+
+ meck:new(rebar_state, [passthrough]),
+ meck:expect(rebar_state, get,
+ fun(_State, rebar_packages_cdn, _Default) ->
+ "http://test.com/";
+ (_, _, Default) ->
+ Default
+ end),
+ meck:expect(rebar_state, resources,
+ fun(_State) ->
+ DefaultConfig = r3_hex_core:default_config(),
+ %% trusted => true is required for OAuth token resolution
+ [rebar_resource_v2:new(pkg, rebar_pkg_resource,
+ #{repos => [DefaultConfig#{name => <<"hexpm">>,
+ trusted => true}],
+ base_config => #{}})]
+ end),
+
+ meck:new(rebar_dir, [passthrough]),
+ meck:expect(rebar_dir, global_cache_dir, fun(_) -> CacheRoot end),
+
+ meck:expect(rebar_packages, registry_dir, fun(_) -> {ok, CacheDir} end),
+ meck:expect(rebar_packages, package_dir, fun(_, _) -> {ok, CacheDir} end),
+
+ meck:new(rebar_prv_update, [passthrough]),
+ meck:expect(rebar_prv_update, do, fun(State) -> {ok, State} end),
+
+ {Pkg, Vsn} = ?config(pkg, Config),
+ PkgFile = <>,
+ {ok, PkgContents} = file:read_file(filename:join(?config(data_dir, Config), PkgFile)),
+
+ OldToken = ?config(oauth_token, Config),
+ RefreshToken = ?config(oauth_refresh_token, Config),
+ NewToken = ?config(new_oauth_token, Config),
+ OldBearer = <<"Bearer ", OldToken/binary>>,
+ NewBearer = <<"Bearer ", NewToken/binary>>,
+
+ %% Write auth config file with expired OAuth token and refresh token
+ AuthConfigDir = filename:join([CacheRoot, "config"]),
+ AuthConfigFile = filename:join(AuthConfigDir, "hex.config"),
+ filelib:ensure_dir(AuthConfigFile),
+ AuthConfig = #{<<"$oauth">> => #{
+ access_token => OldToken,
+ refresh_token => RefreshToken,
+ expires_at => erlang:system_time(second) - 100 %% Expired
+ }},
+ ok = file:write_file(AuthConfigFile, io_lib:format("~p.~n", [AuthConfig])),
+
+ meck:expect(rebar_dir, global_config_dir, fun(_) -> AuthConfigDir end),
+
+ %% Mock update_repo_auth_config to track calls but not actually write
+ meck:new(rebar_hex_repos, [passthrough]),
+ meck:expect(rebar_hex_repos, update_repo_auth_config, fun(_Updates, _RepoName, _State) -> ok end),
+
+ %% Return 401 for old token, 200 for new token
+ meck:expect(r3_hex_repo, get_tarball,
+ fun(#{repo_key := Key}, _, _) when Key =:= OldBearer ->
+ {ok, {401, #{}, #{<<"message">> => <<"Unauthorized">>}}};
+ (#{repo_key := Key}, _, _) when Key =:= NewBearer ->
+ {ok, {200, #{<<"etag">> => ?good_etag}, PkgContents}};
+ (_, _, _) ->
+ {ok, {401, #{}, #{<<"message">> => <<"Unauthorized">>}}}
+ end),
+
+ %% Mock OAuth refresh
+ meck:new(r3_hex_api_oauth, [passthrough]),
+ meck:expect(r3_hex_api_oauth, refresh_token,
+ fun(_Config, _ClientId, _RefreshToken) ->
+ {ok, {200, #{}, #{<<"access_token">> => NewToken,
+ <<"refresh_token">> => <<"new-refresh-token">>,
+ <<"expires_in">> => 3600}}}
+ end),
+
+ [{cache_root, CacheRoot},
+ {cache_dir, CacheDir},
+ {tmp_dir, TmpDir},
+ {mock_table, Tid},
+ {state, rebar_state:new()} | Config].
diff --git a/apps/rebar/test/rebar_pkg_repos_SUITE.erl b/apps/rebar/test/rebar_pkg_repos_SUITE.erl
index 4cb5ee26a..7113acc44 100644
--- a/apps/rebar/test/rebar_pkg_repos_SUITE.erl
+++ b/apps/rebar/test/rebar_pkg_repos_SUITE.erl
@@ -357,14 +357,14 @@ organization_merging(_Config) ->
?assertMatch({ok,
#resource{state=#{repos := [#{name := <<"hexpm:repo-1">>,
parent := <<"hexpm">>,
- repo_name := <<"repo-1">>,
+ repo_name := <<"hexpm">>,
api_repository := <<"repo-1">>,
repo_organization := <<"repo-1">>,
read_key := <<"read key">>,
write_key := <<"write key hexpm">>},
#{name := <<"hexpm:repo-2">>,
parent := <<"hexpm">>,
- repo_name := <<"repo-2">>,
+ repo_name := <<"hexpm">>,
api_repository := <<"repo-2">>,
repo_organization := <<"repo-2">>,
read_key := <<"read key 2">>,
diff --git a/vendor_hex_core.sh b/vendor_hex_core.sh
index 79eaa2c98..e596a68ea 100755
--- a/vendor_hex_core.sh
+++ b/vendor_hex_core.sh
@@ -39,6 +39,7 @@ filenames="hex_core.hrl \
hex_api_package_owner.erl \
hex_api_release.erl \
hex_api_user.erl \
+ hex_cli_auth.erl \
hex_licenses.erl \
hex_safe_binary_to_term.erl \
safe_erl_term.xrl"
@@ -56,6 +57,7 @@ search_to_replace="hex_core: \
hex_http \
hex_repo \
hex_api \
+ hex_cli_auth \
hex_licenses \
hex_safe_binary_to_term \
safe_erl_term"