From 05d768343cb646c3e47bc676b9998c95918e1242 Mon Sep 17 00:00:00 2001 From: fm crewmate Date: Wed, 9 Sep 2026 01:01:47 +0000 Subject: [PATCH 1/2] fix(frontend): vendor Alpine.js + Tailwind same-origin (LAN-safe demo) The P0 templates loaded Alpine.js from cdn.jsdelivr.net and Tailwind from cdn.tailwindcss.com, so LAN-only demo clients got a login page whose JS never engaged (stuck form). Vendor both libraries under app/static/vendor/ (alpine-3.17.2.min.js, tailwind-3.4.17.js) served same-origin at /static, point base.html at local paths, and drop both CDN hosts from the CSP (script-src/style-src stay 'self' 'unsafe-inline'; connect-src 'self'). HTML pages now ship Cache-Control: no-cache; vendored assets are cached public, max-age=31536000, immutable (versioned filenames). HSTS stays TLS-gated. Adds tests/test_frontend_vendoring.py (no external script src on /login, both vendor paths 200, no-cache + immutable header checks, CSP without CDN hosts). --- AGENTS.md | 16 ++++- app/main.py | 40 +++++++++++-- app/static/vendor/alpine-3.17.2.min.js | 21 +++++++ app/static/vendor/tailwind-3.4.17.js | 83 ++++++++++++++++++++++++++ app/templates/base.html | 5 +- tests/test_frontend_vendoring.py | 74 +++++++++++++++++++++++ 6 files changed, 231 insertions(+), 8 deletions(-) create mode 100644 app/static/vendor/alpine-3.17.2.min.js create mode 100644 app/static/vendor/tailwind-3.4.17.js create mode 100644 tests/test_frontend_vendoring.py diff --git a/AGENTS.md b/AGENTS.md index 15fd99c..6b10a86 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -77,7 +77,20 @@ sign-up UI; users are created/managed by admins only (P0 hardening batch). | GET | `/tickets/new` | Client | Create Issue form | | GET | `/tickets/{id}` | Client | Issue detail with timeline | -Frontend: Alpine.js (CDN) + Tailwind CSS (CDN). Auth state in localStorage. Role-based nav routing in `base.html`. +Frontend: Alpine.js + Tailwind CSS vendored same-origin (no CDN) — see +"Frontend assets" below. Auth state in localStorage. Role-based nav routing in `base.html`. + +### Frontend assets (vendored, LAN-safe) +- Alpine.js 3.17.2 + Tailwind Play 3.4.17 are committed under `app/static/vendor/` + and served at `/static/vendor/…` (mounted in `app/main.py`, versioned + filenames → immutable cache `public, max-age=31536000, immutable`). Templates + must never reference a CDN; update `app/templates/base.html` when upgrading: + download `alpinejs@/dist/cdn.min.js` (jsDelivr) and the tailwind play + script (`cdn.tailwindcss.com/`), save as `app/static/vendor/-.min.js`, + bump the ` - + + +