From 4a5317fd4aa9d321a5899996b3bcaaa7f500a743 Mon Sep 17 00:00:00 2001 From: Nathan Barrett Date: Wed, 2 Sep 2026 12:51:34 -0500 Subject: [PATCH 1/2] Bug 2068685 - Support env.distribution in filter expressions --- components/remote_settings/src/client.rs | 68 +++++++++++++++++++++++ components/remote_settings/src/context.rs | 7 +++ 2 files changed, 75 insertions(+) diff --git a/components/remote_settings/src/client.rs b/components/remote_settings/src/client.rs index 84398b22ed9..79bce94efd1 100644 --- a/components/remote_settings/src/client.rs +++ b/components/remote_settings/src/client.rs @@ -1187,6 +1187,74 @@ mod jexl_tests { ); } + #[test] + fn test_jexl_filter_by_distribution() { + let mut api_client = MockApiClient::new(); + let records = vec![RemoteSettingsRecord { + id: "record-0001".into(), + last_modified: 100, + deleted: false, + attachment: None, + fields: serde_json::json!({ + "filter_expression": "env.distribution == \"firefox-001\"" + }) + .as_object() + .unwrap() + .clone(), + }]; + let changeset = ChangesetResponse { + changes: records.clone(), + timestamp: 42, + metadata: CollectionMetadata::default(), + }; + api_client.expect_collection_url().returning(|| { + "http://rs.example.com/v2/buckets/main/collections/test-collection".into() + }); + api_client.expect_fetch_changeset().returning({ + let changeset = changeset.clone(); + move |timestamp| { + assert_eq!(timestamp, None); + Ok(changeset.clone()) + } + }); + api_client.expect_is_prod_server().returning(|| Ok(false)); + + let context = RemoteSettingsContext { + distribution: Some("firefox-001".to_string()), + ..Default::default() + }; + + let mut storage = Storage::new(":memory:".into()); + let _ = storage.insert_collection_content( + "http://rs.example.com/v2/buckets/main/collections/test-collection", + &records, + 42, + CollectionMetadata::default(), + ); + + let rs_client = RemoteSettingsClient::new_from_parts( + "test-collection".into(), + storage, + JexlFilter::new(Some(context)), + api_client, + ); + + assert_eq!( + rs_client.get_records(false).expect("Error getting records"), + Some(records) + ); + + rs_client.inner.lock().jexl_filter = JexlFilter::new(Some(RemoteSettingsContext { + distribution: Some("default".to_string()), + ..Default::default() + })); + + assert_eq!( + rs_client.get_records(false).expect("Error getting records"), + Some(vec![]) + ); + } + // Test that we can't hit the deadlock described in // https://bugzilla.mozilla.org/show_bug.cgi?id=2012955 #[test] diff --git a/components/remote_settings/src/context.rs b/components/remote_settings/src/context.rs index 6caee4c2a20..6f54b5d808e 100644 --- a/components/remote_settings/src/context.rs +++ b/components/remote_settings/src/context.rs @@ -45,6 +45,8 @@ pub struct RemoteSettingsContext { /// for example `Region` on Desktop and `RegionMiddleware` on Android. #[uniffi(default = None)] pub country: Option, + #[uniffi(default = None)] + pub distribution: Option, /// Extra attributes to add to the env for JEXL filtering. /// /// Use this for prototyping / testing new features. In the long-term, new fields should be @@ -94,6 +96,9 @@ impl RemoteSettingsContext { if let Some(country) = self.country { v.insert("country".to_string(), country.into()); } + if let Some(distribution) = self.distribution { + v.insert("distribution".to_string(), distribution.into()); + } if let Some(custom) = self.custom_targetting_attributes { v.extend(custom.into_iter().map(|(k, v)| (k, v.into()))); } @@ -120,6 +125,7 @@ mod test { locale: Some("en-US".into()), form_factor: Some("tablet".into()), country: Some("US".into()), + distribution: Some("firefox-001".into()), custom_targetting_attributes: Some(HashMap::from([("extra".into(), "test".into())])), }; assert_eq!( @@ -141,6 +147,7 @@ mod test { // into official fields that both the Gecko and Rust client support. "formFactor": "tablet", "country": "US", + "distribution": "firefox-001", "extra": "test", }) ); From db7ef1f3b9d72a5f8ca89b314db020979c4d56ca Mon Sep 17 00:00:00 2001 From: Nathan Barrett Date: Wed, 2 Sep 2026 13:02:42 -0500 Subject: [PATCH 2/2] update change log --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ffce80ff4d3..678069069ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,10 @@ - Added `blocks: Vec` to `ffi::MozAdsRequestOptions`, `AdsClient::request*_ads`, `MARSClient::fetch_ads`, `mars::AdRequest`, and `mars::AdRequest::try_new`. This is serialized and passed to MARS so that it can remove blocks server-side. +### Remote Settings + +- Added an optional `distribution` field to `RemoteSettingsContext`, exposed as `env.distribution` in JEXL `filter_expression`s so records can be targeted at specific distributions (e.g. partner repacks). ([Bug 2068685](https://bugzilla.mozilla.org/show_bug.cgi?id=2068685)) + # v156.0 (_2026-08-27_) ## ✨ What's Changed ✨