migration: establish exact preserved app baseline
This commit is contained in:
@@ -0,0 +1,107 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
OUTPUT = ROOT / "config" / "api.config.json"
|
||||
if str(ROOT) not in sys.path:
|
||||
sys.path.insert(0, str(ROOT))
|
||||
|
||||
|
||||
def _owner(path: str) -> str:
|
||||
ordered = (
|
||||
("/api/health", "health"),
|
||||
("/api/auth", "auth"),
|
||||
("/api/admin", "admin"),
|
||||
("/api/account", "account"),
|
||||
("/api/sentiment", "sentiment"),
|
||||
("/api/dashboard", "market"),
|
||||
("/api/realtime-aggregate", "market"),
|
||||
("/api/rotation", "rotation"),
|
||||
("/api/auction", "auction"),
|
||||
("/api/themes", "themes"),
|
||||
("/api/popularity", "popularity"),
|
||||
("/api/dragon-tiger", "dragon_tiger"),
|
||||
("/api/search", "search"),
|
||||
("/api/chart", "charts"),
|
||||
("/api/stock", "market"),
|
||||
("/api/screener", "screener"),
|
||||
("/api/mentors", "mentor"),
|
||||
("/api/heaven", "heaven"),
|
||||
("/api/alerts", "alerts"),
|
||||
("/api/trades", "review"),
|
||||
("/api/assistant", "review"),
|
||||
("/api/watchlist", "review"),
|
||||
("/api/notes", "review"),
|
||||
("/api/reasons", "admin"),
|
||||
("/api/seat-aliases", "admin"),
|
||||
("/api/backfill", "admin"),
|
||||
)
|
||||
for prefix, owner in ordered:
|
||||
if path.startswith(prefix):
|
||||
return owner
|
||||
raise ValueError(f"API owner is not registered: {path}")
|
||||
|
||||
|
||||
def _role(method: str, path: str) -> str:
|
||||
if path == "/api/health" or path in {"/api/auth/register", "/api/auth/login"}:
|
||||
return "public"
|
||||
from api_access import required_role
|
||||
|
||||
sample = re.sub(r"\\d\{6\}", "000001", path)
|
||||
sample = re.sub(r"\\d\+", "1", sample)
|
||||
sample = sample.replace("(.+)", "sample").replace("(", "").replace(")", "")
|
||||
return required_role(method, sample)
|
||||
|
||||
|
||||
def build() -> dict:
|
||||
text = (ROOT / "server.py").read_text(encoding="utf-8")
|
||||
method_matches = list(re.finditer(r"^ def do_(GET|POST|DELETE)\(", text, re.MULTILINE))
|
||||
routes = []
|
||||
for index, match in enumerate(method_matches):
|
||||
method = match.group(1)
|
||||
end = method_matches[index + 1].start() if index + 1 < len(method_matches) else len(text)
|
||||
block = text[match.start():end]
|
||||
exact_paths = set(re.findall(r'parsed\.path\s*==\s*"(/api/[^"]+)"', block))
|
||||
patterns = set(
|
||||
re.findall(
|
||||
r're\.(?:fullmatch|match)\(\s*r?["\']([^"\']*?/api/[^"\']+)["\']\s*,\s*parsed\.path',
|
||||
block,
|
||||
)
|
||||
)
|
||||
for path in sorted(exact_paths):
|
||||
routes.append(
|
||||
{"method": method, "path": path, "match": "exact", "feature": _owner(path), "access": _role(method, path)}
|
||||
)
|
||||
for path in sorted(patterns):
|
||||
normalized = path.replace("^", "").replace("$", "")
|
||||
routes.append(
|
||||
{"method": method, "path": normalized, "match": "regex", "feature": _owner(normalized), "access": _role(method, normalized)}
|
||||
)
|
||||
routes.sort(key=lambda item: (item["path"], item["method"], item["match"]))
|
||||
return {"schema_version": 1, "generated_from": "server.py", "routes": routes}
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description="Build the transitional API ownership registry")
|
||||
parser.add_argument("--check", action="store_true")
|
||||
args = parser.parse_args()
|
||||
rendered = json.dumps(build(), ensure_ascii=False, indent=2) + "\n"
|
||||
if args.check:
|
||||
if not OUTPUT.exists() or OUTPUT.read_text(encoding="utf-8") != rendered:
|
||||
raise SystemExit("API registry is stale; run tools/build_api_registry.py")
|
||||
print("API registry is current.")
|
||||
return 0
|
||||
OUTPUT.parent.mkdir(parents=True, exist_ok=True)
|
||||
OUTPUT.write_text(rendered, encoding="utf-8")
|
||||
print(OUTPUT.relative_to(ROOT).as_posix())
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user