Merge pull request #428 from Molecule-AI/fix/securityheaders-test-stale-csp
fix(tests): CSP test fragment-match instead of exact-match
This commit is contained in:
commit
3cf5fd117a
@ -3,6 +3,7 @@ package middleware
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
@ -33,7 +34,6 @@ func TestSecurityHeaders(t *testing.T) {
|
||||
}{
|
||||
{"X-Content-Type-Options", "nosniff"},
|
||||
{"X-Frame-Options", "DENY"},
|
||||
{"Content-Security-Policy", "default-src 'self'"},
|
||||
{"Strict-Transport-Security", "max-age=31536000; includeSubDomains"},
|
||||
// #282: regression guards for the two headers that were
|
||||
// documented in CLAUDE.md but missing from the implementation.
|
||||
@ -47,6 +47,25 @@ func TestSecurityHeaders(t *testing.T) {
|
||||
t.Errorf("header %s = %q, want %q", tt.header, got, tt.want)
|
||||
}
|
||||
}
|
||||
|
||||
// CSP: widened to allow Next.js inline scripts/styles + data:/blob:
|
||||
// images because the canvas is reverse-proxied through the same
|
||||
// gin middleware stack. Assert the policy starts with the tight
|
||||
// default-src and contains each expected directive — exact-match
|
||||
// would brittle-break every time we tune a subsource list.
|
||||
csp := w.Header().Get("Content-Security-Policy")
|
||||
for _, fragment := range []string{
|
||||
"default-src 'self'",
|
||||
"script-src 'self' 'unsafe-inline' 'unsafe-eval'",
|
||||
"style-src 'self' 'unsafe-inline'",
|
||||
"img-src 'self' data: blob:",
|
||||
"connect-src 'self' ws: wss:",
|
||||
"font-src 'self' data:",
|
||||
} {
|
||||
if !strings.Contains(csp, fragment) {
|
||||
t.Errorf("CSP missing expected fragment %q (full CSP: %q)", fragment, csp)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSecurityHeadersPresenceOnMultipleRoutes(t *testing.T) {
|
||||
@ -75,8 +94,13 @@ func TestSecurityHeadersPresenceOnMultipleRoutes(t *testing.T) {
|
||||
if v := w2.Header().Get("Strict-Transport-Security"); v != "max-age=31536000; includeSubDomains" {
|
||||
t.Errorf("POST /b: Strict-Transport-Security = %q, want max-age=31536000; includeSubDomains", v)
|
||||
}
|
||||
if v := w2.Header().Get("Content-Security-Policy"); v != "default-src 'self'" {
|
||||
t.Errorf("POST /b: Content-Security-Policy = %q, want default-src 'self'", v)
|
||||
// Fragment-match rather than exact — CSP subsource lists get tuned
|
||||
// without changing the security posture. Test intent is "CSP is
|
||||
// present + starts with the tight default-src", not "CSP matches
|
||||
// this exact byte-for-byte string".
|
||||
csp := w2.Header().Get("Content-Security-Policy")
|
||||
if !strings.Contains(csp, "default-src 'self'") {
|
||||
t.Errorf("POST /b: CSP missing default-src 'self' (full: %q)", csp)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user