relay_event_normalization/
remove_other.rs1use relay_event_schema::processor::{ProcessValue, ProcessingResult, ProcessingState, Processor};
2use relay_event_schema::protocol::{Breadcrumb, Event};
3use relay_protocol::{Annotated, ErrorKind, Meta, Object, Value};
4
5fn create_errors(other: &mut Object<Value>) {
7 for value in other.values_mut() {
8 *value = Annotated::from_error(ErrorKind::InvalidAttribute, None);
9 }
10}
11
12pub struct RemoveOtherProcessor;
14
15impl Processor for RemoveOtherProcessor {
16 fn process_other(
17 &mut self,
18 other: &mut Object<Value>,
19 state: &ProcessingState<'_>,
20 ) -> ProcessingResult {
21 if !state.attrs().retain {
24 other.clear();
25 }
26
27 Ok(())
28 }
29
30 fn process_breadcrumb(
31 &mut self,
32 breadcrumb: &mut Breadcrumb,
33 _meta: &mut Meta,
34 state: &ProcessingState<'_>,
35 ) -> ProcessingResult {
36 let mut other = std::mem::take(&mut breadcrumb.other);
38 create_errors(&mut other);
39
40 breadcrumb.process_child_values(self, state)?;
42 breadcrumb.other = other;
43 Ok(())
44 }
45
46 fn process_event(
47 &mut self,
48 event: &mut Event,
49 _meta: &mut Meta,
50 state: &ProcessingState<'_>,
51 ) -> ProcessingResult {
52 let mut other = std::mem::take(&mut event.other);
54
55 other.remove("metadata");
57 other.remove("hashes");
58
59 other.remove("applecrashreport");
61 other.remove("device");
62 other.remove("repos");
63 other.remove("query");
64
65 create_errors(&mut other);
67
68 event.process_child_values(self, state)?;
70
71 event.other = other;
72 Ok(())
73 }
74}
75
76#[cfg(test)]
77mod tests {
78 use relay_event_schema::processor::process_value;
79 use relay_event_schema::protocol::{Context, Contexts, DebugImage, OsContext, User, Values};
80 use relay_protocol::{Empty, FromValue, get_value};
81 use similar_asserts::assert_eq;
82
83 use super::*;
84
85 #[test]
86 fn test_remove_legacy_attributes() {
87 let mut event = Annotated::new(Event {
88 other: {
89 let mut other = Object::new();
90 other.insert("applecrashreport".to_owned(), Value::U64(42).into());
91 other.insert("device".to_owned(), Value::U64(42).into());
92 other.insert("repos".to_owned(), Value::U64(42).into());
93 other.insert("query".to_owned(), Value::U64(42).into());
94 other
95 },
96 ..Default::default()
97 });
98
99 process_value(
100 &mut event,
101 &mut RemoveOtherProcessor,
102 ProcessingState::root(),
103 )
104 .unwrap();
105
106 assert!(event.value().unwrap().other.is_empty());
107 }
108
109 #[test]
110 fn test_remove_unknown_attributes() {
111 let mut event = Annotated::new(Event {
112 other: {
113 let mut other = Object::new();
114 other.insert("foo".to_owned(), Value::U64(42).into());
115 other.insert("bar".to_owned(), Value::U64(42).into());
116 other
117 },
118 ..Default::default()
119 });
120
121 process_value(
122 &mut event,
123 &mut RemoveOtherProcessor,
124 ProcessingState::root(),
125 )
126 .unwrap();
127
128 let other = &event.value().unwrap().other;
129 assert_eq!(
130 *other.get("foo").unwrap(),
131 Annotated::from_error(ErrorKind::InvalidAttribute, None)
132 );
133 assert_eq!(
134 *other.get("bar").unwrap(),
135 Annotated::from_error(ErrorKind::InvalidAttribute, None)
136 );
137 }
138
139 #[test]
140 fn test_remove_nested_other() {
141 let mut event = Annotated::new(Event {
142 user: Annotated::from(User {
143 other: {
144 let mut other = Object::new();
145 other.insert("foo".to_owned(), Value::U64(42).into());
146 other.insert("bar".to_owned(), Value::U64(42).into());
147 other
148 },
149 ..Default::default()
150 }),
151 ..Default::default()
152 });
153
154 process_value(
155 &mut event,
156 &mut RemoveOtherProcessor,
157 ProcessingState::root(),
158 )
159 .unwrap();
160
161 assert!(get_value!(event.user!).other.is_empty());
162 }
163
164 #[test]
165 fn test_remove_enum_fallback_variant() {
166 let mut debug_image = Annotated::new(DebugImage::Other({
167 let mut other = Object::new();
168 other.insert("foo".to_owned(), Value::U64(42).into());
169 other.insert("bar".to_owned(), Value::U64(42).into());
170 other
171 }));
172
173 process_value(
174 &mut debug_image,
175 &mut RemoveOtherProcessor,
176 ProcessingState::root(),
177 )
178 .unwrap();
179
180 assert!(debug_image.is_empty());
181 }
182
183 #[test]
184 fn test_retain_context_other() {
185 let mut os = OsContext::default();
186 os.other
187 .insert("foo".to_owned(), Annotated::from(Value::U64(42)));
188
189 let mut contexts = Contexts::new();
190 contexts.insert("renamed".to_owned(), Context::Os(Box::new(os)));
191
192 let mut event = Annotated::new(Event {
193 contexts: Annotated::new(contexts.clone()),
194 ..Default::default()
195 });
196
197 process_value(
198 &mut event,
199 &mut RemoveOtherProcessor,
200 ProcessingState::root(),
201 )
202 .unwrap();
203
204 assert_eq!(get_value!(event.contexts!).0, contexts.0);
205 }
206
207 #[test]
208 fn test_breadcrumb_errors() {
209 let mut event = Annotated::new(Event {
210 breadcrumbs: Annotated::new(Values::new(vec![Annotated::new(Breadcrumb {
211 other: {
212 let mut other = Object::new();
213 other.insert("foo".to_owned(), Value::U64(42).into());
214 other.insert("bar".to_owned(), Value::U64(42).into());
215 other
216 },
217 ..Breadcrumb::default()
218 })])),
219 ..Default::default()
220 });
221
222 process_value(
223 &mut event,
224 &mut RemoveOtherProcessor,
225 ProcessingState::root(),
226 )
227 .unwrap();
228
229 let other = &event
230 .value()
231 .unwrap()
232 .breadcrumbs
233 .value()
234 .unwrap()
235 .values
236 .value()
237 .unwrap()[0]
238 .value()
239 .unwrap()
240 .other;
241
242 assert_eq!(
243 *other.get("foo").unwrap(),
244 Annotated::from_error(ErrorKind::InvalidAttribute, None)
245 );
246 assert_eq!(
247 *other.get("bar").unwrap(),
248 Annotated::from_error(ErrorKind::InvalidAttribute, None)
249 );
250 }
251
252 #[test]
253 fn test_scrape_attempts() {
254 let json = serde_json::json!({
255 "scraping_attempts": [
256 {"status": "not_attempted", "url": "http://example.com/embedded.js"},
257 {"status": "not_attempted", "url": "http://example.com/embedded.js.map"},
258 ]
259 });
260
261 let mut event = Event::from_value(json.into());
262 process_value(
263 &mut event,
264 &mut RemoveOtherProcessor,
265 ProcessingState::root(),
266 )
267 .unwrap();
268 assert!(event.value().unwrap().other.is_empty());
269 }
270}