API.md ships in the image; GET /api/docs/approved serves it behind api:docs

Moved to app/API.md so the build context carries it. The console renders
it at /leaders/api. tests/smoke_admin.py 162 -> 164.
This commit is contained in:
2026-09-04 20:26:45 -04:00
parent 38bedaea88
commit d1dfa6df90
4 changed files with 22 additions and 3 deletions
View File
+15 -1
View File
@@ -45,7 +45,7 @@ import os
import re
from fastapi import APIRouter, Body, Header, HTTPException, Query, Request
from fastapi.responses import HTMLResponse
from fastapi.responses import HTMLResponse, PlainTextResponse
import auth
import calendar_write
@@ -511,6 +511,20 @@ def whoami(request: Request, x_admin_token: str = Header(None)):
_CAP_RE = re.compile(r"""_(?:auth|people_actor)\([^)]*?["']([a-z_]+:[a-z_]+)["']""")
@docs_router.get("/docs/approved", response_class=PlainTextResponse)
def api_docs_approved(request: Request):
"""API.md: the approved reference, generated from this registry plus a
full HTTP drive of every route (tests/http_drive.py). Markdown; the
console renders it at /leaders/api. Same gate as /api/docs."""
_auth(request, None, "api:docs")
import pathlib
p = pathlib.Path(__file__).with_name("API.md")
if not p.exists():
raise HTTPException(404, "API.md is not in this build")
return p.read_text()
def route_capability(endpoint):
try:
src = inspect.getsource(endpoint)
+2 -2
View File
@@ -1,9 +1,9 @@
"""Drive every admin API route over real HTTP. NOT a unit test: it needs a running
throwaway site on a COPY of the database (container name sw-test on arrstack_arr_net,
reachable at the URL in /tmp/apitest/base) and sessions for four accounts in
/tmp/apitest/setup.json - see projects/scout-website/state.md for the recipe.
/tmp/apitest/setup.json - see projects/scout-website/state.md for the recipe. Output goes to app/API.md so it ships in the image and the console can render it.
Calendar checks write 2036 probes to the REAL Radicale store and delete them.
Writes results to /tmp/apitest/results.json; API.md is generated from that plus the
Writes results to /tmp/apitest/results.json; app/API.md is generated from that plus the
router registry. 123 checks on 2026-09-04, all passing."""
import json, urllib.request, urllib.error, urllib.parse, hashlib, struct, zlib, base64, datetime, sys
+5
View File
@@ -420,6 +420,11 @@ check("fbposts caps: read for leaders, ingest admin-only and scopable", "fbposts
con = S.connect(); con.execute("DELETE FROM fb_posts"); con.commit(); con.close()
import os as _os; _os.remove(S.image_path(r))
print("\napproved doc")
import pathlib as _pl
check("API.md ships beside the app", (_pl.Path(A.__file__).with_name("API.md")).exists() and "## How to call it" in _pl.Path(A.__file__).with_name("API.md").read_text())
check("/api/docs/approved is gated like /api/docs", any(r.path == "/api/docs/approved" for r in A.docs_router.routes))
print("\napi docs registry")
import admin_api as A
reg = A.describe_routes()