Packages

A tool to audit Erlang & Elixir dependencies, to make sure your Gleam ✨ projects really sparkle!

Retired package: Security issue - Vulnerability warnings were never emitted due to an inverted advisory filter. Upgrade to 3.3.1 or 4.0.0-rc2+.

Current section

Files

Jump to
go_over src go_over.erl
Raw

src/go_over.erl

-module(go_over).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/go_over.gleam").
-export([warnings_for_json_results/1, print_json_warnings/1, skipped_workspace_warnings/1, print_warnings/3, audit_project/2, main/0]).
-export_type([audit_result/0]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC(false).
-type audit_result() :: {audit_result,
binary(),
list(go_over@warning:warning()),
list(go_over@warning:warning()),
boolean(),
go_over@config:format()}.
-file("src/go_over.gleam", 35).
?DOC(false).
-spec prefix_label(gleam@option:option(binary()), binary()) -> binary().
prefix_label(Prefix, Label) ->
case Prefix of
{some, Path} ->
<<<<<<"["/utf8, Path/binary>>/binary, "] "/utf8>>/binary,
Label/binary>>;
none ->
Label
end.
-file("src/go_over.gleam", 42).
?DOC(false).
-spec print_warnings_output(
list(go_over@warning:warning()),
go_over@config:config(),
binary(),
gleam@option:option(binary())
) -> nil.
print_warnings_output(Vulns, Conf, Label, Prefix) ->
Label@1 = prefix_label(Prefix, Label),
gleam_stdlib:print_error(Label@1),
case erlang:element(6, Conf) of
minimal ->
_pipe = Vulns,
_pipe@1 = gleam@list:map(
_pipe,
fun go_over@warning:format_as_string_minimal/1
),
_pipe@2 = gleam@string:join(_pipe@1, <<""/utf8>>),
gleam_stdlib:print_error(_pipe@2);
j_s_o_n ->
nil;
s_a_r_i_f ->
nil;
_ ->
_pipe@3 = Vulns,
_pipe@4 = gleam@list:map(
_pipe@3,
fun go_over@warning:format_as_string/1
),
_pipe@5 = gleam@string:join(
_pipe@4,
<<"\n-----------------------------------------------\n"/utf8>>
),
gleam_stdlib:print_error(_pipe@5)
end.
-file("src/go_over.gleam", 70).
?DOC(false).
-spec warnings_label(list(go_over@warning:warning()), binary()) -> binary().
warnings_label(Vulns, Kind) ->
<<<<<<<<<<"⛔ "/utf8,
(erlang:integer_to_binary(erlang:length(Vulns)))/binary>>/binary,
" "/utf8>>/binary,
Kind/binary>>/binary,
"(s) FOUND!"/utf8>>/binary,
(<<"\n-----------------------------------------------\n"/utf8>>)/binary>>.
-file("src/go_over.gleam", 79).
?DOC(false).
-spec info_label(list(go_over@warning:warning())) -> binary().
info_label(Vulns) ->
<<<<<<"ℹ️ "/utf8, (erlang:integer_to_binary(erlang:length(Vulns)))/binary>>/binary,
" Item(s) of Note"/utf8>>/binary,
(<<"\n-----------------------------------------------\n"/utf8>>)/binary>>.
-file("src/go_over.gleam", 86).
?DOC(false).
-spec warnings_for_json(audit_result()) -> list(go_over@warning:warning()).
warnings_for_json(Result) ->
lists:append(erlang:element(4, Result), erlang:element(3, Result)).
-file("src/go_over.gleam", 90).
?DOC(false).
-spec warnings_for_json_results(list(audit_result())) -> list(go_over@warning:warning()).
warnings_for_json_results(Results) ->
gleam@list:flat_map(Results, fun warnings_for_json/1).
-file("src/go_over.gleam", 94).
?DOC(false).
-spec print_json_warnings(list(go_over@warning:warning())) -> nil.
print_json_warnings(Warnings) ->
_pipe = Warnings,
_pipe@1 = gleam@list:map(_pipe, fun go_over@warning:format_as_json/1),
_pipe@2 = gleam@json:preprocessed_array(_pipe@1),
_pipe@3 = gleam@json:to_string(_pipe@2),
gleam_stdlib:print_error(_pipe@3).
-file("src/go_over.gleam", 102).
?DOC(false).
-spec write_sarif(list(audit_result()), gleam@option:option(binary())) -> nil.
write_sarif(Results, Output) ->
Runs = gleam@list:map(
Results,
fun(Result) ->
{erlang:element(2, Result), warnings_for_json(Result)}
end
),
Content = begin
_pipe = go_over@sarif:to_sarif_log(Runs),
gleam@json:to_string(_pipe)
end,
case Output of
none ->
_pipe@1 = Content,
gleam_stdlib:println(_pipe@1);
{some, Path} ->
case begin
_pipe@2 = Path,
simplifile:write(_pipe@2, Content)
end of
{ok, nil} ->
nil;
{error, _} ->
gleam_stdlib:println_error(
<<"could not write SARIF output to "/utf8, Path/binary>>
),
shellout_ffi:os_exit(1)
end
end.
-file("src/go_over.gleam", 128).
?DOC(false).
-spec skipped_workspace_warnings(list(binary())) -> list(go_over@warning:warning()).
skipped_workspace_warnings(Skipped) ->
gleam@list:map(
Skipped,
fun(Path) ->
go_over@warning:info_to_warning(
Path,
<<<<"Info: project at '"/utf8, Path/binary>>/binary,
"' was skipped (exceeds workspace_max_depth)"/utf8>>
)
end
).
-file("src/go_over.gleam", 139).
?DOC(false).
-spec print_warnings(
list(go_over@warning:warning()),
go_over@config:config(),
gleam@option:option(binary())
) -> nil.
print_warnings(Vulns, Conf, Prefix) ->
print_warnings_output(
Vulns,
Conf,
warnings_label(Vulns, <<"WARNING"/utf8>>),
Prefix
),
shellout_ffi:os_exit(1).
-file("src/go_over.gleam", 148).
?DOC(false).
-spec read_project_config(binary()) -> go_over@config:config().
read_project_config(Project_root) ->
Gleam_toml = filepath:join(Project_root, <<"gleam.toml"/utf8>>),
case simplifile:read(Gleam_toml) of
{ok, _} ->
go_over@config:read_config(Gleam_toml);
{error, _} ->
go_over@config:default_config()
end.
-file("src/go_over.gleam", 435).
?DOC(false).
-spec run_deps_outdated(binary()) -> boolean().
run_deps_outdated(Project_root) ->
go_over@util@print:high(
<<"The --outdated flag is deprecated. Use `gleam deps outdated` instead."/utf8>>
),
case shellout:command(
<<"gleam"/utf8>>,
[<<"deps"/utf8>>, <<"outdated"/utf8>>],
Project_root,
[let_be_stdout]
) of
{ok, _} ->
false;
{error, _} ->
true
end.
-file("src/go_over.gleam", 157).
?DOC(false).
-spec audit_project(go_over@config:flags(), binary()) -> {ok, audit_result()} |
{error, binary()}.
audit_project(Flags, Project_root) ->
Manifest_toml = filepath:join(Project_root, <<"manifest.toml"/utf8>>),
Project_config = read_project_config(Project_root),
gleam@result:'try'(
go_over@config:merge_flags_and_config(Flags, Project_config),
fun(Conf) ->
go_over@util@globals:set_project_root(Project_root),
go_over@util@globals:set_verbose(erlang:element(7, Conf)),
go_over@util@globals:set_use_global_cache(erlang:element(8, Conf)),
go_over@util@globals:set_force(erlang:element(5, Conf)),
Machine_output = (erlang:element(6, Conf) =:= s_a_r_i_f) orelse (erlang:element(
6,
Conf
)
=:= j_s_o_n),
Spinner = case Machine_output of
true ->
none;
false ->
go_over@util@spinner:new_spinner(<<"Let's do this!"/utf8>>)
end,
gxyz@function:ignore_result(
erlang:element(5, Conf),
gxyz@function:freeze1(
fun simplifile_erl:delete/1,
go_over@util@globals:go_over_path()
)
),
go_over@util@spinner:set_text_spinner(
Spinner,
<<"Reading manifest"/utf8>>
),
Manifest_pkgs = go_over@packages:read_manifest(Manifest_toml),
Pkgs_audited = begin
_pipe = Manifest_pkgs,
_pipe@1 = go_over@config:filter_dev_dependencies(Conf, _pipe),
go_over@config:filter_indirect(Conf, _pipe@1)
end,
Hex_pkgs = gleam@list:filter(
Pkgs_audited,
fun(P) -> erlang:element(6, P) =:= package_source_hex end
),
go_over@util@spinner:set_text_spinner(
Spinner,
<<"Checking packages: "/utf8,
(go_over@util@print:raw(
<<"vulnerable"/utf8>>,
<<"red"/utf8>>
))/binary>>
),
All_advisories = go_over@advisories@advisories:fetch_all(),
Vulnerable_warnings = go_over@sources:get_vulnerable_warnings(
Pkgs_audited,
Conf,
All_advisories
),
go_over@util@spinner:set_text_spinner(
Spinner,
<<"Checking packages: "/utf8,
(go_over@util@print:raw(
<<"retired"/utf8>>,
<<"yellow"/utf8>>
))/binary>>
),
Retired_warnings = go_over@sources:get_retired_warnings(
Hex_pkgs,
Conf
),
{Hex_warnings, Dependency_licenses} = case erlang:element(10, Conf) of
[] ->
{[], []};
_ ->
go_over@util@spinner:set_text_spinner(
Spinner,
<<"Checking packages: "/utf8,
(go_over@util@print:raw(
<<"licenses"/utf8>>,
<<"brightmagenta"/utf8>>
))/binary>>
),
go_over@sources:get_hex_warnings(Hex_pkgs, Conf)
end,
go_over@util@spinner:set_text_spinner(
Spinner,
<<"Filtering warnings"/utf8>>
),
Audit_warnings = begin
_pipe@2 = lists:append(Retired_warnings, Vulnerable_warnings),
lists:append(_pipe@2, Hex_warnings)
end,
Unnecessary_warnings = go_over@config:unnecessary_ignore_warnings(
Conf,
Manifest_pkgs,
Audit_warnings,
Dependency_licenses,
All_advisories
),
Fatal_warnings = begin
_pipe@3 = Audit_warnings,
_pipe@4 = go_over@config:filter_package_warnings(Conf, _pipe@3),
go_over@config:filter_severity(Conf, _pipe@4)
end,
go_over@util@spinner:stop_spinner(Spinner),
Outdated_failed = case erlang:element(3, Conf) of
false ->
false;
true ->
run_deps_outdated(Project_root)
end,
Info_warnings = lists:append(
Unnecessary_warnings,
go_over@warning:git_deps_to_warnings(Manifest_pkgs)
),
{ok,
{audit_result,
Project_root,
Fatal_warnings,
Info_warnings,
Outdated_failed,
erlang:element(6, Conf)}}
end
).
-file("src/go_over.gleam", 266).
?DOC(false).
-spec print_no_issues_success(integer()) -> nil.
print_no_issues_success(Info_count) ->
case Info_count of
0 ->
go_over@util@print:success(<<"✅ No warnings found!"/utf8>>);
_ ->
go_over@util@print:success(
<<<<"✅ No security issues found ("/utf8,
(erlang:integer_to_binary(Info_count))/binary>>/binary,
" item(s) of note)"/utf8>>
)
end.
-file("src/go_over.gleam", 278).
?DOC(false).
-spec run(go_over@config:flags()) -> nil.
run(Flags) ->
Workspace_mode = gleam@option:is_some(erlang:element(10, Flags)),
{Results, Workspace_skipped} = case erlang:element(10, Flags) of
{some, Scan_root} ->
Scan_config = read_project_config(Scan_root),
Max_depth = erlang:element(15, Scan_config),
case go_over@workspace:discover_or_error(Scan_root, Max_depth) of
{ok, {discover_result, Projects, Skipped}} ->
{gleam@list:map(
Projects,
fun(Project_root) ->
case audit_project(Flags, Project_root) of
{ok, Result} ->
Result;
{error, E} ->
gleam_stdlib:println_error(E),
shellout_ffi:os_exit(1),
go_over@util@util:do_panic()
end
end
),
Skipped};
{error, E@1} ->
gleam_stdlib:println_error(E@1),
shellout_ffi:os_exit(1),
go_over@util@util:do_panic()
end;
none ->
Project_root@1 = gleam@option:unwrap(
erlang:element(9, Flags),
<<"."/utf8>>
),
Result@2 = case audit_project(Flags, Project_root@1) of
{ok, Result@1} -> Result@1;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"go_over"/utf8>>,
function => <<"run"/utf8>>,
line => 309,
value => _assert_fail,
start => 7678,
'end' => 7736,
pattern_start => 7689,
pattern_end => 7699})
end,
{[Result@2], []}
end,
Skipped_warnings = skipped_workspace_warnings(Workspace_skipped),
Results@1 = case Skipped_warnings of
[] ->
Results;
_ ->
case Results of
[First | Rest] ->
[{audit_result,
erlang:element(2, First),
erlang:element(3, First),
lists:append(
Skipped_warnings,
erlang:element(4, First)
),
erlang:element(5, First),
erlang:element(6, First)} |
Rest];
[] ->
Results
end
end,
case {Workspace_mode, erlang:element(7, Flags)} of
{true, none} ->
case go_over@config:validate_workspace_formats(
gleam@list:map(
Results@1,
fun(R) -> {erlang:element(6, R), erlang:element(2, R)} end
)
) of
{error, E@2} ->
gleam_stdlib:println_error(E@2),
shellout_ffi:os_exit(1),
go_over@util@util:do_panic();
{ok, nil} ->
nil
end;
{_, _} ->
nil
end,
Prefix_for = fun(Result@3) -> case Workspace_mode of
true ->
{some, erlang:element(2, Result@3)};
false ->
none
end end,
Display_conf = fun(Result@4) -> _record = go_over@config:default_config(),
{config,
erlang:element(2, _record),
erlang:element(3, _record),
erlang:element(4, _record),
erlang:element(5, _record),
erlang:element(6, Result@4),
erlang:element(7, _record),
erlang:element(8, _record),
erlang:element(9, _record),
erlang:element(10, _record),
erlang:element(11, _record),
erlang:element(12, _record),
erlang:element(13, _record),
erlang:element(14, _record),
erlang:element(15, _record),
erlang:element(16, _record),
erlang:element(17, _record)} end,
Output_format = case Results@1 of
[] ->
minimal;
[First@1 | _] ->
erlang:element(6, First@1)
end,
Sarif_output = Output_format =:= s_a_r_i_f,
Json_output = Output_format =:= j_s_o_n,
case {erlang:element(11, Flags), Sarif_output} of
{{some, _}, false} ->
gleam_stdlib:println_error(
<<"--sarif-output requires --format sarif"/utf8>>
),
shellout_ffi:os_exit(1);
{_, _} ->
nil
end,
case {Sarif_output, Json_output} of
{false, false} ->
gleam@list:each(
Results@1,
fun(Result@5) -> case erlang:element(4, Result@5) of
[] ->
nil;
Info ->
print_warnings_output(
Info,
Display_conf(Result@5),
info_label(Info),
Prefix_for(Result@5)
)
end end
);
{false, true} ->
print_json_warnings(warnings_for_json_results(Results@1));
{true, _} ->
nil
end,
Any_fatal = gleam@list:any(
Results@1,
fun(R@1) -> not gleam@list:is_empty(erlang:element(3, R@1)) end
),
Any_outdated_failed = gleam@list:any(
Results@1,
fun(R@2) -> erlang:element(5, R@2) end
),
Info_count = begin
_pipe = gleam@list:flat_map(
Results@1,
fun(R@3) -> erlang:element(4, R@3) end
),
erlang:length(_pipe)
end,
case {Any_fatal, Any_outdated_failed, Sarif_output, Json_output} of
{false, false, true, _} ->
write_sarif(Results@1, erlang:element(11, Flags)),
nil;
{false, false, false, _} ->
print_no_issues_success(Info_count),
nil;
{false, true, true, _} ->
write_sarif(Results@1, erlang:element(11, Flags)),
shellout_ffi:os_exit(1);
{false, true, false, _} ->
shellout_ffi:os_exit(1);
{true, _, true, _} ->
write_sarif(Results@1, erlang:element(11, Flags)),
shellout_ffi:os_exit(1);
{true, _, false, true} ->
shellout_ffi:os_exit(1);
{true, _, false, false} ->
gleam@list:each(
Results@1,
fun(Result@6) -> case erlang:element(3, Result@6) of
[] ->
nil;
Vulns ->
print_warnings_output(
Vulns,
Display_conf(Result@6),
warnings_label(Vulns, <<"WARNING"/utf8>>),
Prefix_for(Result@6)
)
end end
),
shellout_ffi:os_exit(1)
end.
-file("src/go_over.gleam", 259).
?DOC(false).
-spec main() -> nil.
main() ->
case go_over@config:parse_flags(shellout_ffi:start_arguments()) of
{error, Message} ->
gleam_stdlib:println(Message);
{ok, Flags} ->
run(Flags)
end.