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