Files
minstrel/web/csp_test.go
T
bvandeusenandClaude Opus 5.5 10d50dccbd docs: web comments say what the app does, not how it came to be (#6277)
Rewrites the web app's comments to rule 32. Task, milestone, rule and
spec ids are gone; regression stories are restated as the trap they
guard (public auth routes, the menu's stopPropagation, universal loads
under adapter-static, metric deltas with their margin). Flutter and
Tauri mentions now name the Android app or a native shell, operator
quotes and dates are dropped, and one library's counts no longer
appear outside test fixtures. Verified with a TypeScript-scanner token
comparison (template literals and regex literals re-scanned): only
comment text changed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 12:42:12 -04:00

61 lines
2.0 KiB
Go

package web
import (
"crypto/sha256"
"encoding/base64"
"strings"
"testing"
)
func hashOf(body string) string {
sum := sha256.Sum256([]byte(body))
return "'sha256-" + base64.StdEncoding.EncodeToString(sum[:]) + "'"
}
func TestContentSecurityPolicy_HashesInlineScriptsOnly(t *testing.T) {
theme := "(function () { document.documentElement.dataset.theme = 'dark'; })();"
brand := `window.__MINSTREL__ = { appName: "Minstrel" };`
html := "<html><head><script>" + theme + "</script>" +
`<script type="module" src="/_app/start.js"></script>` +
"<script>" + brand + "</script></head></html>"
csp := contentSecurityPolicy([]byte(html))
var scriptSrc string
for _, d := range strings.Split(csp, "; ") {
if strings.HasPrefix(d, "script-src ") {
scriptSrc = d
}
}
if scriptSrc == "" {
t.Fatalf("no script-src in %q", csp)
}
for _, want := range []string{"'self'", hashOf(theme), hashOf(brand)} {
if !strings.Contains(scriptSrc, want) {
t.Errorf("script-src %q missing %s", scriptSrc, want)
}
}
if strings.Count(scriptSrc, "'sha256-") != 2 {
t.Errorf("script-src %q: want exactly the two inline scripts hashed, not the src= one", scriptSrc)
}
if strings.Contains(scriptSrc, "unsafe-inline") || strings.Contains(scriptSrc, "unsafe-eval") {
t.Errorf("script-src must not fall back to unsafe-*: %q", scriptSrc)
}
for _, want := range []string{"frame-ancestors 'none'", "object-src 'none'", "connect-src 'self'"} {
if !strings.Contains(csp, want) {
t.Errorf("csp missing %q", want)
}
}
}
// The hash must be of the page as served, after the branding template has
// substituted the app's name, or a renamed instance would refuse
// its own bootstrap script.
func TestContentSecurityPolicy_TracksTemplatedContent(t *testing.T) {
a := contentSecurityPolicy([]byte(`<script>window.__MINSTREL__ = { appName: "A" };</script>`))
b := contentSecurityPolicy([]byte(`<script>window.__MINSTREL__ = { appName: "B" };</script>`))
if a == b {
t.Error("different script bodies produced the same policy")
}
}