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:
+15
-1
@@ -45,7 +45,7 @@ import os
|
|||||||
import re
|
import re
|
||||||
|
|
||||||
from fastapi import APIRouter, Body, Header, HTTPException, Query, Request
|
from fastapi import APIRouter, Body, Header, HTTPException, Query, Request
|
||||||
from fastapi.responses import HTMLResponse
|
from fastapi.responses import HTMLResponse, PlainTextResponse
|
||||||
|
|
||||||
import auth
|
import auth
|
||||||
import calendar_write
|
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_]+)["']""")
|
_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):
|
def route_capability(endpoint):
|
||||||
try:
|
try:
|
||||||
src = inspect.getsource(endpoint)
|
src = inspect.getsource(endpoint)
|
||||||
|
|||||||
+2
-2
@@ -1,9 +1,9 @@
|
|||||||
"""Drive every admin API route over real HTTP. NOT a unit test: it needs a running
|
"""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,
|
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
|
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.
|
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."""
|
router registry. 123 checks on 2026-09-04, all passing."""
|
||||||
|
|
||||||
import json, urllib.request, urllib.error, urllib.parse, hashlib, struct, zlib, base64, datetime, sys
|
import json, urllib.request, urllib.error, urllib.parse, hashlib, struct, zlib, base64, datetime, sys
|
||||||
|
|||||||
@@ -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()
|
con = S.connect(); con.execute("DELETE FROM fb_posts"); con.commit(); con.close()
|
||||||
import os as _os; _os.remove(S.image_path(r))
|
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")
|
print("\napi docs registry")
|
||||||
import admin_api as A
|
import admin_api as A
|
||||||
reg = A.describe_routes()
|
reg = A.describe_routes()
|
||||||
|
|||||||
Reference in New Issue
Block a user