From e6deb5fe8413a08e4818932e1da1a99a04086d13 Mon Sep 17 00:00:00 2001 From: Owen Rummage Date: Mon, 17 Aug 2026 00:35:26 -0500 Subject: [PATCH] Fix stale block page preview by cache-busting static assets The preview iframe stayed blank after a redeploy because /static/js/app.js is served with a 24h Cache-Control and no versioning, so browsers kept using the pre-existing cached copy that predated the preview code. Static CSS/JS references now carry a ?v= query string so a new build is never masked by a stale cache. Also makes the CSP's frame-src explicit for the preview iframe rather than relying on the default-src fallback. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01TTKpGMQzpfDsvedu1hvSUf --- internal/web/render.go | 14 ++++++++++++++ internal/web/server.go | 1 + web/templates/layout.html | 4 ++-- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/internal/web/render.go b/internal/web/render.go index 87a12cb..b0be22d 100644 --- a/internal/web/render.go +++ b/internal/web/render.go @@ -30,12 +30,24 @@ type PageData struct { Flashes []Flash Alerts []Alert Version string + Asset string // cache-busting suffix for /static URLs; changes every build Now time.Time Data any Query url.Values BasePath string } +// assetVersion busts the browser cache for /static assets on every new +// build, so a redeploy is never masked by a day-old cached app.js. It falls +// back to the semantic version when no VCS commit was embedded (e.g. a build +// outside a git checkout), which is still stable within one running process. +var assetVersion = func() string { + if version.Commit != "" { + return version.Commit + } + return version.Version +}() + // Alert is a persistent banner such as "a restart is required". type Alert struct { Level string // warning, danger, info @@ -94,6 +106,7 @@ func (s *Server) render(w http.ResponseWriter, r *http.Request, page string, dat } data.Version = version.Version + data.Asset = assetVersion data.Now = time.Now() if data.Query == nil { data.Query = r.URL.Query() @@ -126,6 +139,7 @@ func (s *Server) renderError(w http.ResponseWriter, r *http.Request, status int, data := PageData{ Title: http.StatusText(status), Version: version.Version, + Asset: assetVersion, Now: time.Now(), Data: map[string]any{ "Status": status, diff --git a/internal/web/server.go b/internal/web/server.go index 12283c2..d00f36a 100644 --- a/internal/web/server.go +++ b/internal/web/server.go @@ -418,6 +418,7 @@ func (s *Server) withSecurityHeaders(next http.Handler) http.Handler { "font-src 'self'; "+ "connect-src 'self'; "+ "form-action 'self'; "+ + "frame-src 'self'; "+ "frame-ancestors 'none'; "+ "base-uri 'none'; "+ "object-src 'none'") diff --git a/web/templates/layout.html b/web/templates/layout.html index e161811..3b44604 100644 --- a/web/templates/layout.html +++ b/web/templates/layout.html @@ -8,7 +8,7 @@ - + @@ -119,7 +119,7 @@ - + {{block "scripts" .}}{{end}}