defmodule GitGudWeb.SecurityLiveTest do
@moduledoc """
A repository's Security page and the switches that turn alerts on:
who sees the page and its header link, the alert lists, a personal
repository's and an org's switch (each audited), and a default-branch
push queueing a scan.
"""
use GitGudWeb.ConnCase, async: false
use Oban.Testing, repo: GitGud.Repo
import Ecto.Query
import Phoenix.LiveViewTest
import GitGud.AccountsFixtures
import GitGud.ForgeFixtures
alias GitGud.Advisories
alias GitGud.Advisories.Alert
alias GitGud.Advisories.Workers.Scan
alias GitGud.Organizations
alias GitGud.Repositories.Storage
setup do
# A "scanner" that exists, so the instance reads as able to scan.
scanner = Path.join(System.tmp_dir!(), "osv-#{System.unique_integer([:positive])}")
File.write!(scanner, "#!/bin/sh\necho '{}'\n")
File.chmod!(scanner, 0o755)
before = Application.get_env(:git_gud, Advisories, [])
Application.put_env(:git_gud, Advisories, Keyword.merge(before, scanner: scanner))
on_exit(fn ->
Application.put_env(:git_gud, Advisories, before)
File.rm(scanner)
end)
{owner, repo} = repository_fixture(%{visibility: "public"})
repo = GitGud.Repo.preload(repo, [:owner, :organization])
{:ok, owner: owner, repo: repo, path: "/r/#{Storage.repo_handle(repo)}/#{repo.name}"}
end
defp alert!(repo, attrs) do
%Alert{repository_id: repo.id, first_seen_at: DateTime.utc_now(:second)}
|> Alert.changeset(
Map.merge(
%{
advisory_id: "GHSA-#{System.unique_integer([:positive])}",
ecosystem: "Hex",
package: "plug",
version: "1.19.1",
manifest_path: "mix.lock",
severity: 8.7,
fixed_versions: ["1.19.5"]
},
attrs
)
)
|> Ecto.Changeset.change(Map.take(attrs, [:state]))
|> GitGud.Repo.insert!()
end
describe "the page" do
setup %{repo: repo} do
{:ok, repo} = Advisories.set_repo(repo, true)
{:ok, repo: repo}
end
test "lists open alerts, and the fixed ones on their tab", %{
conn: conn,
owner: owner,
repo: repo,
path: path
} do
open = alert!(repo, %{package: "plug"})
fixed = alert!(repo, %{package: "mint", state: "fixed"})
{:ok, view, _} = live(log_in_user(conn, owner), path <> "/security")
assert has_element?(view, "#alert-#{open.id}", "plug")
refute has_element?(view, "#alert-#{fixed.id}")
view |> element("#security-tab-fixed") |> render_click()
assert_patch(view, path <> "/security/fixed")
assert has_element?(view, "#alert-#{fixed.id}", "mint")
end
test "the header links it, with the open count, for whoever may look", %{
conn: conn,
owner: owner,
repo: repo,
path: path
} do
alert!(repo, %{})
{:ok, view, _} = live(log_in_user(conn, owner), path <> "/issues")
assert has_element?(view, "#repo-security-link")
# A reader of the public repository sees neither.
{:ok, view, _} = live(log_in_user(build_conn(), user_fixture()), path <> "/issues")
refute has_element?(view, "#repo-security-link")
assert {:error, {:redirect, %{to: ^path}}} =
live(log_in_user(build_conn(), user_fixture()), path <> "/security")
end
test "a state it doesn't know goes back to the open list", %{
conn: conn,
owner: owner,
path: path
} do
assert {:error, {:live_redirect, %{to: to}}} =
live(log_in_user(conn, owner), path <> "/security/whatever")
assert to == path <> "/security"
end
end
describe "the switches" do
test "a personal repository's, in its settings, audited", %{
conn: conn,
owner: owner,
repo: repo,
path: path
} do
{:ok, view, _} = live(log_in_user(conn, owner), path <> "/settings")
view |> element("#repo-advisories-toggle") |> render_click()
assert GitGud.Repo.reload!(repo).advisories_enabled
assert_enqueued(worker: Scan, args: %{"repository_id" => repo.id})
assert [%{action: "repo.advisories_enabled"}] =
GitGud.Repo.all(from e in GitGud.Audit.Entry, where: e.repository_id == ^repo.id)
end
test "an org's, in its settings, for its admins", %{conn: conn, owner: owner} do
handle = "sec#{System.unique_integer([:positive])}"
{:ok, org} =
Organizations.create_organization(owner, %{"handle" => handle, "name" => handle})
{:ok, repo} = GitGud.Repositories.create_repository_for_org(org, owner, %{"name" => "svc"})
{:ok, view, _} = live(log_in_user(conn, owner), ~p"/orgs/#{handle}/settings/profile")
view |> element("#org-advisories-toggle") |> render_click()
assert GitGud.Repo.reload!(org).advisories_enabled
assert_enqueued(worker: Scan, args: %{"repository_id" => repo.id, "force" => true})
assert [%{action: "org.advisories_enabled"}] =
GitGud.Repo.all(from e in GitGud.Audit.Entry, where: e.organization_id == ^org.id)
end
end
test "a push to the default branch queues a scan where alerts are on", %{repo: repo} do
{:ok, repo} = Advisories.set_repo(repo, true)
Oban.drain_queue(queue: :advisories)
perform_job(GitGud.Repositories.Workers.CommitBackfill, %{
"repository_id" => repo.id,
"ref" => "refs/heads/#{repo.default_branch}",
"old_sha_hex" => String.duplicate("0", 40),
"new_sha_hex" => String.duplicate("0", 40)
})
assert_enqueued(worker: Scan, args: %{"repository_id" => repo.id, "force" => false})
end
end
neiam
/gitgud
Git Gud
public · Issues · Pulls · Labels · Forks · Compare · Actions success · Badges · Packages
⭐
1
Log in to mark this repository.
5.5 KiB · text
History
b868907