From 6984c556e240b2936a37b321d0ab6f331ad7ffef Mon Sep 17 00:00:00 2001 From: Jonathan Liebig Date: Sun, 20 Sep 2026 03:09:30 +0200 Subject: [PATCH] fix: tolerate corrupt plugin registry during startup refs #3219 --- src/persist/plugin_registry.rs | 4 +++- src/plugin_installations.rs | 22 +++++++++++++++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/persist/plugin_registry.rs b/src/persist/plugin_registry.rs index 69a6e4ee..58c13596 100644 --- a/src/persist/plugin_registry.rs +++ b/src/persist/plugin_registry.rs @@ -16,7 +16,9 @@ fn registry_lock_path() -> PathBuf { crate::config::config_dir().join(REGISTRY_LOCK_FILE) } -fn with_registry_lock(operation: impl FnOnce() -> std::io::Result) -> std::io::Result { +pub(crate) fn with_registry_lock( + operation: impl FnOnce() -> std::io::Result, +) -> std::io::Result { let lock_path = registry_lock_path(); if let Some(parent) = lock_path.parent() { std::fs::create_dir_all(parent)?; diff --git a/src/plugin_installations.rs b/src/plugin_installations.rs index efb113cc..61e486db 100644 --- a/src/plugin_installations.rs +++ b/src/plugin_installations.rs @@ -89,7 +89,7 @@ fn installations() -> io::Result> { } pub(crate) fn retain_startup(leases: &mut Leases, restored_cwds: &[PathBuf]) -> io::Result<()> { - crate::persist::plugin_registry::read(|_| { + crate::persist::plugin_registry::with_registry_lock(|| { for installation in installations()? { if leases.contains_key(&installation) { continue; @@ -300,6 +300,26 @@ mod tests { assert!(!restored.exists()); assert!(!handoff.exists()); + // Corrupt registry contents disable plugins, not the server. The + // startup scan needs serialization, not registry deserialization. + let registry = crate::config::config_dir().join("plugins.json"); + std::fs::write(®istry, "not json").unwrap(); + let (_tx, rx) = tokio::sync::mpsc::unbounded_channel(); + let app = crate::app::App::try_new( + &crate::config::Config::default(), + crate::app::AppPolicy { + persist_plugin_registry: true, + ..crate::app::AppPolicy::TEST + }, + None, + rx, + crate::api::EventHub::default(), + ) + .expect("corrupt registry must not prevent server startup"); + assert!(app.state.installed_plugins.is_empty()); + drop(app); + std::fs::remove_file(registry).unwrap(); + let broken = crate::plugin_paths::create_managed_installation("example.broken").unwrap(); std::fs::create_dir(broken.join(LEASE_FILE)).unwrap();