//! Guards on the packaged-app Content-Security-Policy in `tauri.conf.json`. //! //! The CSP is only enforced on assets Tauri itself serves, so neither //! `just dev` (loads the Vite `devUrl`) nor the Playwright suite (runs under //! `vite preview`) can catch a policy that breaks the app. These tests pin the //! non-obvious sources the frontend actually needs, so a future tightening //! fails here instead of in a signed build. //! //! Kept as an integration test so the policy can be checked without the app //! crate having to declare a test-only module. use std::collections::HashMap; const TAURI_CONF: &str = include_str!("../tauri.conf.json"); fn csp_directives() -> HashMap> { let conf: serde_json::Value = serde_json::from_str(TAURI_CONF).expect("tauri.conf.json is valid JSON"); let csp = conf["app"]["security"]["csp"] .as_str() .expect("app.security.csp is set as a policy string"); csp.split(';') .filter_map(|directive| { let mut parts = directive.split_whitespace(); let name = parts.next()?; Some((name.to_owned(), parts.map(str::to_owned).collect())) }) .collect() } fn sources(directive: &str) -> Vec { csp_directives() .remove(directive) .unwrap_or_else(|| panic!("csp is missing the {directive} directive")) } #[test] fn script_src_allows_wasm_instantiation() { // Shiki's default engine (Oniguruma) instantiates inlined WebAssembly for // every code block; MediaPipe selfie segmentation does the same. Without // this token both silently degrade — highlighting drops to plain text and // animated avatars keep their background. assert!(sources("script-src").contains(&"'wasm-unsafe-eval'".to_owned())); } /// The `MEDIAPIPE_WASM_BASE` literal the frontend hands to `FilesetResolver`. fn mediapipe_wasm_base() -> String { const CAPTURE: &str = include_str!("../../src/features/profile/lib/animatedAvatarCapture.ts"); let after = CAPTURE .split_once("const MEDIAPIPE_WASM_BASE =") .expect("animatedAvatarCapture.ts declares MEDIAPIPE_WASM_BASE") .1; let url = after .split_once('"') .expect("MEDIAPIPE_WASM_BASE is a double-quoted string literal") .1; url.split_once('"') .expect("MEDIAPIPE_WASM_BASE literal is terminated") .0 .to_owned() } /// The npm scope the MediaPipe loader must come from. A CSP source ending in /// `/` is a path *prefix* — paths can't be wildcarded — so this admits any /// `@mediapipe` package while excluding the rest of what jsDelivr serves. const MEDIAPIPE_SCOPE: &str = "https://cdn.jsdelivr.net/npm/@mediapipe/"; #[test] fn script_src_scopes_the_mediapipe_loader() { // `FilesetResolver.forVisionTasks` loads `vision_wasm[_nosimd]_internal.js` // via a `