Protect Tabularium with persistent authenticator-code login
Verify and deploy Tabularium / verify-and-deploy (push) Successful in 5m28s
Verify and deploy Tabularium / verify-and-deploy (push) Successful in 5m28s
This commit is contained in:
+28
-36
@@ -1,48 +1,40 @@
|
||||
"""Exercise actual production routes and assets without third-party dependencies."""
|
||||
from html import unescape
|
||||
"""Check the public authentication boundary; auth-cli verify checks private content."""
|
||||
import json
|
||||
from pathlib import Path
|
||||
import re
|
||||
import sys
|
||||
import urllib.error
|
||||
import urllib.parse
|
||||
import urllib.request
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
|
||||
class NoRedirect(urllib.request.HTTPRedirectHandler):
|
||||
def redirect_request(self, req, fp, code, msg, headers, newurl):
|
||||
return None
|
||||
|
||||
|
||||
def verify(base: str) -> None:
|
||||
def get(path: str) -> tuple[bytes, str]:
|
||||
with urllib.request.urlopen(base.rstrip("/") + path, timeout=15) as response:
|
||||
if response.status != 200:
|
||||
raise RuntimeError(f"Unexpected status for {path}: {response.status}")
|
||||
return response.read(), response.headers.get("Content-Type", "")
|
||||
opener = urllib.request.build_opener(NoRedirect())
|
||||
base = base.rstrip("/")
|
||||
|
||||
health, _ = get("/api/health")
|
||||
assert json.loads(health) == {"status": "ok"}
|
||||
home, _ = get("/")
|
||||
assert b"TABULARIUM" in home
|
||||
for file in sorted((ROOT / "content/docs").glob("*.md")):
|
||||
page, _ = get(f"/docs/{file.stem}")
|
||||
title = re.search(r"^# (.+)$", file.read_text(), re.M)
|
||||
assert title is not None
|
||||
text = unescape(re.sub(r"<[^>]+>", "", page.decode()))
|
||||
assert title.group(1) in text, file.name
|
||||
assets = set(re.findall(r'(?:src|href)="(/_next/static/[^" ]+)"', home.decode()))
|
||||
assert assets, "No generated JavaScript/CSS assets found"
|
||||
for asset in assets:
|
||||
get(unescape(asset))
|
||||
for file in sorted((ROOT / "apps/docs/public/figures").glob("*.svg")):
|
||||
data, kind = get(f"/figures/{file.name}")
|
||||
assert "image/svg+xml" in kind
|
||||
assert ET.fromstring(data).tag.endswith("svg")
|
||||
try:
|
||||
get("/docs/this-document-does-not-exist")
|
||||
except urllib.error.HTTPError as error:
|
||||
assert error.code == 404
|
||||
else:
|
||||
raise RuntimeError("Unknown document did not return 404")
|
||||
print(f"Smoke passed: {base} (health, documents, JS/CSS, SVG, 404)", flush=True)
|
||||
def get(path):
|
||||
try:
|
||||
response = opener.open(base + path, timeout=15)
|
||||
except urllib.error.HTTPError as error:
|
||||
response = error
|
||||
with response:
|
||||
return response.code, response.headers, response.read()
|
||||
|
||||
status, _, health = get("/api/health")
|
||||
assert status == 200 and json.loads(health) == {"status": "ok"}
|
||||
status, _, login = get("/login")
|
||||
assert status == 200 and "输入动态码" in login.decode()
|
||||
for path in ("/", "/docs/00-endor-concepts-draft", "/figures/endor-architecture.svg"):
|
||||
status, headers, _ = get(path)
|
||||
assert status == 307, path
|
||||
target = urllib.parse.urlparse(urllib.parse.urljoin(base, headers["Location"]))
|
||||
assert target.netloc == urllib.parse.urlparse(base).netloc and target.path == "/login"
|
||||
assert "no-store" in headers.get("Cache-Control", "")
|
||||
assert get("/api/unknown")[0] == 401
|
||||
print(f"Public auth boundary passed: {base} (login, health, protected pages/SVG/API)", flush=True)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
Reference in New Issue
Block a user