Skip to content

extract dashboard assets into embed.FS and tighten CSP#15

Merged
akarnani merged 1 commit into
mainfrom
webapp-csp-embed
Apr 29, 2026
Merged

extract dashboard assets into embed.FS and tighten CSP#15
akarnani merged 1 commit into
mainfrom
webapp-csp-embed

Conversation

@akarnani
Copy link
Copy Markdown
Owner

Stacked on top of #14.

Summary

  • Extract the dashboard's HTML, CSS, and JS out of the 740-line webapp/webapp.go const string into proper files under webapp/templates/ and webapp/static/, embedded via `go:embed`. Single static binary unchanged.
  • Replace every inline `onclick=` and `onsubmit=` with delegated event listeners keyed on `data-action` attributes — strict CSP becomes reachable.
  • Add `Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self'; object-src 'none'; frame-ancestors 'none'; base-uri 'none'` to the `securityHeaders` middleware.
  • Parse the template once at package init via `template.ParseFS` instead of re-parsing on every request.

Test plan

  • `go build`, `go test ./...` clean.
  • Smoke test: binary serves dashboard, `/static/dashboard.{js,css}` return with correct MIME types, CSP + all other security headers present on every response (verified across both port 8080 and the metrics-only 9090).
  • Visual verification in a browser: dashboard renders, search filters work, pagination works, auto-refresh works, browser back/forward works.

🤖 Generated with Claude Code

@akarnani akarnani force-pushed the helm-readonly-rootfs branch from 365f0a1 to c86e358 Compare April 29, 2026 17:18
The dashboard was a single 740-line Go file with HTML, CSS, and JS
glued into a const string and inline onclick= attributes throughout.
Strict CSP (no 'unsafe-inline') was unreachable in that shape, and the
embedded source was hostile to read and edit.

Move the assets into proper files under webapp/templates/ and
webapp/static/, embed them via go:embed, and parse the template once
at package init via ParseFS. Static assets are served by
http.FileServer over the embedded fs, mounted at /static/. Single
static binary unchanged, still works with readOnlyRootFilesystem.

Replace every inline onclick= with delegated event listeners keyed on
data-action attributes. The form's onsubmit="return false" becomes a
submit listener calling preventDefault.

Add a Content-Security-Policy header to the securityHeaders middleware:
default-src 'self'; script-src 'self'; style-src 'self'; object-src
'none'; frame-ancestors 'none'; base-uri 'none'. No inline script,
no eval, no third-party origins.

Verified end-to-end: dashboard renders, /static/dashboard.{js,css}
serve with correct MIME types, CSP header present on all responses
(including /metrics on the separate port), all hardening headers
flowing.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Base automatically changed from helm-readonly-rootfs to main April 29, 2026 18:46
@akarnani akarnani merged commit b633d12 into main Apr 29, 2026
13 checks passed
@akarnani akarnani deleted the webapp-csp-embed branch April 29, 2026 18:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant