Implements the subset of the isitagentready.com checklist that maps to
real capabilities of this site:
- RFC 8288 Link headers on every browser response advertising
service-doc (/algo), about, privacy-policy, and sitemap.
- Markdown-for-Agents content negotiation: requests with
Accept: text/markdown for / or /algo return real markdown
(curated summary + verbatim algo.md) with x-markdown-tokens hint.
Other paths still 406 — no synthesizing markdown from LiveView HTML.
- Content-Signal directive in robots.txt declaring
search=yes, ai-train=no, ai-input=no.
- RFC 9727 API catalog at /.well-known/api-catalog with the sole
public endpoint (/api/contacts/map) linking status -> /health and
service-desc -> /openapi.json (a new minimal OpenAPI 3.0 spec).
- Agent Skills Discovery index at /.well-known/agent-skills/index.json
listing two skill documents (fetch-contacts, read-algorithm) with
sha256 digests computed at compile time; documents served at
/.well-known/agent-skills/{name}/SKILL.md.
Skipped (don't match actual site capabilities): Web Bot Auth JWKS,
OAuth/OIDC discovery, MCP server card.
60 lines
2.2 KiB
Elixir
60 lines
2.2 KiB
Elixir
defmodule MicrowavepropWeb.AgentSkillsControllerTest do
|
|
use MicrowavepropWeb.ConnCase, async: true
|
|
|
|
describe "GET /.well-known/agent-skills/index.json" do
|
|
test "returns the agent-skills discovery index", %{conn: conn} do
|
|
conn = get(conn, "/.well-known/agent-skills/index.json")
|
|
|
|
assert conn.status == 200
|
|
assert ["application/json" <> _] = get_resp_header(conn, "content-type")
|
|
|
|
body = Jason.decode!(conn.resp_body)
|
|
assert body["$schema"] =~ "agentskills"
|
|
assert is_list(body["skills"])
|
|
assert body["skills"] != []
|
|
|
|
for skill <- body["skills"] do
|
|
assert is_binary(skill["name"])
|
|
assert is_binary(skill["type"])
|
|
assert is_binary(skill["description"])
|
|
assert is_binary(skill["url"])
|
|
assert String.match?(skill["sha256"], ~r/^[0-9a-f]{64}$/)
|
|
end
|
|
end
|
|
|
|
test "index lists at least fetch-contacts and read-algorithm", %{conn: conn} do
|
|
conn = get(conn, "/.well-known/agent-skills/index.json")
|
|
%{"skills" => skills} = Jason.decode!(conn.resp_body)
|
|
names = Enum.map(skills, & &1["name"])
|
|
|
|
assert "fetch-contacts" in names
|
|
assert "read-algorithm" in names
|
|
end
|
|
end
|
|
|
|
describe "GET /.well-known/agent-skills/:name/SKILL.md" do
|
|
test "serves a skill document as markdown", %{conn: conn} do
|
|
conn = get(conn, "/.well-known/agent-skills/fetch-contacts/SKILL.md")
|
|
|
|
assert conn.status == 200
|
|
assert ["text/markdown; charset=utf-8"] = get_resp_header(conn, "content-type")
|
|
assert conn.resp_body =~ "Fetch contacts dataset"
|
|
end
|
|
|
|
test "sha256 in the index matches the served document bytes", %{conn: conn} do
|
|
%{"skills" => skills} =
|
|
conn |> get("/.well-known/agent-skills/index.json") |> Map.get(:resp_body) |> Jason.decode!()
|
|
|
|
for %{"name" => name, "sha256" => expected} <- skills do
|
|
doc = get(conn, "/.well-known/agent-skills/#{name}/SKILL.md").resp_body
|
|
actual = :sha256 |> :crypto.hash(doc) |> Base.encode16(case: :lower)
|
|
assert actual == expected, "sha256 mismatch for skill #{name}"
|
|
end
|
|
end
|
|
|
|
test "returns 404 for unknown skill names", %{conn: conn} do
|
|
conn = get(conn, "/.well-known/agent-skills/does-not-exist/SKILL.md")
|
|
assert conn.status == 404
|
|
end
|
|
end
|
|
end
|