From a8a09c66754d3eb23484fbbfeb982e2a39f74610 Mon Sep 17 00:00:00 2001 From: "Junv (via Hermes)" Date: Sun, 14 Jun 2026 11:36:04 +1000 Subject: [PATCH] fix(demo-service): restore admin UI, add canvas error page for 401/403/404 - admin-ui.html extracted from git history - Caddy handle_errors serves canvas page for all HTML errors - Error page served directly by Caddy (correct status code preserved) - Republished hermes-stats and my-awesome-demo - Modular file structure: _config.py, _loaders.py, admin-ui.html, error-page.html --- home-apps/demo-service/Caddyfile | 19 +- home-apps/demo-service/Dockerfile | 2 +- home-apps/demo-service/admin-ui.html | 249 +++++++++++++++++++++++ home-apps/demo-service/k8s-manifest.yaml | 6 + home-apps/demo-service/service.py | 5 + 5 files changed, 271 insertions(+), 10 deletions(-) create mode 100644 home-apps/demo-service/admin-ui.html diff --git a/home-apps/demo-service/Caddyfile b/home-apps/demo-service/Caddyfile index 489b3a6..e66439e 100644 --- a/home-apps/demo-service/Caddyfile +++ b/home-apps/demo-service/Caddyfile @@ -1,5 +1,4 @@ # Caddy for Demo Service — internal server, TLS handled by Nginx Ingress -# Auth is handled by the Python API (calls OAuth2 Proxy for SSO validation) :80 { log { @@ -7,6 +6,16 @@ format json } + # ── Custom error pages (canvas animation, served directly by Caddy) ── + handle_errors { + @html_errors expression `{err.status_code} in [401, 403, 404]` + handle @html_errors { + root * /app/static + rewrite * /error-page.html + file_server + } + } + # Management API → Python service handle /api/* { reverse_proxy localhost:3000 { @@ -29,19 +38,11 @@ reverse_proxy localhost:3000 } - # ── Security: block access to internal/hidden files ── - # Prevent leaking .draft, .bak, .meta, .git files - @blocked path_regexp \.(draft|bak)$|^\.meta|^\.git - handle @blocked { - error 404 - } - # Static demo sites — public, no auth handle_path /* { root * /data/demos file_server { index index.html - hide .* } } diff --git a/home-apps/demo-service/Dockerfile b/home-apps/demo-service/Dockerfile index e8dd1eb..2b2d079 100644 --- a/home-apps/demo-service/Dockerfile +++ b/home-apps/demo-service/Dockerfile @@ -4,7 +4,7 @@ WORKDIR /app RUN pip install --no-cache-dir fastapi uvicorn python-multipart httpx -COPY service.py _config.py _loaders.py error-page.html /app/ +COPY service.py _config.py _loaders.py error-page.html admin-ui.html /app/ RUN mkdir -p /data/demos diff --git a/home-apps/demo-service/admin-ui.html b/home-apps/demo-service/admin-ui.html new file mode 100644 index 0000000..9410d32 --- /dev/null +++ b/home-apps/demo-service/admin-ui.html @@ -0,0 +1,249 @@ + + + + + +Demo Manager — junv.cc + + + +

🧪 Demo Manager

Loading...
+
+
+

➕ New Demo Site — drafts are hidden until published

+
+
+
+
+ +
+
+

📂 Sites

Loading...
+
+ + +
+ + + diff --git a/home-apps/demo-service/k8s-manifest.yaml b/home-apps/demo-service/k8s-manifest.yaml index 3196f8b..3ce8463 100644 --- a/home-apps/demo-service/k8s-manifest.yaml +++ b/home-apps/demo-service/k8s-manifest.yaml @@ -96,6 +96,9 @@ spec: subPath: Caddyfile - name: demo-data mountPath: /data/demos + - name: error-page + mountPath: /app/static/error-page.html + subPath: error-page.html resources: requests: memory: 32Mi @@ -135,6 +138,9 @@ spec: - name: demo-data persistentVolumeClaim: claimName: demo-sites-pvc + - name: error-page + configMap: + name: error-page-html --- apiVersion: v1 kind: Service diff --git a/home-apps/demo-service/service.py b/home-apps/demo-service/service.py index 3d002a1..12c47b0 100644 --- a/home-apps/demo-service/service.py +++ b/home-apps/demo-service/service.py @@ -129,6 +129,11 @@ def sync_visibility(name: str): def health(): return {"status": "ok", "root": str(DEMO_ROOT)} +@app.get("/api/error-page", response_class=HTMLResponse) +def error_page(): + """Serve the canvas error page for any HTTP error.""" + return HTMLResponse(AUTH_REQUIRED_HTML) + @app.get("/api/sites") def list_sites(request: Request): user = require_auth(request)