relay_filter/
releases.rs

1//! Implements event filtering based on application release version.
2//!
3//! A user may configure the server to ignore certain application releases
4//! (known old bad releases) and Sentry will ignore events originating from
5//! clients with the specified release.
6
7use crate::{FilterStatKey, Filterable, ReleasesFilterConfig};
8
9/// Filters events generated by known problematic SDK clients.
10pub fn should_filter<F>(item: &F, config: &ReleasesFilterConfig) -> Result<(), FilterStatKey>
11where
12    F: Filterable,
13{
14    if let Some(release) = item.release() {
15        if config.releases.is_match(release) {
16            return Err(FilterStatKey::ReleaseVersion);
17        }
18    }
19
20    Ok(())
21}
22
23#[cfg(test)]
24mod tests {
25    use relay_event_schema::protocol::{Event, LenientString, Span, SpanData};
26    use relay_protocol::Annotated;
27
28    use super::*;
29
30    fn get_event_for_release(release: &str) -> Event {
31        Event {
32            release: Annotated::from(LenientString::from(release.to_owned())),
33            ..Event::default()
34        }
35    }
36
37    fn get_span_for_release(release: &str) -> Span {
38        Span {
39            data: Annotated::new(SpanData {
40                release: Annotated::from(LenientString::from(release.to_owned())),
41                ..Default::default()
42            }),
43            ..Default::default()
44        }
45    }
46
47    #[test]
48    fn test_release_filtering() {
49        let examples = &[
50            //simple matches
51            ("1.2.3", &["1.3.0", "1.2.3", "1.3.1"][..], true),
52            ("1.2.3", &["1.3.0", "1.3.1", "1.2.3"], true),
53            ("1.2.3", &["1.2.3", "1.3.0", "1.3.1"], true),
54            //pattern matches
55            ("1.2.3", &["1.3.0", "1.2.*", "1.3.1"], true),
56            ("1.2.3", &["1.3.0", "1.3.*", "1.*"], true),
57            ("1.2.3", &["*", "1.3.0", "1.3.*"], true),
58            //simple non match
59            ("1.2.3", &["1.3.0", "1.2.4", "1.3.1"], false),
60            //pattern non match
61            ("1.2.3", &["1.4.0", "1.3.*", "3.*"], false),
62            //sentry compatibility tests
63            ("1.2.3", &[], false),
64            ("1.2.3", &["1.1.1", "1.1.2", "1.3.1"], false),
65            ("1.2.3", &["1.2.3"], true),
66            ("1.2.3", &["1.2.*", "1.3.0", "1.3.1"], true),
67            ("1.2.3", &["1.3.0", "1.*", "1.3.1"], true),
68        ];
69
70        for &(release, blocked_releases, expected) in examples {
71            let event = get_event_for_release(release);
72            let span = get_span_for_release(release);
73
74            let config = ReleasesFilterConfig {
75                releases: blocked_releases.iter().map(|&r| r.to_owned()).collect(),
76            };
77
78            let actual = should_filter(&event, &config) != Ok(());
79            assert_eq!(
80                actual,
81                expected,
82                "Release {release} should have {} been filtered by {blocked_releases:?}",
83                if expected { "" } else { "not" },
84            );
85
86            let actual = should_filter(&span, &config) != Ok(());
87            assert_eq!(
88                actual,
89                expected,
90                "Release {release} should have {} been filtered by {blocked_releases:?}",
91                if expected { "" } else { "not" },
92            );
93        }
94    }
95}