diff --git a/CHANGELOG.md b/CHANGELOG.md index cbbe6eb8..30624a78 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [Unreleased] + +### Changed + +- **CSP inline script elimination**: Moved inline scripts to external files; + only the import map remains inline with a CSP nonce, eliminating Safari CSP + false-positive violations. + ## [0.8.8] - 2026-02-11 ### Changed diff --git a/crates/gateway/src/assets/index.html b/crates/gateway/src/assets/index.html index 7272e7ce..4cfbcbda 100644 --- a/crates/gateway/src/assets/index.html +++ b/crates/gateway/src/assets/index.html @@ -16,7 +16,7 @@ - + {{ share_site_name }} @@ -37,8 +37,7 @@ - - + disconnected
@@ -538,6 +536,6 @@

No LLMs Connected

- + diff --git a/crates/gateway/src/assets/js/gon.js b/crates/gateway/src/assets/js/gon.js index 114d3c00..573f90fd 100644 --- a/crates/gateway/src/assets/js/gon.js +++ b/crates/gateway/src/assets/js/gon.js @@ -1,14 +1,15 @@ // ── Server-injected data (gon pattern) ──────────────────── // -// The server injects `window.__MOLTIS__ = { ... }` into every -// page before any module script runs. This module -// provides typed access, runtime updates, and a refresh -// mechanism that re-fetches the data from `/api/gon`. +// The server injects a ` + {{ page_title }} - - + + diff --git a/crates/gateway/src/assets/onboarding.html b/crates/gateway/src/assets/onboarding.html index 49a6ac48..f8b89382 100644 --- a/crates/gateway/src/assets/onboarding.html +++ b/crates/gateway/src/assets/onboarding.html @@ -4,7 +4,7 @@ - + {{ page_title }} @@ -25,6 +25,6 @@
- + diff --git a/crates/gateway/src/assets/sw.js b/crates/gateway/src/assets/sw.js index 52d81707..ed6a70ac 100644 --- a/crates/gateway/src/assets/sw.js +++ b/crates/gateway/src/assets/sw.js @@ -4,6 +4,7 @@ var CACHE_NAME = "moltis-v2"; var STATIC_ASSETS = [ "/manifest.json", + "/assets/js/theme-init.js", "/assets/css/base.css", "/assets/css/layout.css", "/assets/css/chat.css", diff --git a/crates/gateway/src/server.rs b/crates/gateway/src/server.rs index 003aa919..68f8122d 100644 --- a/crates/gateway/src/server.rs +++ b/crates/gateway/src/server.rs @@ -5711,11 +5711,14 @@ mod tests { assert!(html.contains("/assets/v/test/js/onboarding-app.js")); assert!(!html.contains("/assets/v/test/js/app.js")); assert!(!html.contains("/manifest.json")); - assert!(html.contains("")); + // Import map still requires a nonce. assert!(html.contains("")); + // Gon data is now a non-executable JSON blob. assert!(html.contains( - "" + "" )); + // External module script does NOT need a nonce. + assert!( + html.contains( + "" + ) + ); + // Theme init is external. + assert!(html.contains("")); + // Inline favicon script was removed. + assert!(!html.contains("var svg=")); + // Import map still has nonce. + assert!(html.contains("" - ))); + // Theme init is now an external script (no nonce needed, allowed by 'self'). + assert!(index_html.contains("")); + // Gon data is a non-executable JSON blob (no nonce needed). + assert!(index_html.contains("" - ))); + // External module script does NOT need a nonce (allowed by 'self'). + assert!( + index_html + .contains("") + ); + // Inline title-update script was removed (handled by app.js). + assert!(!index_html.contains("document.title=a}()")); let onboarding_template = OnboardingHtmlTemplate { build_ts: "dev", @@ -6155,9 +6177,18 @@ mod tests { Ok(html) => html, Err(e) => panic!("failed to render onboarding template: {e}"), }; - assert!(onboarding_html.contains(&format!( - "" - ))); + // Onboarding: external module script does NOT need a nonce. + assert!(onboarding_html.contains( + "" + )); + // Onboarding: theme init is external. + assert!( + onboarding_html.contains("") + ); + // Onboarding: import map still has nonce. + assert!( + onboarding_html.contains(&format!("