From 8bbabfc5b1c9f6f318e057d34848df8e791a6c48 Mon Sep 17 00:00:00 2001 From: Ogulcan Celik Date: Wed, 20 May 2026 19:59:22 +0300 Subject: fix: harden release manifest update flow --- src/update.rs | 51 ++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 48 insertions(+), 3 deletions(-) (limited to 'src/update.rs') diff --git a/src/update.rs b/src/update.rs index 63b58c08..60fa594e 100644 --- a/src/update.rs +++ b/src/update.rs @@ -98,7 +98,7 @@ struct UpdateManifest { protocol: Option, notes: String, assets: BTreeMap, - announcement: Option, + announcement: Option, } #[derive(Deserialize)] @@ -158,9 +158,23 @@ fn fetch_update_manifest() -> Result { } fn handle_manifest_announcement(manifest: &UpdateManifest) { + let announcement = match manifest.announcement.as_ref() { + Some(value) => match serde_json::from_value::< + crate::product_announcements::ManifestAnnouncement, + >(value.clone()) + { + Ok(announcement) => Some(announcement), + Err(err) => { + tracing::warn!("skipping invalid product announcement in update manifest: {err}"); + None + } + }, + None => None, + }; + if let Err(err) = crate::product_announcements::save_manifest_announcement( &manifest.version, - manifest.announcement.as_ref(), + announcement.as_ref(), ) { tracing::warn!("failed to save product announcement: {err}"); } @@ -1528,7 +1542,8 @@ mod tests { manifest .announcement .as_ref() - .map(|announcement| announcement.id.as_str()), + .and_then(|announcement| announcement.get("id")) + .and_then(serde_json::Value::as_str), Some("keymap-v2") ); assert_eq!( @@ -1549,6 +1564,36 @@ mod tests { assert!(serde_json::from_str::(json).is_err()); } + #[test] + fn invalid_manifest_announcement_does_not_block_release_info() { + let (os, arch) = platform_target(); + let asset_key = format!("{os}-{arch}"); + let json = format!( + r####"{{ + "version": "99.99.99", + "protocol": 4, + "notes": "### Changed\n- One", + "announcement": {{ + "id": 123, + "title": "Keymap changes", + "body": "### Heads up\n- Defaults changed" + }}, + "assets": {{ + "{asset_key}": "https://example.com/herdr" + }} + }}"#### + ); + + let manifest: UpdateManifest = serde_json::from_str(&json).unwrap(); + handle_manifest_announcement(&manifest); + let release = release_info_from_manifest(manifest) + .unwrap() + .expect("release info"); + + assert_eq!(release.version, Version::parse("99.99.99").unwrap()); + assert_eq!(release.download_url, "https://example.com/herdr"); + } + #[test] fn checked_in_website_manifest_matches_update_schema() { let manifest: UpdateManifest = serde_json::from_str(include_str!("../website/latest.json")) -- cgit v1.2.3