Initial commit on Forgejo
All checks were successful
CI and deploy / Test (push) Successful in 4m52s
CI and deploy / Deploy production (push) Successful in 23s

Fresh repository history for elektrine/tarakan hosted at
https://git.elektrine.com/elektrine/tarakan.
This commit is contained in:
Maxfield Luke 2026-07-29 04:43:40 -04:00
commit af6077b9c3
455 changed files with 78366 additions and 0 deletions

View file

@ -0,0 +1,148 @@
defmodule TarakanWeb.API.ClientAuthControllerTest do
use TarakanWeb.ConnCase, async: true
import Phoenix.LiveViewTest
alias Tarakan.Accounts.ApiCredentials
test "browser approval exchanges a device code for one scoped credential", %{conn: conn} do
start_response =
conn
|> post(~p"/api/client-auth/start", %{client_name: "Tarakan CLI on laptop"})
|> json_response(201)
assert start_response["device_code"] =~ "trkd_"
assert start_response["user_code"] =~ ~r/^[A-Z2-7]{4}-[A-Z2-7]{4}$/
assert start_response["verification_uri_complete"] =~
"/client/authorize/#{start_response["user_code"]}"
pending =
build_conn()
|> post(~p"/api/client-auth/exchange", %{device_code: start_response["device_code"]})
|> json_response(400)
assert pending == %{"error" => "authorization_pending"}
account = account_fixture()
{:ok, view, _html} =
build_conn()
|> log_in_account(account)
|> live(~p"/client/authorize/#{start_response["user_code"]}")
assert has_element?(view, "#client-authorization-code")
assert has_element?(view, "#client-authorization-approve-button")
view
|> element("#client-authorization-approve-button")
|> render_click()
assert has_element?(view, "#client-authorization-approved")
exchange_response =
build_conn()
|> post(~p"/api/client-auth/exchange", %{device_code: start_response["device_code"]})
|> json_response(200)
assert exchange_response["token"] =~ "trkn_"
assert exchange_response["token_type"] == "Bearer"
assert "tasks:read" in exchange_response["scopes"]
assert "tasks:claim" in exchange_response["scopes"]
assert "contributions:write" in exchange_response["scopes"]
assert "reviews:submit" in exchange_response["scopes"]
refute "reviews:verify" in exchange_response["scopes"]
refute "reviews:read" in exchange_response["scopes"]
assert {:ok, ^account, credential} = ApiCredentials.authenticate(exchange_response["token"])
assert credential.name == "Tarakan CLI on laptop"
# Device-minted credentials are short-lived (agent blast-radius control).
expires_in_days = DateTime.diff(credential.expires_at, DateTime.utc_now(), :day)
assert expires_in_days in 6..7
consumed =
build_conn()
|> post(~p"/api/client-auth/exchange", %{device_code: start_response["device_code"]})
|> json_response(400)
assert consumed == %{"error" => "invalid_device_code"}
revoke_conn =
build_conn()
|> put_req_header("authorization", "Bearer #{exchange_response["token"]}")
|> delete(~p"/api/client-auth/session")
assert response(revoke_conn, 204) == ""
assert :error = ApiCredentials.authenticate(exchange_response["token"])
end
test "the browser can deny a login without issuing a credential", %{conn: conn} do
start_response =
conn
|> post(~p"/api/client-auth/start", %{})
|> json_response(201)
{:ok, view, _html} =
build_conn()
|> log_in_account(account_fixture())
|> live(~p"/client/authorize/#{start_response["user_code"]}")
view
|> element("#client-authorization-deny-button")
|> render_click()
assert has_element?(view, "#client-authorization-denied")
denied =
build_conn()
|> post(~p"/api/client-auth/exchange", %{device_code: start_response["device_code"]})
|> json_response(403)
assert denied == %{"error" => "access_denied"}
end
test "authorization page requires a signed-in web account", %{conn: conn} do
start_response =
conn
|> post(~p"/api/client-auth/start", %{})
|> json_response(201)
assert {:error, {:redirect, %{to: path}}} =
live(build_conn(), ~p"/client/authorize/#{start_response["user_code"]}")
assert path == ~p"/accounts/log-in"
end
test "a signed-in session can approve without recent reauth", %{conn: conn} do
start_response =
conn
|> post(~p"/api/client-auth/start", %{})
|> json_response(201)
return_to = ~p"/client/authorize/#{start_response["user_code"]}"
stale_at = DateTime.add(DateTime.utc_now(:second), -9 * 60, :minute)
{:ok, view, _html} =
build_conn()
|> log_in_account(account_fixture(), token_authenticated_at: stale_at)
|> live(return_to)
assert has_element?(view, "#client-authorization-approve-button")
view
|> element("#client-authorization-approve-button")
|> render_click()
assert has_element?(view, "#client-authorization-approved")
end
test "invalid device codes fail without revealing authorization state", %{conn: conn} do
response =
conn
|> post(~p"/api/client-auth/exchange", %{device_code: "not-a-device-code"})
|> json_response(400)
assert response == %{"error" => "invalid_device_code"}
end
end