defmodule GitGudWeb.Plugs.HookAuthTest do
@moduledoc """
The hook and SSH-wrapper endpoints answer only this node's own hooks:
the listener is public, so a caller has to show the secret the node
handed its git processes.
"""
use GitGudWeb.ConnCase, async: false
import GitGud.AccountsFixtures
import GitGud.ForgeFixtures
alias GitGudWeb.Plugs.HookAuth
@zero String.duplicate("0", 40)
defp hook_post(conn, path, body, token) do
conn =
if token, do: put_req_header(conn, HookAuth.header(), token), else: conn
conn
|> put_req_header("content-type", "text/plain")
|> post(path, body)
end
setup do
{_owner, repo} = repository_fixture()
%{repo: repo}
end
for path <- ["/_hooks/post-receive", "/_hooks/pre-receive"] do
test "#{path} refuses a caller without the secret", %{conn: conn, repo: repo} do
conn = put_req_header(conn, "x-repo-path", repo.disk_path)
line = "#{@zero} #{String.duplicate("a", 40)} refs/heads/main\n"
assert hook_post(conn, unquote(path), line, nil).status == 403
assert hook_post(conn, unquote(path), line, "guess").status == 403
end
end
test "a forged post-receive starts nothing", %{conn: conn, repo: repo} do
victim = user_fixture()
resp =
conn
|> put_req_header("x-repo-path", repo.disk_path)
|> put_req_header("x-pusher-id", Integer.to_string(victim.id))
|> hook_post(
"/_hooks/post-receive",
"#{@zero} #{String.duplicate("b", 40)} refs/heads/x\n",
nil
)
assert resp.status == 403
assert resp.halted
end
test "/_ssh/resolve refuses a caller without the secret", %{conn: conn, repo: repo} do
body = Jason.encode!(%{"key_id" => "1", "repo" => repo.name, "cmd" => "git-receive-pack"})
resp =
conn
|> put_req_header("content-type", "application/json")
|> post("/_ssh/resolve", body)
assert resp.status == 403
refute resp.resp_body =~ "OK"
end
test "the node's own hook gets through", %{conn: conn, repo: repo} do
resp =
conn
|> put_req_header("x-repo-path", repo.disk_path)
|> hook_post("/_hooks/pre-receive", "", HookAuth.secret())
assert resp.status == 200
assert resp.resp_body =~ "OK"
body = Jason.encode!(%{"key_id" => "999999999", "repo" => "a/b", "cmd" => "git-upload-pack"})
resp =
build_conn()
|> put_req_header(HookAuth.header(), HookAuth.secret())
|> put_req_header("content-type", "application/json")
|> post("/_ssh/resolve", body)
assert resp.status == 200
assert resp.resp_body =~ "DENY"
end
test "the secret is in the environment git inherits" do
assert System.get_env("GITGUD_HOOK_SECRET") == HookAuth.secret()
assert byte_size(HookAuth.secret()) >= 32
end
end
neiam
/gitgud
Git Gud
public · Issues · Pulls · Labels · Forks · Compare · Actions success · Badges · Packages
⭐
1
Log in to mark this repository.
2.7 KiB · text
History
b868907