defmodule GitGud.PackageSigningKeysTest do
@moduledoc """
Signing keys belong to the namespace that publishes, not to the
repository. The whole point is what a *consumer* has to do: one
keyring entry per organization, not one per repository.
"""
use GitGudWeb.ConnCase, async: false
alias GitGud.Packages
alias GitGud.Packages.Apt.Native
alias GitGud.Repositories.Storage
import GitGud.AccountsFixtures
import GitGud.ForgeFixtures
describe "scoping" do
test "two repositories in one organization share a key" do
{_user, org, one, two} = org_with_two_repos()
assert {:ok, %{public_pem: first}} = Packages.signing_key(one, "deb")
assert {:ok, %{public_pem: second}} = Packages.signing_key(two, "deb")
assert first == second
assert Packages.get_signing_key(org, "deb")
end
test "and the apt repositories they serve verify against that one key" do
{_user, _org, one, two} = org_with_two_repos()
key = Packages.signing_key(one, "deb") |> elem(1) |> Map.fetch!(:public_pem)
for repo <- [one, two] do
root = "/pkg/deb/#{Storage.repo_handle(repo)}/#{repo.name}"
release = get(build_conn(), root <> "/dists/stable/Release").resp_body
signature = get(build_conn(), root <> "/dists/stable/Release.gpg").resp_body
assert {:ok, true} = Native.verify_detached(key, release, signature),
"#{repo.name}'s Release did not verify against the organization key"
end
end
test "different organizations get different keys" do
{_u1, _org1, one, _} = org_with_two_repos()
{_u2, _org2, two, _} = org_with_two_repos()
assert {:ok, %{public_pem: first}} = Packages.signing_key(one, "deb")
assert {:ok, %{public_pem: second}} = Packages.signing_key(two, "deb")
refute first == second
end
test "a personal repository's key belongs to its user, and is shared too" do
user = user_fixture()
{_u, one} = repository_fixture(%{owner: user})
{_u, two} = repository_fixture(%{owner: user})
assert {:ok, %{public_pem: first}} = Packages.signing_key(one, "hex")
assert {:ok, %{public_pem: second}} = Packages.signing_key(two, "hex")
assert first == second
assert Packages.get_signing_key(user, "hex")
end
test "formats don't share a key — apt wants OpenPGP, Hex wants RSA" do
{_user, _org, repo, _} = org_with_two_repos()
{:ok, %{public_pem: deb}} = Packages.signing_key(repo, "deb")
{:ok, %{public_pem: hex}} = Packages.signing_key(repo, "hex")
assert deb =~ "-----BEGIN PGP PUBLIC KEY BLOCK-----"
assert hex =~ "-----BEGIN PUBLIC KEY-----"
end
test "a key is generated once and then reused verbatim" do
{_user, _org, repo, _} = org_with_two_repos()
assert {:ok, %{private_pem: first}} = Packages.signing_key(repo, "deb")
assert {:ok, %{private_pem: second}} = Packages.signing_key(repo, "deb")
assert first == second
end
test "get_signing_key/2 never generates" do
{_user, org, _one, _two} = org_with_two_repos()
assert Packages.get_signing_key(org, "deb") == nil
end
end
describe "GET /pkg/_keys/:format/:owner" do
test "serves the namespace key once it exists", %{conn: conn} do
{_user, org, repo, _two} = org_with_two_repos()
{:ok, %{public_pem: key}} = Packages.signing_key(repo, "deb")
conn = get(conn, "/pkg/_keys/deb/#{org.handle}")
assert conn.status == 200
assert conn.resp_body == key
assert get_resp_header(conn, "content-type") == ["application/pgp-keys"]
end
test "and it is the same key every repository in the org signs with", %{conn: conn} do
{_user, org, one, two} = org_with_two_repos()
{:ok, _} = Packages.signing_key(one, "deb")
shared = get(conn, "/pkg/_keys/deb/#{org.handle}").resp_body
for repo <- [one, two] do
root = "/pkg/deb/#{Storage.repo_handle(repo)}/#{repo.name}"
assert get(build_conn(), root <> "/key.asc").resp_body == shared
end
end
test "mints the key on first ask — pinning it is the first setup step", %{conn: conn} do
{_user, org, _one, _two} = org_with_two_repos()
refute Packages.get_signing_key(org, "deb")
conn = get(conn, "/pkg/_keys/deb/#{org.handle}")
assert conn.status == 200
assert conn.resp_body =~ "-----BEGIN PGP PUBLIC KEY BLOCK-----"
assert Packages.get_signing_key(org, "deb")
end
test "and hands back the same key every time after that", %{conn: conn} do
{_user, org, _one, _two} = org_with_two_repos()
first = get(conn, "/pkg/_keys/deb/#{org.handle}").resp_body
second = get(build_conn(), "/pkg/_keys/deb/#{org.handle}").resp_body
assert first == second
end
test "a handle that doesn't resolve 404s, and mints nothing", %{conn: conn} do
assert get(conn, "/pkg/_keys/deb/nobody-at-all").status == 404
end
test "404s for a format the forge doesn't serve", %{conn: conn} do
{_user, org, repo, _two} = org_with_two_repos()
{:ok, _} = Packages.signing_key(repo, "deb")
assert get(conn, "/pkg/_keys/nonsense/#{org.handle}").status == 404
end
test "needs no credentials — apt and mix pin the key before they have any", %{conn: conn} do
{_user, org, repo, _two} = org_with_two_repos()
{:ok, _} = Packages.signing_key(repo, "deb")
assert get(conn, "/pkg/_keys/deb/#{org.handle}").status == 200
end
test "serves a Hex public key as text", %{conn: conn} do
{_user, org, repo, _two} = org_with_two_repos()
{:ok, _} = Packages.signing_key(repo, "hex")
conn = get(conn, "/pkg/_keys/hex/#{org.handle}")
assert conn.status == 200
assert conn.resp_body =~ "-----BEGIN PUBLIC KEY-----"
end
end
defp org_with_two_repos do
user = user_fixture()
{:ok, org} =
GitGud.Organizations.create_organization(user, %{
"handle" => "org#{System.unique_integer([:positive])}",
"name" => "Test Org"
})
{:ok, one} =
GitGud.Repositories.create_repository_for_org(org, user, %{
"name" => unique_repo_name(),
"visibility" => "public"
})
{:ok, two} =
GitGud.Repositories.create_repository_for_org(org, user, %{
"name" => unique_repo_name(),
"visibility" => "public"
})
# `Storage.repo_handle/1` refuses to guess, so hand back repos that
# can actually name their own namespace.
preload = &GitGud.Repo.preload(&1, [:owner, :organization])
{user, org, preload.(one), preload.(two)}
end
end
neiam
/gitgud
Git Gud
public · Issues · Pulls · Labels · Forks · Compare · Actions success · Badges · Packages
⭐
1
Log in to mark this repository.
6.5 KiB · text
History
b868907