feat(hardening): production logging, single-instance, CSP, and scoped asset protocol

Phase 4 of the 0.1.0 release prep:
- tauri-plugin-log: rotating file log (5 MB, Info) in the app log dir plus
  stdout; all 54 backend println!/eprintln! sites migrated to log macros so
  release builds finally produce diagnostics
- tauri-plugin-single-instance (registered first): second launches focus the
  existing window instead of racing the same SQLite DB with a second worker
  fleet; tauri-plugin-window-state persists window geometry
- real CSP replacing null (scripts self-only, media/images via the asset
  protocol, IPC endpoints whitelisted, object-src none) with a devCsp
  variant for Vite HMR
- asset protocol scope narrowed from '**' to thumbnails statically plus
  per-folder runtime grants (setup, add_folder, update_folder_path)

Panic audit (plan item) concluded with no changes: worker loops already
catch and log all Result errors; remaining unwraps are startup fail-fast,
poisoned-lock convention, infallible-by-construction, or test code.
This commit is contained in:
2026-06-12 20:12:03 +01:00
parent 890c23bdce
commit 3fb4a9685f
10 changed files with 454 additions and 61 deletions
+4 -4
View File
@@ -443,7 +443,7 @@ impl WdTagger {
let labels = load_labels(&labels_path)?;
println!(
log::info!(
"WD tagger loaded in {:?} ({} labels, input {}x{}, {:?} acceleration)",
started_at.elapsed(),
labels.len(),
@@ -519,7 +519,7 @@ impl WdTagger {
tags.sort_by(|a, b| b.confidence.total_cmp(&a.confidence));
tags.truncate(max_tags);
println!(
log::info!(
"WD tagger: {} tags (threshold={}, rating={}) in {:?} for {}",
tags.len(),
self.threshold,
@@ -559,13 +559,13 @@ fn create_tagger_session(path: &Path, acceleration: TaggerAcceleration) -> Resul
let mut builder = match acceleration {
TaggerAcceleration::Cpu => {
println!("WD tagger: using CPU execution provider");
log::info!("WD tagger: using CPU execution provider");
builder
}
TaggerAcceleration::Auto => builder
.with_execution_providers([ep::DirectML::default().build().fail_silently()])
.unwrap_or_else(|error| {
println!("WD tagger: DirectML unavailable, falling back to CPU");
log::info!("WD tagger: DirectML unavailable, falling back to CPU");
error.recover()
}),
TaggerAcceleration::Directml => builder