chore(hardening): tighten security and footprint defaults
This commit is contained in:
93
src-tauri/tests/config_hardening.rs
Normal file
93
src-tauri/tests/config_hardening.rs
Normal file
@@ -0,0 +1,93 @@
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
|
||||
use serde_json::Value;
|
||||
|
||||
fn manifest_dir() -> &'static Path {
|
||||
Path::new(env!("CARGO_MANIFEST_DIR"))
|
||||
}
|
||||
|
||||
fn read_json(path: impl AsRef<Path>) -> Value {
|
||||
let raw = fs::read_to_string(path.as_ref()).expect("read json file");
|
||||
serde_json::from_str(&raw).expect("valid json")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn csp_keeps_loopback_narrow() {
|
||||
let conf = read_json(manifest_dir().join("tauri.conf.json"));
|
||||
let csp = conf
|
||||
.pointer("/app/security/csp")
|
||||
.and_then(Value::as_str)
|
||||
.expect("csp string");
|
||||
let connect_src = csp
|
||||
.split(';')
|
||||
.map(str::trim)
|
||||
.find(|directive| directive.starts_with("connect-src "))
|
||||
.expect("connect-src directive");
|
||||
|
||||
assert!(connect_src.contains("http://127.0.0.1:*"));
|
||||
assert!(connect_src.contains("ws://127.0.0.1:*"));
|
||||
assert!(!connect_src.contains("http://localhost:*"));
|
||||
assert!(!connect_src.contains("ws://localhost:*"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn updater_is_signed_or_absent() {
|
||||
let conf = read_json(manifest_dir().join("tauri.conf.json"));
|
||||
if let Some(updater) = conf.pointer("/plugins/updater") {
|
||||
let pubkey = updater
|
||||
.get("pubkey")
|
||||
.and_then(Value::as_str)
|
||||
.unwrap_or_default();
|
||||
assert!(
|
||||
!pubkey.trim().is_empty(),
|
||||
"updater config must not ship with an empty pubkey"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn secondary_windows_do_not_get_high_risk_plugin_permissions() {
|
||||
let denied = [
|
||||
"dialog:",
|
||||
"autostart:",
|
||||
"global-shortcut:",
|
||||
"opener:",
|
||||
"updater:",
|
||||
];
|
||||
let capability_dir = manifest_dir().join("capabilities");
|
||||
|
||||
for entry in fs::read_dir(capability_dir).expect("capabilities dir") {
|
||||
let path = entry.expect("capability entry").path();
|
||||
if path.extension().and_then(|ext| ext.to_str()) != Some("json") {
|
||||
continue;
|
||||
}
|
||||
let capability = read_json(&path);
|
||||
let windows = capability
|
||||
.get("windows")
|
||||
.and_then(Value::as_array)
|
||||
.cloned()
|
||||
.unwrap_or_default();
|
||||
let applies_to_secondary = windows.iter().any(|window| {
|
||||
matches!(
|
||||
window.as_str(),
|
||||
Some("tasks-float" | "transcript-viewer" | "transcription-preview")
|
||||
)
|
||||
});
|
||||
if !applies_to_secondary {
|
||||
continue;
|
||||
}
|
||||
let permissions = capability
|
||||
.get("permissions")
|
||||
.and_then(Value::as_array)
|
||||
.cloned()
|
||||
.unwrap_or_default();
|
||||
for permission in permissions.iter().filter_map(Value::as_str) {
|
||||
assert!(
|
||||
!denied.iter().any(|prefix| permission.starts_with(prefix)),
|
||||
"{} grants high-risk permission {permission} to a secondary window",
|
||||
path.display()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user