diff --git a/CHANGELOG.md b/CHANGELOG.md index e25b738c834..c3128f20e84 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ - Preserve user specified event values in Unreal crash reports. ([#4882](https://github.com/getsentry/relay/pull/4882)) - OS name parsing of Unreal crash reports. ([#4854](https://github.com/getsentry/relay/pull/4854)) - Do not overwrite geo information if already set. ([#4888](https://github.com/getsentry/relay/pull/4888)) +- The `type` fields of contexts are now enforced to be strings. Non-string values are replaced with the + context's key. ([#4932](https://github.com/getsentry/relay/pull/4932)) **Internal**: diff --git a/relay-event-schema/src/protocol/contexts/mod.rs b/relay-event-schema/src/protocol/contexts/mod.rs index 04ad6d28c66..8478429801d 100644 --- a/relay-event-schema/src/protocol/contexts/mod.rs +++ b/relay-event-schema/src/protocol/contexts/mod.rs @@ -274,7 +274,7 @@ impl FromValue for Contexts { for (key, value) in items.iter_mut() { if let Annotated(Some(Value::Object(items)), _) = value { // Set the `"type"` if it's empty and overwrite it if it's an empty object or array. - if value_is_empty(items.get("type")) { + if !is_valid_context_type(items.get("type")) { items.insert( "type".to_owned(), Annotated::new(Value::String(key.to_string())), @@ -287,17 +287,10 @@ impl FromValue for Contexts { } } -/// Returns `true` if `value` is `None`, empty object, or an empty array. -fn value_is_empty(value: Option<&Annotated>) -> bool { - let Some(value) = value.and_then(|v| v.value()) else { - return true; - }; - - match value { - Value::Array(values) => values.is_empty(), - Value::Object(values) => values.is_empty(), - _ => false, - } +/// Returns `true` if `value` is a non-empty string, which is the only valid value +/// for the `"type"` field of a context. +fn is_valid_context_type(value: Option<&Annotated>) -> bool { + matches!(value.and_then(|v| v.value()), Some(Value::String(s)) if !s.is_empty()) } /// A well-known context in the [`Contexts`] interface. @@ -371,14 +364,28 @@ mod tests { } #[test] - fn test_context_empty_type_deserialize() { - let json = r#"{"os":{"name":"Linux","type":{}},"runtime":{"name":"rustc","type":[]}}"#; + fn test_context_invalid_type_deserialize() { + let json = r#"{ + "monitor":{"name":"Foobar","type":17}, + "os":{"name":"Linux","type":{}}, + "profile":{"profile_id":"52df9022835246eeb317dbd739ccd059","type":""}, + "runtime":{"name":"rustc","type":["invalid"]} + }"#; let mut map = Contexts::new(); + map.add(MonitorContext( + [("name".to_owned(), Value::String("Foobar".to_owned()).into())] + .into_iter() + .collect(), + )); map.add(OsContext { name: Annotated::new("Linux".to_owned()), ..Default::default() }); + map.add(ProfileContext { + profile_id: Annotated::new("52df9022835246eeb317dbd739ccd059".parse().unwrap()), + ..Default::default() + }); map.add(RuntimeContext { name: Annotated::new("rustc".to_owned()), ..Default::default()