defmodule VavPipeline.Tablet46MishmarTest do @moduledoc """ Tablet 46 (2026-10-06) — no gate had a watch. Tamid §1.1 writes the pe'ah's limit in the spec; nothing enforced it, on any tier. Every admitted request spends manna; one caller could gather the whole omer. """ use ExUnit.Case, async: false import Plug.Test import Plug.Conn alias VavPipeline.BigdeiKodesh.{Mishmar, Router} @opts Router.init([]) setup do original = Application.get_env(:vav_pipeline, :rate_limits) Application.put_env(:vav_pipeline, :rate_limits, peah: [minute: 3, hour: 5], courtyard: [minute: 2, hour: 100], chatzer: [minute: 10_000, hour: 100_000] ) Mishmar.reset() on_exit(fn -> Application.put_env(:vav_pipeline, :rate_limits, original) Mishmar.reset() end) :ok end describe "Mishmar.knock/3" do test "counts the minute, then the hour, per subject; a refusal is not counted" do t = 1_000_000 * 60 assert {:ok, 2} = Mishmar.knock(:peah, "a", t) assert {:ok, 1} = Mishmar.knock(:peah, "a", t + 1) assert {:ok, 0} = Mishmar.knock(:peah, "a", t + 2) assert {:error, :minute, 57} = Mishmar.knock(:peah, "a", t + 3) assert {:error, :minute, 57} = Mishmar.knock(:peah, "a", t + 3) # Another subject is another count. assert {:ok, 2} = Mishmar.knock(:peah, "b", t + 3) # The next minute opens — but the hour (5) is nearly spent: 3 so far. assert {:ok, 2} = Mishmar.knock(:peah, "a", t + 60) assert {:ok, 1} = Mishmar.knock(:peah, "a", t + 61) assert {:error, :hour, retry} = Mishmar.knock(:peah, "a", t + 62) assert retry == 3600 - rem(t + 62, 3600) # The next hour opens. assert {:ok, 2} = Mishmar.knock(:peah, "a", t + 3600) end test "tiers are counted apart" do t = 2_000_000 * 60 assert {:ok, 1} = Mishmar.knock(:courtyard, "k", t) assert {:ok, 0} = Mishmar.knock(:courtyard, "k", t) assert {:error, :minute, _} = Mishmar.knock(:courtyard, "k", t) assert {:ok, 2} = Mishmar.knock(:peah, "k", t) end test "the sweep drops closed windows and nothing else" do t = 3_000_000 * 60 assert {:ok, _} = Mishmar.knock(:peah, "old", t) assert {:ok, _} = Mishmar.knock(:peah, "new", t + 7200) :ok = Mishmar.sweep(Mishmar, t + 7200) # "old" has been forgotten entirely; "new" is still counted. assert :ets.info(Mishmar, :size) == 2 assert {:ok, 1} = Mishmar.knock(:peah, "new", t + 7200) end test "the table holds hashes, never the subject" do :ok = Mishmar.reset() {:ok, _} = Mishmar.knock(:peah, "203.0.113.7") for {{id, _, _}, _} <- :ets.tab2list(Mishmar) do assert is_binary(id) and byte_size(id) == 32 refute id =~ "203.0.113" end end end describe "Mishmar.peer/1 — who is knocking, behind the ingress" do setup do original = Application.get_env(:vav_pipeline, :trusted_proxies) Application.put_env(:vav_pipeline, :trusted_proxies, ["192.168.0.0/16", "not-a-cidr", "fd00::/8"]) on_exit(fn -> Application.put_env(:vav_pipeline, :trusted_proxies, original) end) :ok end test "from the ingress, X-Real-IP is the caller" do conn = %{conn(:post, "/peah/ask") | remote_ip: {192, 168, 150, 211}} |> put_req_header("x-real-ip", "203.0.113.7") assert Mishmar.peer(conn) == "203.0.113.7" v6 = %{conn(:post, "/peah/ask") | remote_ip: {0xFD00, 0, 0, 0, 0, 0, 0, 1}} |> put_req_header("x-real-ip", "2001:db8::7") assert Mishmar.peer(v6) == "2001:db8::7" end test "from anyone else, X-Real-IP is only a claim — the peer is the caller" do conn = %{conn(:post, "/peah/ask") | remote_ip: {203, 0, 113, 9}} |> put_req_header("x-real-ip", "198.51.100.1") assert Mishmar.peer(conn) == "203.0.113.9" # Just outside the /16. edge = %{conn(:post, "/peah/ask") | remote_ip: {192, 169, 0, 1}} |> put_req_header("x-real-ip", "198.51.100.1") assert Mishmar.peer(edge) == "192.169.0.1" end test "from the ingress without the header, or with a header that is not an address — the peer" do bare = %{conn(:post, "/peah/ask") | remote_ip: {192, 168, 1, 1}} assert Mishmar.peer(bare) == "192.168.1.1" junk = bare |> put_req_header("x-real-ip", "'; drop table") assert Mishmar.peer(junk) == "192.168.1.1" end test "no trusted proxies configured — nobody's header is believed" do Application.put_env(:vav_pipeline, :trusted_proxies, []) conn = %{conn(:post, "/peah/ask") | remote_ip: {192, 168, 150, 211}} |> put_req_header("x-real-ip", "203.0.113.7") assert Mishmar.peer(conn) == "192.168.150.211" end test "a caller cannot escape the watch by naming a new address with every knock" do knock = fn claimed -> %{conn(:post, "/peah/ask", Jason.encode!(%{question: "x"})) | remote_ip: {203, 0, 113, 50}} |> put_req_header("content-type", "application/json") |> put_req_header("x-real-ip", claimed) |> Router.call(@opts) end statuses = for i <- 1..4, do: knock.("198.51.100.#{i}").status assert List.last(statuses) == 429 end test "two callers through the same ingress are counted apart" do via = fn real -> %{conn(:post, "/peah/ask", Jason.encode!(%{question: "x"})) | remote_ip: {192, 168, 150, 211}} |> put_req_header("content-type", "application/json") |> put_req_header("x-real-ip", real) |> Router.call(@opts) end for _ <- 1..3, do: via.("203.0.113.60") assert via.("203.0.113.60").status == 429 refute via.("203.0.113.61").status == 429 end end describe "at the router" do test "the pe'ah: the fourth knock from one address in a minute is 429 with Retry-After and the manna explanation" do statuses = for _ <- 1..4, do: ask({203, 0, 113, 9}).status assert Enum.take(statuses, 3) |> Enum.all?(&(&1 != 429)) conn = ask({203, 0, 113, 9}) assert conn.status == 429 [retry] = get_resp_header(conn, "retry-after") assert String.to_integer(retry) in 1..60 body = Jason.decode!(conn.resp_body) assert body["error"]["code"] == "RATE_LIMITED" assert body["error"]["guidance"]["manna"] =~ "Shemot 16:18" # Another address is not held back by this one. refute ask({203, 0, 113, 10}).status == 429 end test "the courtyard: per key, and only past the gate" do # A wrong key knocks all it likes and is never counted — 401, not 429. for _ <- 1..5, do: assert(bedikah("Bearer wrong").status == 401) assert bedikah("Bearer test-token").status != 429 assert bedikah("Bearer test-token").status != 429 conn = bedikah("Bearer test-token") assert conn.status == 429 assert Jason.decode!(conn.resp_body)["error"]["guidance"]["issue"] =~ "courtyard allows 2 a minute" # The chatzer key is its own hand, even at the same door. refute bedikah("Bearer chatzer-test-token").status == 429 end end defp ask(ip) do %{conn(:post, "/peah/ask", Jason.encode!(%{question: "x"})) | remote_ip: ip} |> put_req_header("content-type", "application/json") |> Router.call(@opts) end defp bedikah(auth) do conn(:post, "/courtyard/bedikah", Jason.encode!(%{output: "", model: "gpt"})) |> put_req_header("content-type", "application/json") |> put_req_header("authorization", auth) |> Router.call(@opts) end end