defmodule TarakanWeb.API.FindingControllerTest do use TarakanWeb.ConnCase setup do submitter = github_account_fixture() repository = listed_github_repository_fixture(submitter) %{repository: repository, submitter: submitter} end test "returns a serialized public finding", %{ conn: conn, repository: repository, submitter: submitter } do scan = repository |> scan_fixture(submitter, %{"findings_json" => findings_json_with_disclosure_fixture()}) |> publish_scan("public") [finding] = scan.findings conn = get(conn, ~p"/api/findings/#{finding.public_id}") assert %{"finding" => data} = json_response(conn, 200) assert data["public_id"] == finding.public_id assert data["title"] == finding.title assert data["severity"] == "high" assert data["status"] == "verified" assert data["description"] =~ "String-built SQL" assert data["reproduction_steps"] =~ "Run the payload" assert data["affected_versions"] == ">= 1.0, < 2.0" assert data["cwe_id"] == "CWE-89" assert data["cve_id"] == "CVE-2026-12345" assert data["file_path"] == "lib/example/module_1.ex" assert data["line_start"] == 10 assert data["line_end"] == 15 assert data["first_seen_commit_sha"] == scan.commit_sha assert data["last_seen_commit_sha"] == scan.commit_sha assert data["verified_at"] assert is_map(data["counters"]) assert data["repository"] == %{"host" => "github.com", "owner" => "openai", "name" => "codex"} assert data["record_url"] == TarakanWeb.Endpoint.url() <> "/findings/#{finding.public_id}" assert data["inserted_at"] end test "404s for a restricted finding", %{ conn: conn, repository: repository, submitter: submitter } do scan = scan_fixture(repository, submitter, %{"findings_json" => findings_json_fixture(1)}) {:ok, _restricted} = Tarakan.Scans.update_visibility( Tarakan.Accounts.Scope.for_account(moderator_account_fixture()), scan, "restricted", %{ "moderation_reason" => "takedown_review", "moderation_notes" => "Restricted in this test to keep it off the public API." } ) [finding] = scan.findings conn = get(conn, ~p"/api/findings/#{finding.public_id}") assert json_response(conn, 404)["error"] =~ "not found" end test "404s for a summary-only finding", %{ conn: conn, repository: repository, submitter: submitter } do scan = repository |> scan_fixture(submitter, %{"findings_json" => findings_json_fixture(1)}) |> publish_scan("public_summary") [finding] = scan.findings conn = get(conn, ~p"/api/findings/#{finding.public_id}") assert json_response(conn, 404)["error"] =~ "not found" end test "404s for an unknown public id", %{conn: conn} do conn = get(conn, ~p"/api/findings/#{Ecto.UUID.generate()}") assert json_response(conn, 404)["error"] =~ "not found" end defp findings_json_with_disclosure_fixture do Jason.encode!(%{ "tarakan_scan_format" => 1, "findings" => [ %{ "file" => "lib/example/module_1.ex", "line_start" => 10, "line_end" => 15, "severity" => "high", "title" => "Unsanitized input reaches interpolated query (1)", "description" => "String-built SQL executed with request parameters.", "reproduction" => "1. Check out the pinned commit\n2. Run the payload", "affected_versions" => ">= 1.0, < 2.0", "cwe" => "CWE-89", "cve" => "CVE-2026-12345" } ] }) end defp publish_scan(scan, visibility) do scan = confirmation_fixture(scan, reviewer_account_fixture()) scan = confirmation_fixture(scan, reviewer_account_fixture()) scope = Tarakan.Accounts.Scope.for_account(moderator_account_fixture()) if visibility == "public" do scan.repository |> Tarakan.Repositories.Repository.participation_changeset(%{ participation_mode: "maintainer_verified" }) |> Tarakan.Repo.update!() end {:ok, scan} = Tarakan.Scans.accept_scan(scope, scan, %{ "moderation_reason" => "evidence_reviewed", "moderation_notes" => "Two independent reviewers supplied reproducible evidence for the pinned commit." }) {:ok, scan} = Tarakan.Scans.update_visibility(scope, scan, visibility, %{ "moderation_reason" => "disclosure_reviewed", "moderation_notes" => "Disclosure was separately reviewed for scope, secrets, and personal data.", "sensitive_data_reviewed" => "true" }) scan end end