Fresh repository history for elektrine/tarakan hosted at https://git.elektrine.com/elektrine/tarakan.
137 lines
4.6 KiB
Elixir
137 lines
4.6 KiB
Elixir
defmodule TarakanWeb.API.InfestationControllerTest do
|
|
use TarakanWeb.ConnCase, async: true
|
|
|
|
import Ecto.Query, only: [from: 2]
|
|
|
|
alias Tarakan.FindingMemory
|
|
|
|
setup do
|
|
submitter = github_account_fixture()
|
|
other = github_account_fixture()
|
|
repo_a = listed_github_repository_fixture(submitter)
|
|
{:ok, repo_b} = Tarakan.Repositories.register_github_repository("acme/widget", other)
|
|
repo_b = listed_repository_fixture(repo_b)
|
|
|
|
title = "API infestation sample #{System.unique_integer([:positive])}"
|
|
|
|
findings = fn path ->
|
|
Jason.encode!(%{
|
|
"tarakan_scan_format" => 1,
|
|
"findings" => [
|
|
%{
|
|
"file" => path,
|
|
"line_start" => 1,
|
|
"line_end" => 2,
|
|
"severity" => "high",
|
|
"title" => title,
|
|
"description" => "Shared issue class for the patterns API test."
|
|
}
|
|
]
|
|
})
|
|
end
|
|
|
|
scan_fixture(repo_a, submitter, %{"findings_json" => findings.("lib/a.ex")})
|
|
scan_fixture(repo_b, other, %{"findings_json" => findings.("src/b.rs")})
|
|
|
|
%{pattern_key: FindingMemory.pattern_key(title), title: title}
|
|
end
|
|
|
|
test "lists patterns", %{conn: conn, pattern_key: pattern_key} do
|
|
conn = get(conn, ~p"/api/infestations")
|
|
|
|
assert %{"patterns" => patterns} = json_response(conn, 200)
|
|
assert pattern = Enum.find(patterns, &(&1["pattern_key"] == pattern_key))
|
|
assert pattern["repo_count"] >= 2
|
|
assert pattern["instance_count"] >= 2
|
|
assert pattern["record_url"] =~ "/infestations/#{pattern_key}"
|
|
end
|
|
|
|
test "whitelists query params", %{conn: conn, pattern_key: pattern_key} do
|
|
conn = get(conn, ~p"/api/infestations?days=13&min_repos=0&limit=5000")
|
|
assert %{"patterns" => _} = json_response(conn, 200)
|
|
|
|
conn = get(conn, ~p"/api/infestations?days=7&min_repos=2&limit=10")
|
|
assert %{"patterns" => patterns} = json_response(conn, 200)
|
|
assert Enum.any?(patterns, &(&1["pattern_key"] == pattern_key))
|
|
end
|
|
|
|
test "shows a pattern with its first page of instances", %{
|
|
conn: conn,
|
|
pattern_key: pattern_key,
|
|
title: title
|
|
} do
|
|
conn = get(conn, ~p"/api/infestations/#{pattern_key}")
|
|
|
|
assert %{"pattern" => pattern, "instances" => instances} = json_response(conn, 200)
|
|
assert pattern["pattern_key"] == pattern_key
|
|
assert pattern["title"] =~ title
|
|
|
|
assert length(instances) >= 2
|
|
assert Enum.any?(instances, &(&1["repository"]["owner"] == "openai"))
|
|
assert Enum.any?(instances, &(&1["repository"]["owner"] == "acme"))
|
|
end
|
|
|
|
test "404s for an unknown pattern", %{conn: conn} do
|
|
conn = get(conn, ~p"/api/infestations/no-such-pattern")
|
|
assert json_response(conn, 404)["error"] =~ "not found"
|
|
end
|
|
|
|
describe "vaccine packs" do
|
|
alias Tarakan.Accounts.Scope
|
|
alias Tarakan.FindingSignals
|
|
alias Tarakan.Repo
|
|
alias Tarakan.Scans.CanonicalFinding
|
|
|
|
# The endpoint must refuse to invent a detector. It used to always return
|
|
# one, and the one it returned matched nothing.
|
|
test "404s while nobody has written a validated detector", %{
|
|
conn: conn,
|
|
pattern_key: pattern_key
|
|
} do
|
|
conn = get(conn, ~p"/api/infestations/#{pattern_key}/vaccine.yaml")
|
|
|
|
assert %{"error" => error} = json_response(conn, 404)
|
|
assert error =~ "no validated detector"
|
|
end
|
|
|
|
test "serves the validated rule once one exists", %{conn: conn, pattern_key: pattern_key} do
|
|
# Put this infestation's findings into one code cluster.
|
|
cluster = "code:vaccinetest"
|
|
|
|
Repo.all(from f in CanonicalFinding, where: f.pattern_key == ^pattern_key)
|
|
|> Enum.each(fn finding ->
|
|
finding
|
|
|> CanonicalFinding.embedding_changeset(%{code_pattern_key: cluster})
|
|
|> Repo.update!()
|
|
end)
|
|
|
|
scope = Scope.for_account(reviewer_account_fixture())
|
|
|
|
{:ok, _rule} =
|
|
FindingSignals.put_rule(scope, cluster, %{
|
|
engine: "semgrep",
|
|
language: "elixir",
|
|
rule_yaml: """
|
|
rules:
|
|
- id: tarakan-real-detector
|
|
message: Shared issue class
|
|
severity: ERROR
|
|
languages: [elixir]
|
|
patterns:
|
|
- pattern: System.cmd($C, $A)
|
|
""",
|
|
checked_count: 2,
|
|
matched_count: 2,
|
|
matched_finding_ids: [Ecto.UUID.generate(), Ecto.UUID.generate()]
|
|
})
|
|
|
|
conn = get(conn, ~p"/api/infestations/#{pattern_key}/vaccine.yaml")
|
|
|
|
assert body = response(conn, 200)
|
|
assert get_resp_header(conn, "content-type") |> hd() =~ "application/x-yaml"
|
|
assert body =~ "tarakan-real-detector"
|
|
assert body =~ "matched 2 of 2 known instances"
|
|
refute body =~ "tarakan-vaccine-placeholder"
|
|
end
|
|
end
|
|
end
|