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
+9 -9
View File
@@ -470,7 +470,7 @@ impl FlorenceCaptioner {
acceleration,
false,
)?;
println!(
log::info!(
"Florence sessions loaded in {:?} with {:?} acceleration (total init {:?})",
sessions_started_at.elapsed(),
acceleration,
@@ -490,9 +490,9 @@ impl FlorenceCaptioner {
pub fn generate(&mut self, image_path: &Path) -> Result<String> {
let started_at = Instant::now();
println!("Florence caption started: {}", image_path.display());
log::info!("Florence caption started: {}", image_path.display());
let image_features = run_vision_encoder(&mut self.vision_session, image_path)?;
println!("Florence vision encoder done in {:?}", started_at.elapsed());
log::info!("Florence vision encoder done in {:?}", started_at.elapsed());
let prompt_ids = self
.tokenizer
.encode(self.caption_detail.prompt(), false)
@@ -502,7 +502,7 @@ impl FlorenceCaptioner {
.map(|id| i64::from(*id))
.collect::<Vec<_>>();
let prompt_embeds = run_token_embedder(&mut self.embed_session, &prompt_ids)?;
println!(
log::info!(
"Florence token embeddings done in {:?}",
started_at.elapsed()
);
@@ -513,7 +513,7 @@ impl FlorenceCaptioner {
&encoder_embeds,
&encoder_attention_mask,
)?;
println!("Florence encoder done in {:?}", started_at.elapsed());
log::info!("Florence encoder done in {:?}", started_at.elapsed());
let generated_ids = run_decoder(
&mut self.decoder_prefill_session,
@@ -523,7 +523,7 @@ impl FlorenceCaptioner {
&encoder_attention_mask,
self.caption_detail.max_new_tokens(),
)?;
println!("Florence decoder done in {:?}", started_at.elapsed());
log::info!("Florence decoder done in {:?}", started_at.elapsed());
let generated_u32 = generated_ids
.into_iter()
@@ -784,7 +784,7 @@ fn run_decoder(
"inputs_embeds" => prefill_inputs_embeds_tensor
})
.map_err(|error| anyhow::anyhow!("{error}"))?;
println!(
log::info!(
"Florence decoder prefill done in {:?}",
prefill_started_at.elapsed()
);
@@ -848,7 +848,7 @@ fn run_decoder(
decoder_kv = collect_present_key_values(&outputs, DECODER_LAYERS)?;
}
println!("Florence decoder produced {} token(s)", generated.len());
log::info!("Florence decoder produced {} token(s)", generated.len());
Ok(generated)
}
@@ -886,7 +886,7 @@ fn create_session(
CaptionAcceleration::Auto | CaptionAcceleration::Directml => {
// `allow_directml` is false for the 4 text/decoder sessions —
// they intentionally run on CPU regardless of the setting.
println!(
log::info!(
"Florence: using CPU for {} (DirectML disabled for this session type)",
path.display()
);