From 7bae5ecd265ffa9c21b01f5c4a0c45c4ebcb1643 Mon Sep 17 00:00:00 2001 From: Bryan Oltman Date: Fri, 8 Nov 2024 17:00:31 -0500 Subject: [PATCH 1/2] fix: reset patches when updater state fails to deserialize --- library/src/cache/updater_state.rs | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/library/src/cache/updater_state.rs b/library/src/cache/updater_state.rs index 459b33c..71655df 100644 --- a/library/src/cache/updater_state.rs +++ b/library/src/cache/updater_state.rs @@ -132,7 +132,10 @@ impl UpdaterState { if !is_file_not_found(&e) { shorebird_info!("No existing state file found: {:#}, creating new state.", e); } - Self::create_new_and_save(storage_dir, release_version, patch_public_key) + let mut new = + Self::create_new_and_save(storage_dir, release_version, patch_public_key); + let _ = new.patch_manager.reset(); + new } } } @@ -445,4 +448,26 @@ mod tests { assert!(state.is_known_bad_patch(1)); assert!(!state.is_known_bad_patch(2)); } + + #[test] + fn load_or_new_on_error_clears_patch_state_on_error() -> Result<()> { + let tmp_dir = TempDir::new("example")?; + + // Create a new state, add a patch, and save it. + let mut state = UpdaterState::load_or_new_on_error(&tmp_dir.path(), "1.0.0+1", None); + let patch = fake_patch(&tmp_dir, 1); + state.install_patch(&patch, "hash", None)?; + state.save()?; + assert_eq!(state.next_boot_patch().unwrap().number, 1); + + // Corrupt the state file. + let state_file = tmp_dir.path().join(STATE_FILE_NAME); + std::fs::write(&state_file, "corrupt json")?; + + // Ensure that, by corrupting the file, we've reset the patches state. + let mut state = UpdaterState::load_or_new_on_error(&tmp_dir.path(), "1.0.0+2", None); + assert!(state.next_boot_patch().is_none()); + + Ok(()) + } } From e7cce9c8b7629b1dc2c0e4080cf9f69ecf975795 Mon Sep 17 00:00:00 2001 From: Bryan Oltman Date: Fri, 8 Nov 2024 17:07:34 -0500 Subject: [PATCH 2/2] cleanup --- library/src/cache/updater_state.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/library/src/cache/updater_state.rs b/library/src/cache/updater_state.rs index 71655df..551f497 100644 --- a/library/src/cache/updater_state.rs +++ b/library/src/cache/updater_state.rs @@ -94,7 +94,7 @@ impl UpdaterState { release_version: &str, patch_public_key: Option<&str>, ) -> Self { - let state = Self::new( + let mut state = Self::new( storage_dir.to_owned(), release_version.to_owned(), patch_public_key, @@ -102,6 +102,8 @@ impl UpdaterState { if let Err(e) = state.save() { shorebird_warn!("Error saving state {:?}, ignoring.", e); } + // Ensure we clear any patch data if we're creating a new state. + let _ = state.patch_manager.reset(); state } @@ -112,14 +114,13 @@ impl UpdaterState { ) -> Self { let load_result = Self::load(storage_dir, patch_public_key); match load_result { - Ok(mut loaded) => { + Ok(loaded) => { if loaded.serialized_state.release_version != release_version { shorebird_info!( "release_version changed {} -> {}, creating new state", loaded.serialized_state.release_version, release_version ); - let _ = loaded.patch_manager.reset(); return Self::create_new_and_save( storage_dir, release_version, @@ -132,10 +133,7 @@ impl UpdaterState { if !is_file_not_found(&e) { shorebird_info!("No existing state file found: {:#}, creating new state.", e); } - let mut new = - Self::create_new_and_save(storage_dir, release_version, patch_public_key); - let _ = new.patch_manager.reset(); - new + Self::create_new_and_save(storage_dir, release_version, patch_public_key) } } }