defmodule GitGudWeb.PublicPackageFormatsTest do
@moduledoc """
Publishing a format from a repository that is not itself public.
The case this exists for: an Android client whose source is private.
The APK is meant to be on a phone, and an F-Droid client is anonymous,
so without an opt-in the repository is absent from the `_all` index
the phone subscribes to and 401s on its own URL.
What is asserted here is mostly what the opt-in does *not* do —
it widens anonymous reads of the named format and nothing else.
"""
use GitGudWeb.ConnCase, async: false
alias GitGud.Packages
alias GitGud.Packages.Auth
alias GitGud.Repositories
alias GitGud.Repositories.Storage
import GitGud.ForgeFixtures
@firmware <<0xE9, 0x06, 0x02, 0x1F>> <> :crypto.strong_rand_bytes(256)
setup do
{user, repo} = repository_fixture(%{visibility: "private"})
{:ok, _t, token} = Packages.create_registry_token(repo, "ci", ["pull", "push"])
handle = Storage.owner_handle(user)
# Publish with the token, which works regardless of visibility --
# that is the CI path, and it is not what any of this changes.
build_conn()
|> put_req_header("authorization", token)
|> put_req_header("content-type", "application/octet-stream")
|> put("/pkg/raw/#{handle}/#{repo.name}/1.0.0/firmware.bin", @firmware)
{:ok,
user: user,
repo: repo,
token: token,
handle: handle,
root: "/pkg/raw/#{handle}/#{repo.name}"}
end
defp publish_formats(repo, formats) do
{:ok, repo} = Repositories.update_repository(repo, %{"public_package_formats" => formats})
repo
end
describe "without the opt-in" do
test "a private repository's registry refuses an anonymous read", %{conn: conn, root: root} do
assert conn |> get(root <> "/manifest.json") |> Map.fetch!(:status) == 401
end
test "and it is absent from what a namespace-wide index would serve", %{user: user} do
assert Packages.namespace_catalog(user, :anonymous) == %{}
end
end
describe "with the format opted in" do
setup %{repo: repo}, do: {:ok, repo: publish_formats(repo, ["raw"])}
test "an anonymous client reads it", %{conn: conn, root: root} do
conn = get(conn, root <> "/manifest.json")
assert conn.status == 200
assert Jason.decode!(conn.resp_body)["latest"] == "1.0.0"
end
test "the bytes themselves come back", %{conn: conn, root: root} do
conn = get(conn, root <> "/1.0.0/firmware.bin")
assert conn.status == 200
assert conn.resp_body == @firmware
end
test "and it appears in what a namespace-wide index would serve", %{user: user, repo: repo} do
catalog = Packages.namespace_catalog(user, :anonymous)
assert [%{repository: %{id: id}}] = catalog["raw"].packages
assert id == repo.id
end
test "the repository itself is still private", %{repo: repo} do
assert Repositories.get_repository!(repo.id).visibility == "private"
end
end
describe "what the opt-in does not open" do
setup %{repo: repo}, do: {:ok, repo: publish_formats(repo, ["fdroid"])}
test "a format that was not ticked stays shut", %{conn: conn, root: root} do
assert conn |> get(root <> "/manifest.json") |> Map.fetch!(:status) == 401
end
test "nor does it let an anonymous caller publish", %{conn: conn, handle: handle, repo: repo} do
conn =
conn
|> put_req_header("content-type", "application/octet-stream")
|> put("/pkg/fdroid/#{handle}/#{repo.name}/9.9.9/app.apk", @firmware)
assert conn.status in [401, 403]
end
test "writes are refused for the opted-in format too", %{repo: repo} do
assert Auth.authorize(:anonymous, repo, :write, "fdroid") == false
end
test "an unticked format is still refused at the authorize level", %{repo: repo} do
assert Auth.authorize(:anonymous, repo, :read, "raw") == false
assert Auth.authorize(:anonymous, repo, :read, "fdroid") == true
end
end
describe "the catalog the dashboard renders" do
test "lists the format only under the one opted into", %{user: user, repo: repo} do
repo = publish_formats(repo, ["raw"])
assert Auth.public_format?(repo, "raw")
catalog = Packages.namespace_catalog(user, :anonymous)
assert Map.has_key?(catalog, "raw")
# And with nothing ticked, the anonymous catalog is empty again.
publish_formats(repo, [])
assert Packages.namespace_catalog(user, :anonymous) == %{}
end
end
describe "the setting itself" do
test "rejects a format the forge does not serve", %{repo: repo} do
assert {:error, changeset} =
Repositories.update_repository(repo, %{
"public_package_formats" => ["raw", "npm"]
})
errors = Ecto.Changeset.traverse_errors(changeset, fn {msg, _opts} -> msg end)
assert "has an invalid entry" in errors.public_package_formats
end
test "clearing every box stores an empty list, not a blank entry", %{repo: repo} do
repo = publish_formats(repo, ["raw", ""])
assert repo.public_package_formats == ["raw"]
repo = publish_formats(repo, [""])
assert repo.public_package_formats == []
end
end
end
neiam
/gitgud
Git Gud
public · Issues · Pulls · Labels · Forks · Compare · Actions success · Badges · Packages
⭐
1
Log in to mark this repository.
5.1 KiB · text
History
b868907