chore(server): switch CSP to report-only while tuning

Emit the policy via Content-Security-Policy-Report-Only instead of the
enforcing header so browsers log violations without blocking resources
while we debug remaining CSP issues. The policy string is unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Bryan Helmkamp 2026-06-01 19:42:29 -04:00
parent b3528a982e
commit efbd2d02e0
No known key found for this signature in database
2 changed files with 13 additions and 8 deletions

View file

@ -20,9 +20,14 @@ pub async fn layer(req: Request, next: Next) -> Response {
}
fn apply_csp(headers: &mut HeaderMap) {
// Report-only while we tune the policy: browsers evaluate violations and log
// them to the console without blocking any resources. Switch back to the
// enforcing `content-security-policy` header once the policy is clean.
if let Ok(value) = HeaderValue::from_str(csp::policy()) {
headers
.entry(HeaderName::from_static("content-security-policy"))
.entry(HeaderName::from_static(
"content-security-policy-report-only",
))
.or_insert(value);
}
}
@ -187,11 +192,11 @@ mod tests {
}
#[test]
fn csp_is_enforced_not_report_only() {
fn csp_is_report_only_not_enforced() {
let mut headers = HeaderMap::new();
apply_csp(&mut headers);
assert!(headers.contains_key("content-security-policy"));
assert!(!headers.contains_key("content-security-policy-report-only"));
assert!(headers.contains_key("content-security-policy-report-only"));
assert!(!headers.contains_key("content-security-policy"));
}
#[test]

View file

@ -350,15 +350,15 @@ async fn security_headers_are_applied_to_all_responses() {
// external module scripts.
let csp = spa_response
.headers()
.get("content-security-policy")
.expect("CSP header should be emitted")
.get("content-security-policy-report-only")
.expect("CSP report-only header should be emitted")
.to_str()
.expect("CSP should be ASCII");
assert!(
!spa_response
.headers()
.contains_key("content-security-policy-report-only"),
"CSP should be enforced, not report-only"
.contains_key("content-security-policy"),
"CSP should be report-only while tuning, not enforced"
);
assert!(csp.contains("default-src 'self'"), "got: {csp}");
assert!(csp.contains("script-src 'self'"), "got: {csp}");