defmodule VavPipeline.Tablet45GateTest do @moduledoc """ Tablet 45 (2026-10-06) — the courtyard gate opened for any hand. `/courtyard/*` and `/chatzer/*` checked that the Authorization header had the SHAPE `Bearer `, and nothing else. Every test of it sent `Bearer test-token` and passed; none sent `Bearer wrong`. These tests send the wrong key, no key, a key for the outer ring at the inner gate, and a key when there is no keys file at all. """ use ExUnit.Case, async: false import Plug.Test import Plug.Conn alias VavPipeline.BigdeiKodesh.{Gate, Router} @opts Router.init([]) describe "Gate.parse/1" do test "reads tier and key, skips comments, blanks and unknown tiers" do assert Gate.parse(""" # keys courtyard abc chatzer\tdef # trailing words are ignored kodesh ghi courtyard """) == [courtyard: "abc", chatzer: "def"] end end describe "Gate.admit/2" do test "the right key for the ring" do assert {:ok, :courtyard} = Gate.admit(with_key("test-token"), :courtyard) assert {:ok, :chatzer} = Gate.admit(with_key("chatzer-test-token"), :chatzer) end test "the inner ring's key opens the outer gate; not the reverse" do assert {:ok, :chatzer} = Gate.admit(with_key("chatzer-test-token"), :courtyard) assert {:error, :tier_too_low} = Gate.admit(with_key("test-token"), :chatzer) end test "a wrong key, a near key, an empty key, no header" do assert {:error, :unknown_key} = Gate.admit(with_key("wrong"), :courtyard) assert {:error, :unknown_key} = Gate.admit(with_key("test-token2"), :courtyard) assert {:error, :unknown_key} = Gate.admit(with_key("test-toke"), :courtyard) assert {:error, :no_header} = Gate.admit(with_key(""), :courtyard) assert {:error, :no_header} = Gate.admit(conn(:post, "/courtyard/offering"), :courtyard) basic = conn(:post, "/courtyard/offering") |> put_req_header("authorization", "Basic dGVzdA==") assert {:error, :no_header} = Gate.admit(basic, :courtyard) end test "no keys file, an empty one, a missing one — nobody passes" do original = Application.get_env(:vav_pipeline, :api_keys_file) on_exit(fn -> Application.put_env(:vav_pipeline, :api_keys_file, original) end) Application.put_env(:vav_pipeline, :api_keys_file, nil) assert {:error, :unknown_key} = Gate.admit(with_key("test-token"), :courtyard) empty = Path.join(System.tmp_dir!(), "tablet45_empty_#{System.unique_integer([:positive])}") File.write!(empty, "# nothing here\n\n") Application.put_env(:vav_pipeline, :api_keys_file, empty) assert {:error, :unknown_key} = Gate.admit(with_key("test-token"), :courtyard) File.rm!(empty) Application.put_env(:vav_pipeline, :api_keys_file, "/nonexistent/api_keys") assert {:error, :unknown_key} = Gate.admit(with_key("test-token"), :courtyard) end end describe "at the router" do test "a wrong key is 401 at every gated door, and says nothing about the keys" do for {path, body} <- [ {"/courtyard/offering", %{offering_type: "shelamim", content: "x"}}, {"/courtyard/bedikah", %{output: "x", model: "gpt"}}, {"/chatzer/sanhedrin", %{case: "x"}} ] do conn = post(path, body, "Bearer wrong") assert conn.status == 401, path decoded = Jason.decode!(conn.resp_body) assert decoded["error"]["code"] == "UNAUTHORIZED" refute conn.resp_body =~ "test-token" end end test "a courtyard key at the chatzer is 403, not 401" do conn = post("/chatzer/sanhedrin", %{case: "x"}, "Bearer test-token") assert conn.status == 403 assert Jason.decode!(conn.resp_body)["error"]["code"] == "FORBIDDEN" end test "a chatzer key is good in the courtyard" do conn = post("/courtyard/offering", %{offering_type: "shelamim"}, "Bearer chatzer-test-token") # Past the gate: the next check (no content) answers, not the gate. assert conn.status == 422 end end defp with_key(key) do conn(:post, "/courtyard/offering") |> put_req_header("authorization", "Bearer " <> key) end defp post(path, body, auth) do conn(:post, path, Jason.encode!(body)) |> put_req_header("content-type", "application/json") |> put_req_header("authorization", auth) |> Router.call(@opts) end end