Skip to main content

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        && config.releases.is_match(release)
16    {
17        return Err(FilterStatKey::ReleaseVersion);
18    }
19
20    Ok(())
21}
22
23#[cfg(test)]
24mod tests {
25    use relay_conventions::attributes::SENTRY__RELEASE;
26    use relay_event_schema::protocol::{Event, LenientString, Span, SpanData};
27    use relay_protocol::{Annotated, Value};
28
29    use super::*;
30
31    fn get_event_for_release(release: &str) -> Event {
32        Event {
33            release: Annotated::from(LenientString::from(release.to_owned())),
34            ..Event::default()
35        }
36    }
37
38    fn get_span_for_release(release: &str) -> Span {
39        Span {
40            data: Annotated::new(SpanData::from([(
41                SENTRY__RELEASE.to_owned(),
42                Annotated::new(Value::String(release.to_owned())),
43            )])),
44            ..Default::default()
45        }
46    }
47
48    #[test]
49    fn test_release_filtering() {
50        let examples = &[
51            //simple matches
52            ("1.2.3", &["1.3.0", "1.2.3", "1.3.1"][..], true),
53            ("1.2.3", &["1.3.0", "1.3.1", "1.2.3"], true),
54            ("1.2.3", &["1.2.3", "1.3.0", "1.3.1"], true),
55            //pattern matches
56            ("1.2.3", &["1.3.0", "1.2.*", "1.3.1"], true),
57            ("1.2.3", &["1.3.0", "1.3.*", "1.*"], true),
58            ("1.2.3", &["*", "1.3.0", "1.3.*"], true),
59            //simple non match
60            ("1.2.3", &["1.3.0", "1.2.4", "1.3.1"], false),
61            //pattern non match
62            ("1.2.3", &["1.4.0", "1.3.*", "3.*"], false),
63            //sentry compatibility tests
64            ("1.2.3", &[], false),
65            ("1.2.3", &["1.1.1", "1.1.2", "1.3.1"], false),
66            ("1.2.3", &["1.2.3"], true),
67            ("1.2.3", &["1.2.*", "1.3.0", "1.3.1"], true),
68            ("1.2.3", &["1.3.0", "1.*", "1.3.1"], true),
69        ];
70
71        for &(release, blocked_releases, expected) in examples {
72            let event = get_event_for_release(release);
73            let span = get_span_for_release(release);
74
75            let config = ReleasesFilterConfig {
76                releases: blocked_releases.iter().map(|&r| r.to_owned()).collect(),
77            };
78
79            let actual = should_filter(&event, &config) != Ok(());
80            assert_eq!(
81                actual,
82                expected,
83                "Release {release} should have {} been filtered by {blocked_releases:?}",
84                if expected { "" } else { "not" },
85            );
86
87            let actual = should_filter(&span, &config) != Ok(());
88            assert_eq!(
89                actual,
90                expected,
91                "Release {release} should have {} been filtered by {blocked_releases:?}",
92                if expected { "" } else { "not" },
93            );
94        }
95    }
96}