Current section

Files

Jump to
metastatic lib mix tasks metastatic.security_scan.ex
Raw

lib/mix/tasks/metastatic.security_scan.ex

defmodule Mix.Tasks.Metastatic.SecurityScan do
@shortdoc "Scans for security vulnerabilities"
use Mix.Task
alias Metastatic.Analysis.Security
alias Metastatic.Builder
def run(args) do
{opts, files, _} = OptionParser.parse(args, strict: [format: :string, language: :string])
case files do
[] ->
Mix.shell().error("Usage: mix metastatic.security_scan FILE")
exit({:shutdown, 2})
[file | _] ->
analyze(file, opts[:language], opts[:format] || "text")
end
end
defp analyze(file, language, format) do
unless File.exists?(file),
do:
(
Mix.shell().error("File not found")
exit({:shutdown, 2})
)
source = File.read!(file)
lang = language || detect_lang(file)
case Builder.from_source(source, String.to_atom(lang)) do
{:ok, doc} ->
{:ok, result} = Security.analyze(doc)
output =
if format == "json",
do: Jason.encode!(Security.Result.to_map(result), pretty: true),
else: result.summary
Mix.shell().info(output)
exit({:shutdown, if(result.has_vulnerabilities?, do: 1, else: 0)})
{:error, reason} ->
Mix.shell().error("Parse error: #{inspect(reason)}")
exit({:shutdown, 2})
end
end
defp detect_lang(file) do
case Path.extname(file) do
".py" ->
"python"
".ex" ->
"elixir"
".exs" ->
"elixir"
".erl" ->
"erlang"
".rb" ->
"ruby"
".hs" ->
"haskell"
_ ->
Mix.shell().error("Cannot detect language")
exit({:shutdown, 2})
end
end
end