diff options
| author | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-05-20 19:59:22 +0300 |
|---|---|---|
| committer | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-05-20 19:59:22 +0300 |
| commit | 8bbabfc5b1c9f6f318e057d34848df8e791a6c48 (patch) | |
| tree | c6ef7fd599e05997f39dc2f4c5eb9a2bc3e25b2a /src | |
| parent | 836fd7e585af15cc1ccb0d4f04586ffec28d2a3c (diff) | |
fix: harden release manifest update flow
Diffstat (limited to 'src')
| -rw-r--r-- | src/update.rs | 51 |
1 files changed, 48 insertions, 3 deletions
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<u32>, notes: String, assets: BTreeMap<String, String>, - announcement: Option<crate::product_announcements::ManifestAnnouncement>, + announcement: Option<serde_json::Value>, } #[derive(Deserialize)] @@ -158,9 +158,23 @@ fn fetch_update_manifest() -> Result<UpdateManifest, String> { } 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!( @@ -1550,6 +1565,36 @@ mod tests { } #[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")) .expect("website/latest.json should match updater schema"); |
