Packages
Mix tasks (mix vet, mix vet.check) for the Vet dependency security scanner.
Current section
Files
Jump to
Current section
Files
lib/mix/tasks/vet.check.ex
defmodule Mix.Tasks.Vet.Check do
@moduledoc """
Pre-install dependency check. Run BEFORE `mix deps.get` to verify
that declared dependencies exist on hex.pm and aren't typosquats
or slopsquatting targets.
Reads mix.exs directly — does not require mix.lock or fetched deps.
## Usage
mix vet.check [--path PATH]
## Options
* `--path`, `-p` — Path to the project root (default: current project)
"""
@shortdoc "Pre-install check: verify dependencies before mix deps.get"
use Mix.Task
@impl Mix.Task
def run(args) do
Application.ensure_all_started(:vet_core)
{opts, rest, _} =
OptionParser.parse(args,
strict: [path: :string],
aliases: [p: :path]
)
path = opts[:path] || List.first(rest) || Mix.Project.config()[:root] || File.cwd!()
Mix.shell().info("Checking dependencies in #{path}/mix.exs...")
case VetCore.PreInstallCheck.check_deps(path) do
{:ok, []} ->
Mix.shell().info("All dependencies look clean.")
{:ok, results} ->
has_critical? =
Enum.reduce(results, false, fn result, critical? ->
print_result(result)
critical? or result.phantom?
end)
if has_critical? do
Mix.raise(
"Vet: one or more dependencies do not exist on hex.pm. " <>
"Verify package names before running mix deps.get."
)
end
{:error, reason} ->
Mix.raise("Vet pre-install check failed: #{reason}")
end
end
defp print_result(result) do
name = result.package
severity = if result.phantom?, do: "CRITICAL", else: "WARNING"
color = if result.phantom?, do: :red, else: :yellow
Mix.shell().info([
color,
"\n[#{severity}] :#{name}",
:reset
])
Mix.shell().info(" #{result.assessment}")
if result.metadata do
Mix.shell().info(" Downloads: #{result.metadata.downloads || "unknown"}")
Mix.shell().info(" Owners: #{result.metadata.owner_count || "unknown"}")
end
for warning <- result.typosquat_warnings do
Mix.shell().info([:yellow, " Typosquat: #{warning}", :reset])
end
end
end